Parsing Bison:有效表达式的GLR解析失败,没有错误消息
我正在GNU bison中使用GLR解析器,我有以下问题: 我试图解析的语言允许布尔表达式,包括关系(、b和c),我可以在调试输出中看到,解析器的行为如下:Parsing Bison:有效表达式的GLR解析失败,没有错误消息,parsing,bison,cobol,glr,Parsing,Bison,Cobol,Glr,我正在GNU bison中使用GLR解析器,我有以下问题: 我试图解析的语言允许布尔表达式,包括关系(、b和c),我可以在调试输出中看到,解析器的行为如下: booleanexpression : relation | booleanexpression TOK_AND booleanexpression ... ; relation : arithmeticexpression TOK_GT maxtree ... ; maxtree : ari
booleanexpression
: relation
| booleanexpression TOK_AND booleanexpression
...
;
relation
: arithmeticexpression TOK_GT maxtree
...
;
maxtree
: arithmeticexpression
| maxtree TOK_AND maxtree
...
;
- 它读取
并在向前看a
时将
简化为a
算术表达式
- 它读取
,并在向前看b
时,将和
简化为b
,然后已经简化为算术表达式
maxtree
- 它将
减少为a>b
关系
- 它读取
并将其简化为c
算术表达式
和c
显然被丢弃了-调试输出没有显示这些令牌的任何操作。甚至没有错误消息。相应的if语句在我的AST中不存在(我仍然得到AST,因为我有错误恢复)
我会认为,在阅读了b
之后,应该有两个堆栈。但是b
不应该减少。或者至少它应该给我一些错误消息(“语言不明确”可以,我以前见过这个消息-我不明白为什么它不适用于这里)。有人能理解这一点吗
从一段时间的语法来看,这里的主要问题是在下一个算术表达式之后是否会出现
- 另一个关系标记(那么您应该减少)
- 另一个布尔合成(然后您应该移位)
- 布尔/算术表达式语法(如THEN)之外的一个标记,它将终止表达式,并且还应该移位
booleanexpression : relation AND booleanexpression
maxtree : arithmeticexpression AND maxtree
etc.
我想这会让野牛更喜欢移动,只会先在右边减少。也许通过使用不同的非终端,它会允许在算术表达式后面有一个准“前瞻性”
旁注:GnuCOBOL处理这个问题的方法是收集所有的标记,将它们推到中间堆栈上,然后从那里手动构建表达式。这让我很沮丧,但我还是希望他们这样做,因为bison在开始时不支持GLR解析
编辑:
一个可复制的小例子
%{
#include <stdio.h>
int yylex ();
void yyerror(const char* msg);
%}
%glr-parser
%left '&'
%left '>'
%%
input: %empty | input bool '\n' {printf("\n");};
arith : 'a' | 'b' | 'c';
maxtree : arith { printf("[maxtree : arith] "); }
| maxtree '&' maxtree { printf("[maxtree : maxtree & maxtree] "); } ;
rel : arith '>' maxtree { printf("[rel : arith > maxtree] "); } ;
bool : rel { printf("[bool : rel] "); }
| bool '&' bool { printf("[bool : bool & bool] "); } ;
%%
void yyerror(const char* msg) { printf("%s\n", msg); }
int yylex () {
int c;
while ((c = getchar ()) == ' ' || c == '\t');
return c == EOF ? 0 : c;
}
int main (int argc, char** argv) {
return yyparse();
}
%{
#包括
int-yylex();
无效错误(常量字符*消息);
%}
%glr解析器
%左“&”
%左'>'
%%
输入:%empty | input bool'\n'{printf(“\n”);};
arith:‘a’|‘b’|‘c’;
maxtree:arith{printf(“[maxtree:arith]”;}
|maxtree'&'maxtree{printf(“[maxtree:maxtree&maxtree]”;};
rel:arith'>'maxtree{printf(“[rel:arith>maxtree]”;};
bool:rel{printf(“[bool:rel]”;}
|bool'&bool{printf(“[bool:bool&bool]”);
%%
void yyerror(const char*msg){printf(“%s\n”,msg);}
int-yylex(){
INTC;
而((c=getchar())=''|| c=='\t');
返回c==EOF?0:c;
}
int main(int argc,字符**argv){
返回yyparse();
}
奇怪的是,这一条确实在输入
a>b&c
上打印了错误消息“syntax error”(语法错误)。通过使用优先级声明简化语法确实很方便(有时)[注1],但它不能很好地使用GLR解析器,因为它可能导致早期拒绝明确的解析
优先级声明背后的思想是解决歧义(或者更准确地说,转移/减少冲突)使用一个简单的单令牌前瞻,并在可能的缩减和可能的移位之间配置优先级。如果语法没有移位/缩减冲突,则不会使用优先级声明,但如果使用它们,则将根据(静态)优先级关系,使用它们来抑制移位或缩减
Bison生成的GLR解析器实际上并不解决歧义,但它允许继续开发可能不正确的解析,直到语法解决歧义。与使用优先级不同,这是一种延迟解析;速度稍慢,但功能更强。(GLR解析器可以生成“解析林”包含所有可能的解析。但Bison没有实现此功能,因为它期望解析编程语言,并且与人类语言不同,编程语言不能含糊不清。)
在你的语言中,不可能静态地解决移位/减少冲突的不确定性,正如你在问题中所指出的那样。你的语法根本不是LR(1),更少的运算符优先级,因此GLR解析是一个实用的解决方案。但您必须允许GLR完成其工作。过早地使用优先级比较来消除其中一个看似合理的解析将阻止GLR算法在以后考虑它。如果您设法消除唯一与uld是正确的
在语法中,不可能定义rel
产品和&
符号之间的优先关系,因为不存在优先关系。在某些句子中,rel
缩减需要赢;在其他句子中,移位应该赢。因为语法不含糊,GLR最终会赢找出哪个是哪个,只要换档和减速都允许进行
在您的完整语言中,布尔表达式和算术表达式都有类似于运算符优先级的内容,但仅在其各自的域中。运算符优先级解析器(以及等效的yacc/bison优先级声明)其工作原理是消除不同非终端之间的差异;它无法处理像您这样的语法,其中某些操作
%left '+' '-'
%left '*' '/'
%% %%
expr : term
| expr '+' term expr: expr '+' expr
| expr '-' term | expr '-' expr
term : factor
| term '*' factor | expr '*' expr
| term '/' factor | expr '/' expr
factor: ID | ID
| '(' expr ')' | '(' expr ')'
%code top {
#define _GNU_SOURCE 1
}
%{
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int yylex(void);
void yyerror(const char* msg);
%}
%define api.value.type { char* }
%glr-parser
%token ID
%%
input : %empty
| input bool '\n' { puts($2); }
arith : ID
maxtree : arith
| maxtree '&' arith { asprintf(&$$, "[maxtree& %s %s]", $1, $3); }
rel : arith '>' maxtree { asprintf(&$$, "[COMP %s %s]", $1, $3); }
bool : rel
| bool '&' rel { asprintf(&$$, "[AND %s %s]", $1, $3); }
%%
void yyerror(const char* msg) { printf("%s\n", msg); }
int yylex(void) {
int c;
while ((c = getchar ()) == ' ' || c == '\t');
if (isalpha(c)) {
*(yylval = strdup(" ")) = c;
return ID;
}
else return c == EOF ? 0 : c;
}
int main (int argc, char** argv) {
#if YYDEBUG
if (argc > 1 && strncmp(argv[1], "-d", 2) == 0) yydebug = 1;
#endif
return yyparse();
}
$ bison -t -o glr_prec.c glr_prec.y
glr_prec.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
$ gcc -Wall -o glr_prec glr_prec.c
$ ./glr_prec
a>b
[COMP a b]
a>b & c
[COMP a [maxtree& b c]]
a>b & c>d
[AND [COMP a b] [COMP c d]]
a>b & c & c>d
[AND [COMP a [maxtree& b c]] [COMP c d]]
a>b & c>d & e
[AND [COMP a b] [COMP c [maxtree& d e]]]
$
IDENTIFICATION DIVISION.
PROGRAM-ID EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 A PIC 9 VALUE 2.
01 B PIC 9 VALUE 1.
01 W PIC 9 VALUE 3.
88 C VALUE 3.
PROCEDURE DIVISION.
IF A > B AND C
DISPLAY 'A > B AND 88 LEVEL C is TRUE because W = ' W
ELSE
DISPLAY 'A not > B or 88 LEVEL C is not TRUE'
END-IF
DISPLAY 'A: ' A ' B: ' B ' W:' W
GOBACK
.
A > B AND 88 LEVEL C is TRUE because W = 3
A: 2 B: 1 W: 3
%skeleton "glr.cc"