我无法解决这个问题以及转移减少问题。
添加';'到最后并没有解决问题,因为我无法改变语言,它需要像下面的例子一样去。是否有任何预先操作数?
示例如下:
变量可以声明为:作为指针或int作为整数,因此,这两个都是有效的:
<int> a = 0
int a = 1
代码:
%left '<'
declaration: variable
| declaration variable
variable : type tNAME '=' expr
| type tNAME
type : '<' type '>'
| tINT
expr : tINTEGER
| expr '<' expr
显然在expr之后给出了一个转移/减少问题。因为它可以为“less”运算符的expr移位,或者为另一个变量声明减少。
我希望在变量声明上给出优先权,并尝试创建%nonassoc prec_aux并放在'&lt;'之后输入'&gt;' %prec prec_aux和类型tNAME之后但它没有解决我的问题:S
我该如何解决这个问题?
输出是:
很好的数字hwo可以在回复时发布换行符和代码......所以这里输出结果:
35: shift/reduce conflict (shift 47, reduce 7) on '<'
state 35
variable : type tNAME '=' expr . (7)
expr : expr . '+' expr (26)
expr : expr . '-' expr (27)
expr : expr . '*' expr (28)
expr : expr . '/' expr (29)
expr : expr . '%' expr (30)
expr : expr . '<' expr (31)
expr : expr . '>' expr (32)
'>' shift 46
'<' shift 47
'+' shift 48
'-' shift 49
'*' shift 50
'/' shift 51
'%' shift 52
$end reduce 7
tINT reduce 7
输出和错误似乎是我提到的那个。
有没有人知道一个不同的解决方案,除了在一个不是真正的选项的语言中添加一个新的终端?
我认为解决方法是重写语法,以便以某种方式可以预见并查看它是'&lt;'之后的类型还是expr但我没看到怎么做。
优先权不太可能起作用,因为它是相同的角色。有没有办法为我们定义的类型提供优先权?如声明?
提前致谢
答案 0 :(得分:2)
你的语法在这样的文字中混淆了:
int a = b
<int> c
那'&lt;'在第二行可能是第一个声明中表达式的一部分。它必须进一步向前看才能找到答案。
这就是大多数语言都有语句终止符的原因。这不会产生冲突:
%%
%token tNAME;
%token tINT;
%token tINTEGER;
%token tTERM;
%left '<';
declaration: variable
| declaration variable
variable : type tNAME '=' expr tTERM
| type tNAME tTERM
type : '<' type '>'
| tINT
expr : tINTEGER
| expr '<' expr
在创建解析器时,它有助于了解如何设计语法以消除可能的冲突。为此,您需要了解解析器的工作方式,这超出了本答案的范围:)
答案 1 :(得分:1)
这里的基本问题是你需要比使用yacc / bison获得的1个令牌更多的前瞻。当解析器看到一个<
时,它无法判断它是否完成了preivous声明,并且它看了一个括号类型的开头,或者这是一个小于运算符。你可以在这里做两件基本的事情:
使用解析方法,例如bison的%glr-parser
选项或btyacc,它可以处理非LR(1)语法
使用词法分析器做额外的预测并返回消除歧义的标记
对于后者,你会让词法分析者在'&lt;'之后做额外的预测并返回一个不同的标记,如果它后跟一个看起来像一个类型的东西。最简单的方法是使用flex的/
超前运算符。例如:
"<"/[ \t\n\r]*"<" return OPEN_ANGLE;
"<"/[ \t\n\r]*"int" return OPEN_ANGLE;
"<" return '<';
然后,您将野兔规则更改为OPEN_ANGLE
类型而不是<
:
type : OPEN_ANGLE type '>'
| tINT
expr : tINTEGER
| expr '<' expr
对于更复杂的问题,您可以使用弹性开始状态,甚至可以在词法分析器和解析器之间插入整个标记过滤器/变换传递。
答案 2 :(得分:0)
这是修复,但并不完全令人满意:
%{
%}
%token tNAME tINT tINTEGER
%left '<'
%left '+'
%nonassoc '=' /* <-- LOOK */
%%
declaration: variable
| declaration variable
variable : type tNAME '=' expr
| type tNAME
type : '<' type '>'
| tINT
expr : tINTEGER
| expr '<' expr
| expr '+' expr
;
这个问题是这两个LR项目之间的冲突:点终点:
variable : type tNAME '=' expr_no_less .
和这一个:
expr : expr . '<' expr
请注意,这两个有不同的运算符。正如您所想的那样,并不是涉及'&lt;'的不同作品之间的冲突。操作
通过将=
添加到优先级排名,我们可以解决冲突诊断消失的问题。
请注意,我给了=
一个高优先级。这将通过支持减少来解决冲突。这意味着你不能使用'&lt;'表达式作为初始化程序:
int name = 4 < 3 // syntax error
当&lt;可以看出,int name = 4
希望减少,并且<
必须是下一个声明的开头,作为type
制作的一部分。
要允许<
关系表达式用作初始值设定项,请将括号的支持添加到表达式语法中。然后用户可以括起来:
int foo = (4 < 3) <int> bar = (2 < 1)
如果没有更强大的解析方法或黑客,就没有办法解决这个问题。
如果您在%nonassoc
之前移动%left '<'
,优先级较低,该怎么办?然后转变将受到青睐。不幸的是,这导致您无法在声明后写下另一个<int>
声明。
int foo = 3 <int> bar = 4
^ // error: the machine shifted and is now doing: expr '<' . expr.
这是解决冲突的错误方法;你希望能够写出多个这样的声明。
另一个注意事项:
我的TXR语言实现了与Parse Expression Grammars相当的东西,可以很好地处理这种语法。这基本上是LL(无限),胜过LALR(1)。
我们甚至不需要单独的词法分析器和解析器!这只是因为一个符号前瞻的限制所必需的东西,以及1970年代硬件对最高效率的需求。
shell命令行的示例输出,通过转换为类似Lisp的抽象语法树来演示解析,该语法树绑定到变量dl
(声明列表)。所以这完成了语义动作,产生了一个可以在TXR Lisp中进一步处理的输出。通过调用intern
将标识符转换为Lisp符号,并将数字转换为数字对象。
$ txr -l type.txr -
int x = 3 < 4 int y
(dl (decl x int (< 3 4)) (decl y int nil))
$ txr -l type.txr -
< int > x = 3 < 4 < int > y
(dl (decl x (pointer int) (< 3 4)) (decl y (pointer int) nil))
$ txr -l type.txr -
int x = 3 + 4 < 9 < int > y < int > z = 4 + 3 int w
(dl (decl x int (+ 3 (< 4 9))) (decl y (pointer int) nil)
(decl z (pointer int) (+ 4 3)) (decl w int nil))
$ txr -l type.txr -
<<<int>>>x=42
(dl (decl x (pointer (pointer (pointer int))) 42))
(type.txr
)的源代码:
@(define ws)@/[ \t]*/@(end)
@(define int)@(ws)int@(ws)@(end)
@(define num (n))@(ws)@{n /[0-9]+/}@(ws)@(filter :tonumber n)@(end)
@(define id (id))@\
@(ws)@{id /[A-Za-z_][A-Za-z_0-9]*/}@(ws)@\
@(set id @(intern id))@\
@(end)
@(define type (ty))@\
@(local l)@\
@(cases)@\
@(int)@\
@(bind ty @(progn 'int))@\
@(or)@\
<@(type l)>@\
@(bind ty @(progn '(pointer ,l)))@\
@(end)@\
@(end)
@(define expr (e))@\
@(local e1 op e2)@\
@(cases)@\
@(additive e1)@{op /[<>]/}@(expr e2)@\
@(bind e @(progn '(,(intern op) ,e1 ,e2)))@\
@(or)@\
@(additive e)@\
@(end)@\
@(end)
@(define additive (e))@\
@(local e1 op e2)@\
@(cases)@\
@(num e1)@{op /[+\-]/}@(expr e2)@\
@(bind e @(progn '(,(intern op) ,e1 ,e2)))@\
@(or)@\
@(num e)@\
@(end)@\
@(end)
@(define decl (d))@\
@(local type id expr)@\
@(type type)@(id id)@\
@(maybe)=@(expr expr)@(or)@(bind expr nil)@(end)@\
@(bind d @(progn '(decl ,id ,type ,expr)))@\
@(end)
@(define decls (dl))@\
@(coll :gap 0)@(decl dl)@(end)@\
@(end)
@(freeform)
@(decls dl)