PEG语法抑制if命令中的执行

时间:2017-11-13 12:17:37

标签: parsing grammar peg

我想创建一个解析一些命令的语法。大多数工作完美无缺,但是" if(条件,然后价值,其他价值)"并没有与" out"命令显示一些值。 如果output-command在if-command之外,它可以正常工作:

out(if(1,42,43))

→按预期输出并返回42确定

但是目前输出命令位于then-和else-part(需要更直观)内,它失败了:

if(1,out(42),out(43))

→仍然只返回42预期OK,但输出函数被调用两次42和43

我在C下使用peg / leg解析器生成器here工作 使用以下非常简化的语法时,PEG.js在线解析器生成器here也可以重现该问题:

Expression
  = Int
  / "if(" cond:Expression "," ok:Expression "," nok:Expression ")" { return cond?ok:nok; }
  / "out(" num:Expression ")" { window.alert(num); return num;}

Int = [0-9]+ { return parseInt(text(), 10); }

" window.alert()"只是所需输出函数的占位符,但对于这个问题,它的作用是相同的。 看起来扫描仪必须匹配完整的if命令,然后 -  和 - 值直到结束括号")"。所以它匹配两个out-commands并且它们都执行定义的函数 - 这不是我期望的。

peg / leg中是否有一种方法可以匹配某些字符,但在某些情况下会抑制相应函数的执行?

(我已经尝试过"&"谓词元素没有成功)

(也许左递归与右递归在这里有所帮助,但是使用peg / leg-generator似乎只支持右递归)

2 个答案:

答案 0 :(得分:2)

  

peg / leg中是否有一种方法可以匹配某些字符,但在某些情况下会抑制相应函数的执行?

我对这些工具并不熟悉,但如果可行,我会感到惊讶。即使是这样,在实现循环时也会遇到类似的问题:现在您需要多次执行该操作。

您需要的是不要直接执行代码,而是返回可用于执行代码的操作。

解释器工作的常用方法是解析器生成某种源代码表示(例如字节码或AST),然后将其作为单独的步骤执行。

使您的解析器工作而不会改变太多的最简单(但也许不是最干净的)方法是将所有操作包装在0参数函数中。然后,当且仅当您希望它们被执行时,您才可以调用子表达式返回的函数。然后,为了实现循环,您可以简单地多次调用函数。

答案 1 :(得分:0)

解决方案可能是使用谓词表达式"& {表达}" (不要混淆谓词元素"& element")

Expression
  = Function
  
Function
  = Int
  / "if(" IfCond "," ok:Function "," nok:FunctionDisabled ")" { return ok; }
  / "if(" FunctionDisabled "," ok:FunctionDisabled "," nok:Function ")" { return nok; }
  / "out(" num:Function ")" { window.alert("Out:"+num); return num;}
 
FunctionDisabled
  = Int
  / "if(" IfCond "," ok:FunctionDisabled "," nok:FunctionDisabled ")" { return ok; }
  / "if(" FunctionDisabled "," ok:FunctionDisabled "," nok:FunctionDisabled ")" { return nok; }

  / "out(" num:FunctionDisabled ")" { return num;}

IfCond
  = cond:FunctionDisabled   &{ return cond; }
                   
Int = [0-9]+ { return parseInt(text(), 10); }

这个想法是定义out()两次,一次真正做某事,第二次禁用没有输出。 使用{}内的代码评估if-command的条件,因此如果条件为false,则整个表达式匹配failes。

可见的缺点是if-command的冗余定义为then和else以及递归禁用