我正在Bison输入文件中描述此语法:https://courses.engr.illinois.edu/cs421/sp2011/mps/mp2/minijavasyntax.pdf
这是我的输入:
%start Program
%token KW_CLASS KW_EXTENDS KW_PUBLIC KW_STATIC KW_BOOLEAN KW_STRING KW_FLOAT KW_INT EOF
%token KW_IF KW_WHILE KW_BREAK KW_CONTINUE KW_SWITCH KW_CASE KW_DEFAULT KW_RETURN
%token KW_NEW KW_THIS KW_NULL KW_TRUE KW_FALSE KW_PRINTLN
%token IDENT INT_LITERAL FLOAT_LITERAL STRING_LITERAL
%nonassoc "THEN"
%nonassoc KW_ELSE
%right "STATEMENTS"
%right OP_ASSIGN
%left OP_OR
%left OP_AND
%nonassoc CMP_EQ CMP_NEQ
%nonassoc CMP_GT CMP_LT CMP_GTE CMP_LTE
%left OP_ADD OP_MINUS
%left OP_MULT OP_DIV OP_MOD
%right OP_NOT OP_UNARY "NEW"
%left "FUNCALL" "SUBSCRIPT" '.'
%nonassoc '('
%nonassoc ')'
%%
Program: ClassDeclp EOF
;
ClassDeclp: ClassDecl
| ClassDeclp ClassDecl
;
ClassDecl: KW_CLASS IDENT ExtendsFrom
'{' VarDecls MethodDecls '}'
;
ExtendsFrom: /*empty*/
| KW_EXTENDS IDENT
;
VarDecls: /*empty*/
| VarDecls VarDecl
;
VarDecl: Type IDENT ';'
| KW_STATIC Type IDENT ';' /*Co the sua thanh AcessModifier Type IDENT*/
;
MethodDecls: /*empty*/
| MethodDecls MethodDecl
;
MethodDecl: KW_PUBLIC Type IDENT
'('MethodParams')'
'{'VarDecls Statements KW_RETURN Expression ';' '}'
;
MethodParams: /*empty*/
| MethodParams ',' MethodParam
;
MethodParam: Type IDENT;
Type : Type '['']'
| KW_BOOLEAN
| KW_STRING
| KW_FLOAT
| KW_INT
| IDENT
;
Statements: Statements Statement %prec "STATEMENTS"
| /*empty*/ %prec "STATEMENT"
;
Statementp: Statements Statement %prec "STATEMENTS"
;
Statement: '{'Statements'}'
| KW_IF '(' Expression ')' Statement %prec "THEN"
| KW_IF '(' Expression ')' Statement KW_ELSE Statement
| KW_WHILE '(' Expression ')'Statement
| KW_PRINTLN '(' Expression ')' ';'
| IDENT OP_ASSIGN Expression ';'
| KW_BREAK ';'
| KW_CONTINUE ';'
| IDENT %prec "SUBSCRIPT" '['Expression']' '=' Expression ';'
| KW_SWITCH '(' Expression ')' '{'
Cases
KW_DEFAULT ':' Statementp '}'
;
Cases: Cases Case
| /*empty*/
;
Case: KW_CASE INT_LITERAL ':' Statementp
;
Expression: Expression OP_OR Expression
| Expression OP_AND Expression
| Expression CMP_EQ Expression
| Expression CMP_NEQ Expression
| Expression CMP_GT Expression
| Expression CMP_GTE Expression
| Expression CMP_LT Expression
| Expression CMP_LTE Expression
| Expression OP_ADD Expression
| Expression OP_MINUS Expression
| Expression OP_MULT Expression
| Expression OP_DIV Expression
| Expression OP_MOD Expression
| '-' Expression %prec OP_UNARY
| OP_NOT Expression
| Expression %prec "SUBSCRIPT" '['Expression']'
| Expression '.'"length"
| Expression '.' IDENT %prec "FUNCALL" '(' ParamList ')'
| INT_LITERAL
| FLOAT_LITERAL
| STRING_LITERAL
| KW_NULL
| KW_TRUE
| KW_FALSE
| IDENT
| KW_THIS
| KW_NEW Type '[' Expression ']' %prec "NEW"
| KW_NEW IDENT '('')' %prec "NEW"
| '(' Expression ')'
;
ParamList: /*empty*/
| ParamList ',' Expression
| Expression
;
%%
main(int argc, char** argv[])
{
extern FILE *yyin;
++argv; --argc;
yyin = fopen(argv[0], "r");
yydebug = 1;
errors = 0;
yyparse();
}
yyerror(char *s)
{
printf("%sn", s);
}
/* Co 3 conflict RR can xu ly khi bien thuoc kieu bool
giua BoolExpr va Expresstion */
我在编译时遇到了两个16冲突。其中一个冲突,我用--report=lookahead:运行Bison
OP_NOT Expression . [OP_OR, OP_AND, CMP_EQ, CMP_NEQ, CMP_GT, CMP_LT, CMP_GTE, CMP_LTE, OP_ADD, OP_MINUS, OP_MULT, OP_DIV, OP_MOD, ')', ';', ',', '[', ']']
我所期望的是"["不在OP_not前瞻性令牌中,因为SUBSCRIPT优先级必须高于Operator!。其他冲突就是这样。我该怎么解决。Tks
优先级不是这样工作的。
编辑:如果你觉得以下描述令人困惑,或者你不想费力阅读太多英文文本,你可以接受我的常规建议:不要使用优先级。您几乎总是可以编写一个不需要优先级声明的明确语法。如果你这样做了,你就不需要理解优先级。(不过,老实说,如果你了解LR解析的工作原理,它就没有那么复杂了。)/EDIT
优先级总是比较可能的减少(即其右手边与当前解析器堆栈顶部匹配的产品)和前瞻符号。
此时:
Expression : Expression · '[' Expression ']'
唯一可能的解析器操作是移位,因为只有当点位于右手边的末端时,才能进行减少。
然而,在发生这一点的状态之一,还有另一种生产:
Expression : OP_NOT Expression ·
这个可以减少,因为点在末尾。
由于这两个点处于相同的状态,因此它们必须都是有效的。这意味着我们正在关注:
OP_NOT Expression · '[' Expression ']'
我们正试图弄清楚该怎么办。我们可以将OP_NOT Expression
减少到Expression
,此时我们将得到:
Expression · '[' Expression ']'
或者我们可以转移"[",留下
OP_NOT Expression '[' · Expression ']'
由于这两者都是可能的,因此存在偏移/减少冲突。Yacc/Bison将尝试使用优先级规则(如果存在)来解决该冲突。特别是,它需要比较生产的优先级,这可能会减少:
Expression : OP_NOT Expression
以及可能被移位的符号:CCD_ 4。
但是,仔细查看优先级声明可以发现'['
没有分配优先级。因此,yacc/bison无法针对生产(其优先级由右侧的最后一个终端OP_NOT
定义,因为没有%prec
声明。
如果希望后缀下标运算符([
表达式']')的优先级高于前缀运算符OP_NOT
,则必须声明[
的优先级高于OP_NOT
。
顺便说一句,我不认为这里有什么不一致的地方。您可以将!
用于OP_NOT
(将-
用于OP_MINUS
等等),这样会更容易阅读,工作量更少。
你似乎认为中的%prec
声明
Expression %prec "SUBSCRIPT" '['Expression']'
是相关的。事实并非如此。只有当解析器能够减少Expression '[' Expression ']'
时,它才适用。但这也是毫无意义的,因为你不需要创建一个虚假的终端来获得该产品的优先权;它的优先级是由右侧的最后一个端子']'
定义的,所以您可以只声明该端子的优先级。
声明Expression : OP_MINUS Expression %prec OP_UNARY
中的伪令牌是必需的,因为'-'
具有两个不同的优先级,或者更准确地说,因为OP_MINUS Expression
具有与Expresson OP_MINUS Expression
不同的优先级。不过,你实际上并不需要发明一个假代币;您可以使用任何具有正确优先级的令牌,例如OP_NOT
或OP_NEW
。
如果这还不够的话,我试着用几个不同的SO答案来解释这一点。这是一个,这是另一个,还有一个。此外,这是克里斯·多德的一本,这是野牛手册中的文档。如果你幸运的话,你可能会用自己的语言找到描述,使用任何最适合你的互联网搜索引擎,或者与你的教授交谈(如果你有)。
顺便说一句,前瞻性报告告诉你哪些符号可能跟随给定的生产。先例对此没有影响。CCD_ 25肯定能跟得上CCD_ 26。优先级告诉解析器是减少还是移位,但可能触发减少或移位的令牌肯定在前瞻集中。