我打算使用野牛解析一些脚本语言,用这种语言,我可以写下代码:
a = input()
b = a + 1
function myfunc
a = input()
b = a + 1
end function
我发现块
a = input()
b = a + 1
可以通过相同的规则stmts
降低功能定义的出现和外出,因此我像以下代码一样编写代码
%{
#include <stdio.h>
#include <string>
#include <sstream>
#include <iostream>
#include <stdarg.h>
#include <tuple>
using namespace std;
%}
%debug
%token CRLF EXP FUNCTIONBEGIN FUNCTIONEND
%start program
%%
stmt : EXP
|
stmts : stmt CRLF stmts
| stmt
function : FUNCTIONBEGIN CRLF stmts CRLF FUNCTIONEND
unit : function
| stmts
program : unit
| unit CRLF program
%%
当然,由于一次轮班/减少冲突
,此代码无法工作State 3
3 stmts: stmt . CRLF stmts
4 | stmt .
CRLF shift, and go to state 9
CRLF [reduce using rule 4 (stmts)]
$default reduce using rule 4 (stmts)
我认为这种冲突既是我的program
规则和stmts
规则都使用相同的终端CRLF
作为"二进制运算符",因此我无法通过将优先级设置为操作员来解决这一冲突。
也许我可以通过以某种方式将另外两个规则添加到STMT
来合并program
规则和stmts
规则 stmts : function CRLF stmts
| function
但是,我认为这种方法(是否可以实际工作)不是很漂亮,所以我问是否还有其他解决方案
问题与CRLF令牌无关。相反,这是您对program
的定义。program
是一系列unit
s,每个单元是function
或stmts
。但是stmts
不是一个"单位",这是由于其名称是复数的事实所暗示的。stmts
是一系列stmt
s。
因此,假设我们有一个由三个语句组成的程序。那是多少 unit
s?它是由所有三个语句组成的stmts
吗?还是其中两个,一个带有两个陈述,另一个只有一个?还是另一方面?甚至三个unit
s,每个s由包含单个语句的stmts
组成?
解析器无法说出这些选择中的哪个是因为语法模棱两可。这就是造成冲突的原因。
最简单的解决方案是将生产unit: stmts
更改为单数:unit: stmt
。然后就没有歧义。三键program
完全具有三个unit
s,每个stmt
。
顺便说一句,在编写LR语法时,您应该始终更喜欢左递归。正确的递归通常不会造成冲突,它与您当前的问题无关,但是它确实导致了不必要的IARGE解析堆栈,并且降低诸如units
和stmts
之类的列表将从右至左执行的组件执行从堆栈中弹出,通常不是意图的。