使用YECC解析基于缩进的语法(如Python)

时间:2014-12-04 02:59:13

标签: parsing erlang grammar lalr yecc

我有以下代码:

case 1
of 2
    3
of 3
    4
5

我的自定义标记生成器转换为:

Tokens: [{'case',1},
         {integer,1,1},
         {eol,1},
         {'of',1},
         {integer,1,2},
         {block,[{integer,1,3}]},
         {eol,1},
         {'of',1},
         {integer,1,3},
         {block,[{integer,1,4}]},
         {eol,1},
         {integer,1,5}]

但是后来我无法使用以下Yecc解析它:

Nonterminals
    grammar
    statements statement
    case_def case_conditions condition.


Terminals
    eol block
    integer
    case of.


Rootsymbol grammar.


grammar -> statements : '$1'.


statements -> statement eol statements : ['$1'|'$3'].
statements -> statement : ['$1'].

statement -> case_def : '$1'.
statement -> integer : '$1'.


case_def -> 'case' integer case_conditions : ''.

case_conditions -> case_condition case_conditions : ['$1'|'$2'].
case_conditions -> case_condition : ['$1'].

case_condition -> eol 'of' integer block : ''.

它给了我以下输出:

["syntax error before: ","5"]

非常欢迎任何帮助,谢谢。

1 个答案:

答案 0 :(得分:1)

我认为在非终结列表中,您应该case_condition而不是condition

您的自定义扫描程序会忽略缩进。它必须为INDENTDEDENT发出令牌。我找到了example in yacc。然后你可以改变你的语法来使用那些令牌。

您的示例会生成转移/减少冲突。文档说:

  

转移/减少冲突得到解决,有利于转移,如果有的话   没有运算符优先级声明。

这意味着,当您的解析器位于|

表示的位置时
of 3
    4|
5

并看到新行,可能有两个选项:

  • 这可能是下一个case_condition所以解析器需要继续“转移”以阅读更多内容
  • 这可能是语句的结束,因此解析器需要在语句之前处理所有内容并将其置于堆栈或简称“reduce”

因为这些冲突总是被解决才能转移,所以在你开始案例之后你不能放下一个声明!你需要改变你的语法。使用它直到yecc:file/1没有产生任何警告。

提示:在这种情况下缩进所有内容:

case 1
    of 2
        3
    of 3
        4
5

这样,你清楚地说,case是一个陈述而5是另一个陈述。我对解析器的了解有点生疏,但我相信,如果你不这样做,你就无法编写能够用左到右解析器区分case_conditionstatement的语法。添加缩进或某种终结符。