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

Parsing 在if命令中抑制执行的PEG语法,parsing,grammar,peg,Parsing,Grammar,Peg,我想创建一个语法分析一些命令。大多数都工作正常,但是“if(条件、然后值、否则值)”没有与“out”命令一起工作以显示某些值。 如果输出命令在if命令之外,则其工作正常: out(if(1,42,43)) → 输出并按预期返回42正常 但此时输出命令在内部,否则部分(要求更直观)失败: if(1,out(42),out(43)) → 仍然像预期的那样只返回42 OK,但是输出函数被42和43调用了两次 我在C语言下使用peg/leg解析器生成器 当使用以下非常简化的语法时,PEG.js on

我想创建一个语法分析一些命令。大多数都工作正常,但是“if(条件、然后值、否则值)”没有与“out”命令一起工作以显示某些值。 如果输出命令在if命令之外,则其工作正常:

out(if(1,42,43))
→ 输出并按预期返回42正常

但此时输出命令在内部,否则部分(要求更直观)失败:

if(1,out(42),out(43))
→ 仍然像预期的那样只返回42 OK,但是输出函数被42和43调用了两次

我在C语言下使用peg/leg解析器生成器 当使用以下非常简化的语法时,PEG.js online parser generator也会重现此问题:

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()”只是所需输出函数的占位符,但对于这个问题,它的作用是相同的。 看起来扫描仪必须将full if命令与then匹配- 否则,在结束括号内输入“)”。所以它匹配了两个out命令,它们都执行定义的函数——这不是我所期望的

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

(我已经尝试了“&”谓词元素,但没有成功)

(可能左递归和右递归在这里会有所帮助,但使用的peg/leg生成器似乎只支持右递归)

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

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

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

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

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

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

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

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

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


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

解决方案可以是使用谓词表达式“&{expression}”(不要被谓词元素“&element”混淆)

其思想是定义out()两次,一次是真正做某事,另一次是在没有输出的情况下禁用。 if命令的条件是使用{}内的代码计算的,因此如果条件为false,则整个表达式匹配失败


明显的缺点是then和else的if命令的冗余定义和递归禁用

解决方案可以使用谓词表达式“&{expression}”(不要被谓词元素“&”混淆)

其思想是定义out()两次,一次是真正做某事,另一次是在没有输出的情况下禁用。 if命令的条件是使用{}内的代码计算的,因此如果条件为false,则整个表达式匹配失败


明显的缺点是对then和else的if命令进行了冗余定义,并禁用了递归

Wow,这将导致我的语法完全重新设计。目前,我在模式后面的语法中实现了20多个函数,如{}。大多数都很简单。创建字节码树并执行它们确实是一个有效的解决方案——目前我没有其他选择。谢谢阿奇姆沃,这将导致我的语法完全重新设计。目前,我在模式后面的语法中实现了20多个函数,如{}。大多数都很简单。创建字节码树并执行它们确实是一个有效的解决方案——目前我没有其他选择。多亏了AchimIn添加了代码复制(随着语法越来越大,这将变得越来越烦人),请注意,这种方法对循环没有帮助。这似乎也与期望的行为不太匹配,因为您的if条件现在不再执行其副作用(我认为您这样做是为了防止它们被执行两次)。除了代码重复(随着语法变得更大,这将变得越来越烦人)之外,请注意,这种方法对循环没有帮助。这似乎也不太符合期望的行为,因为您的if条件现在不再执行其副作用(我认为您这样做是为了防止它们被执行两次)。
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); }