work around operator left recursion

main
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); module.add_cell(cell);
Ok(output_gen_wire) Ok(output_gen_wire)
} }
// operations should really just desugar to callables
parser::Expression::Operation(_op) => todo!("operators not yet implemented"), parser::Expression::Operation(_op) => todo!("operators not yet implemented"),
parser::Expression::Literal(lit) => { parser::Expression::Literal(lit) => {
Ok(rtlil::SigSpec::Const(*lit as i64, TODO_WIDTH)) Ok(rtlil::SigSpec::Const(*lit as i64, TODO_WIDTH))

View File

@ -61,8 +61,8 @@ pub struct Assign<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum Operation<'a> { pub enum Operation<'a> {
And { a: String, b: Expression<'a> }, And { a: Expression<'a>, b: Expression<'a> },
Or { a: String, b: Expression<'a> }, Or { a: Expression<'a>, b: Expression<'a> },
Not(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 // temporarily given up on before I learn the shunting yard algorithm
alt(( alt((
map( map(
separated_pair(ws0(identifier), char('&'), ws0(expression)), separated_pair(ws0(expression_nonrecurse), char('&'), ws0(expression)),
|(a, b)| Operation::And { |(a, b)| Operation::And {
a: (*a.fragment()).into(), a,
b, b,
}, },
), ),
map( map(
separated_pair(ws0(identifier), char('|'), ws0(expression)), separated_pair(ws0(expression_nonrecurse), char('|'), ws0(expression)),
|(a, b)| Operation::Or { |(a, b)| Operation::Or {
a: (*a.fragment()).into(), a,
b, b,
}, },
), ),
@ -134,14 +134,25 @@ fn call_item(input: Span) -> IResult<Span, Call> {
)(input) )(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> { fn expression(input: Span) -> IResult<Span, Expression> {
alt(( alt((
map(ws0(decimal), |lit| Expression::Literal(lit)),
map(ws0(operation), |op| Expression::Operation(Box::new(op))), 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(call_item), |call| Expression::Call(Box::new(call))),
map(ws0(identifier), |ident| { map(ws0(identifier), |ident| {
Expression::Ident(*ident.fragment()) Expression::Ident(*ident.fragment())
}), }),
delimited(char('('), expression, char(')')),
))(input) ))(input)
} }