Search code examples
javascriptpegjs

Grammar is matching function rule more than required number of times


Here is a grammar that I used. The action after matching the rule 'Func' is called 12 times for the input string if(diff("col")) instead of 2 times.

Debugging I realised the varible peg$currPos is being set back when parsing the Eq rule. I am not able to understand the exact behaviour

 Main = Eq
 Eq = (Ar (('equal'i/'>='/'<='/'<>'/'!='/'<'/'>'/'=') Ar))
      /Ar ('equal'i/'>='/'<='/'<>'/'!='/'<'/'>'/'=')
      /Ar 

 Ar = (Mul (('+'/'-') Mul )*) ('+'/'-')?

 Mul = (Ex (('*'/'/'/'%'/'^') Ex )*) ('*'/'/'/'%'/'^')?

 Ex = __ ('-'__ Main/'(' __ Main __ ')'/Func/Lit) __ /'-'

 Func = __ id (('('__ Main __')')/'('__')') __ {
      console.log(text());
 }

 Lit = (col/charLit/numLit)
       / id:id

 charLit "character" = string:$("'"[^']*"'")

 numLit "number" = $([0-9.]+)

 col "column" = col:$('"'[^"]*'"') 

 id "identifier" = $([a-zA-Z][a-zA-Z0-9_]*)

 __ "space" = [ \t\n]*              

Solution

  • The reason you are encountering this is because the Func rule is matched that many times. Unfortunately, some of those matches are part of larger expressions (in the Eq rule) that fail. That's why you see peg$currPos being set back.

    Maybe try:

    Eq = Ar (('equal'i/'>='/'<='/'<>'/'!='/'<'/'>'/'=') Ar?)?