【问题标题】:How to define recursive rule for pegJS如何为 pegJS 定义递归规则
【发布时间】:2017-02-11 01:48:16
【问题描述】:

所以,我正在尝试使用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.

我知道左右递归的想法,但我不知道如何让它无限地递归调用规则。

【问题讨论】:

    标签: javascript parsing recursion pegjs


    【解决方案1】:

    我认为问题在于您的语法歧义。向 GNF(领先终端)扩展一点,我们得到两个用于字母符号的规则链:

    arg = [0-9a-z,A-Z]+ arg = call # 展开调用 = func"("arg")" # 展开函数 = [a-zA-Z]+"("arg")"

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

    我不熟悉 PegJS,所以我无法建议如何强制您的解析器提交。你确实需要一个 1-token 的前瞻来解决这个问题。

    不过,我确实了解解析器。许多正则表达式引擎是“贪婪的”:它们会抓取最长的匹配字符串。如果您有其中之一,那么关键问题是

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

    将在返回任何其他处理之前消耗跨度“4,g”,从而消除找到“g()”作为第二个参数的可能性。在这种情况下,您需要的是一种能够找到单个参数并且对每个都贪婪的语法。使用逗号作为分隔符,并将它们组合成一个 arg_list(一个新的非令牌):

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

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

    【讨论】:

    • 谢谢!我实际上是通过让它在普通参数之前先检查函数调用来解决这个问题的,
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多