我想创建一个解析一些命令的语法。大多数工作完美无缺,但是" 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似乎只支持右递归)
答案 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以及递归禁用