How do I write this `expression` PEG grammar so that it is not recursive, or so that I can use the prec climber?

221 Views Asked by At

I am creating a parser for solidity and I am using the PEST parser for rust. I am trying to write the grammar for expression, but there are many cases of left recursion. I have looked online and know that you can use the prec climber but I am not quite sure as to how to implement this. Would it be better to remove left recursion by writing the rules by precedence or use the prec climber?

Can someone help me figure how to implement this grammar so that it works with the PEST parser? Please let me know if there is anything that might be helpful to add to the post for context.

Here is the expression grammar

expression = {
    (expression ~ LBrack ~ expression? ~ RBrack)
    | (expression ~ LBrack ~ expression? ~ Colon ~ expression? ~ RBrack)
    | (expression ~ Period ~ (identifier | Address))
    | (expression ~ LBrack ~ (namedArgument ~ (Comma ~ namedArgument)*)? ~ RBrack)
    | (expression ~ callArgumentList)
    | (Payable ~ callArgumentList)
    | (Type ~ LParen ~ typeName ~ RParen)
    | ((Inc | Dec | Not | BitNot | Delete | Sub) ~ expression)
    | (expression ~ (Inc | Dec))
    | (expression ~ Exp ~ expression)
    | (expression ~ (Mul | Div | Mod) ~ expression)
    | (expression ~ (Add | Sub) ~ expression)
    | (expression ~ (Shl | Sar | Shr) ~ expression)
    | (expression ~ BitAnd ~ expression)
    | (expression ~ BitXor ~ expression)
    | (expression ~ BitOr ~ expression)
    | (expression ~ (LessThan | GreaterThan | LessThanOrEqual | GreaterThanOrEqual) ~ expression)
    | (expression ~ (Equal | NotEqual) ~ expression)
    | (expression ~ And ~ expression)
    | (expression ~ Or ~ expression)
    | (expression ~ Conditional ~ expression ~ Colon ~ expression)
    | (expression ~ assignOp ~ expression)
    | (New ~ typeName)
    | (tupleExpression)
    | (inlineArrayExpression)
}
1

There are 1 best solutions below

0
Bart Kiers On

You could try something like this:

expr = { assign }

assign = { conditional ~ ("=" ~ conditional)? }
conditional = { orExpr ~ ("?" ~ orExpr ~ ":" ~ orExpr)? }
orExpr = { andExpr ~ ("||" ~ andExpr)* }
andExpr = { eqExpr ~ ("&&" ~ eqExpr)* }
eqExpr = { relExpr ~ (("==" | "!=") ~ relExpr)? }
relExpr = { bitOrExpr ~ (("<" | "<=" | ">" | ">=") ~ bitOrExpr)? }
bitOrExpr = { bitXorExpr ~ ("|" ~ bitXorExpr)* }
bitXorExpr = { bitAndExpr ~ ("^" ~ bitAndExpr)* }
bitAndExpr = { shiftExpr ~ ("&" ~ shiftExpr)* }
shiftExpr = { addExpr ~ (("<<" | ">>" | ">>>") ~ addExpr)* }
addExpr = { multExpr ~ (("+" | "-") ~ multExpr)* }
multExpr = { expExpr ~ (("*" | "/" | "%") ~ expExpr)* }
expExpr = { incrOrDecr ~ ("^" ~ incrOrDecr)* }
incrOrDecr = { prefix ~ ("++" | "--")? }
prefix = { ("++" | "--" | "!" | "~" | "delete" | "-")? ~ atom }

atom = { 
   Number 
 | Id ~ ("." ~ Id)* ~ callArgumentList?
 | "(" ~ expr ~ ")" 
}

callArgumentList = { "(" ~ (callArgument ~ ("," ~ callArgument)*)? ~ ")" }
callArgument = { expr ~ ((":" | "=") ~ expr)? }

Id = { 'a'..'z'+ }
Number = { '0'..'9'+ }