如何为pegJS

时间:2017-02-09 23:10:58

标签: javascript parsing recursion pegjs

因此,我尝试使用PegJS为简单语言定义解析器。

该语言完全由无限深度的函数调用组成,这些函数调用由逗号分隔,例如:

f(4, g()) => [f, [4, g, []]]

g()
f(5) => [g, [], f, [5]]

这是我的语法:

call = 
  func"("arg")"

func =
  [a-zA-Z]+

arg =
  [0-9a-z,A-Z]+ / call


_ "whitespace"
  = [ \t\n\r]*

然而它并没有复发:

输入:b(r(6))

错误:Line 1, column 4: Expected ")" or [0-9a-z,A-Z] but "(" found.

我理解左对右递归但我没有得到如何让它无限地递归调用规则。

1 个答案:

答案 0 :(得分:1)

我认为问题出在你的语法模糊性上。向GNF(领先终端)扩展一点,我们得到两个字母符号的规则链:

arg = [0-9a-z,A-Z] +    arg = call#展开呼叫        = func"(" arg")" #Expout func        = [a-zA-Z] +"(" arg")"

因此,字母标识符可以解析为调用 arg func 。您生成的解析器显然选择将 g 减少为另一个 arg ,而不是 func 的第一部分。

我不熟悉PegJS,因此我无法建议如何强迫您的解析器提交。你需要一个1令牌前瞻来解决这个问题。

但是,我一般都知道解析器。许多正则表达式引擎都是"贪心":他们会抓住最长的匹配字符串。如果您有其中一个,那么关键问题是

arg = [0-9a-z,A-Z]+

将消耗跨度" 4,g"在它返回任何其他处理之前,从而减少了找到" g()"作为第二个论点。在这种情况下,您需要的是一个查找单个参数的语法,并且对每个每个都很贪婪。使用逗号作为分隔符,并将它们放在一起成为arg_list(一个新的非令牌):

arg_list = arg \
           arg "," arg_list

call = func "(" arg_list ")" \
       func "()"

这是解析函数调用的一种规范方法。