work around operator left recursion

This commit is contained in:
NotAFile 2022-01-17 17:29:00 +01:00
parent edab641506
commit b4e31d2bc8
2 changed files with 19 additions and 7 deletions

View File

@ -178,6 +178,7 @@ fn lower_expression(
module.add_cell(cell);
Ok(output_gen_wire)
}
// operations should really just desugar to callables
parser::Expression::Operation(_op) => todo!("operators not yet implemented"),
parser::Expression::Literal(lit) => {
Ok(rtlil::SigSpec::Const(*lit as i64, TODO_WIDTH))

View File

@ -61,8 +61,8 @@ pub struct Assign<'a> {
#[derive(Debug)]
pub enum Operation<'a> {
And { a: String, b: Expression<'a> },
Or { a: String, b: Expression<'a> },
And { a: Expression<'a>, b: Expression<'a> },
Or { a: Expression<'a>, b: Expression<'a> },
Not(Expression<'a>),
}
@ -100,16 +100,16 @@ fn operation(input: Span) -> IResult<Span, Operation> {
// temporarily given up on before I learn the shunting yard algorithm
alt((
map(
separated_pair(ws0(identifier), char('&'), ws0(expression)),
separated_pair(ws0(expression_nonrecurse), char('&'), ws0(expression)),
|(a, b)| Operation::And {
a: (*a.fragment()).into(),
a,
b,
},
),
map(
separated_pair(ws0(identifier), char('|'), ws0(expression)),
separated_pair(ws0(expression_nonrecurse), char('|'), ws0(expression)),
|(a, b)| Operation::Or {
a: (*a.fragment()).into(),
a,
b,
},
),
@ -134,14 +134,25 @@ fn call_item(input: Span) -> IResult<Span, Call> {
)(input)
}
/// parser combinators can not parse left-recursive grammars. To work around this, we split
/// expressions into a recursive and non-recursive portion.
/// Parsers reachable from this point must call expression_nonrecurse instead
fn expression(input: Span) -> IResult<Span, Expression> {
alt((
map(ws0(decimal), |lit| Expression::Literal(lit)),
map(ws0(operation), |op| Expression::Operation(Box::new(op))),
expression_nonrecurse
))(input)
}
/// the portion of the expression grammar that can be parsed without left recursion
fn expression_nonrecurse(input: Span) -> IResult<Span, Expression> {
alt((
map(ws0(decimal), |lit| Expression::Literal(lit)),
map(ws0(call_item), |call| Expression::Call(Box::new(call))),
map(ws0(identifier), |ident| {
Expression::Ident(*ident.fragment())
}),
delimited(char('('), expression, char(')')),
))(input)
}