编译 Yacc 代码
Compiling Yacc code
下面是我解析C源代码的yacc代码。我对此有点陌生,这是一个已经存在的代码。
{
%{
#include <stdio.h>
#include <string.h>
#include "Expression.c"
%}
%token Identifier
%token Number
%token '=' '+' '-' '*' '/' ',' ';' '(' ')' '{' '}' '[' ']' '<' '>'
%token INT
%token CHAR
%token FLOAT
%token LONG
%token DOUBLE
%token RETURN
%token IF
%token ELSE
%token EQ /* == */
%token BADTOKEN
%%
program
: function
{ $$ = ; }
| program function
{ $$ = binaryNode("",,);}
| error '}'
function:
typename Identifier '(' formal.arguments ')' function.body
{ $$ = attachAllChildren(,,,); }
typename
: INT
{ $$ = leafNode("INT");}
| CHAR
{ $$ = leafNode("CHAR"); }
| DOUBLE
{ $$ = leafNode("DOUBLE"); }
| LONG
{ $$ = leafNode("LONG"); }
| FLOAT
{ $$ = leafNode("FLOAT"); }
formal.arguments
: /* empty */
{ $$ = NULL; }
| formal.argument.list
{ $$ = ; }
formal.argument.list
: formal.argument
{ $$ = ; }
| formal.argument.list ',' formal.argument
{ $$ = binaryNode(",", , ); }
formal.argument
: typename Identifier
{ $$ = attachChild(, ); }
function.body
: '{' '}'
{ $$ = NULL; }
| '{' statements '}'
{ $$ = ; }
statements
: statement
{ $$ = ; }
| statements statement
{ $$ = attachChild(,);}
statement
: declaration
{ $$ = ; }
| RETURN expression ';' /* return statement */
{ $$ = unaryNode("RETURN", ); }
| if.statement
{ $$ =; }
| term '=' expression ';' /* assignment */
{ $$ = binaryNode("=", , ); }
| expression ';'
{ $$ = ; }
| '{' statements '}'
{ $$ = ; }
| ';' /* null statement */
{ $$ = NULL; }
declaration
: typename Identifier ';'
{ $$ = attachChild(,); }
| typename Identifier '[' Number ']' ';' /* array */
{ $$ = attachSiblings(, , ); }
if.statement
: IF '(' expression ')' statement
{ $$ = ternaryNode("IF",,, NULL); }
| IF '(' expression ')' statement ELSE statement
{ $$ = ternaryNode("IF", , , ); }
expression
: additive.expression
{ $$ = ; }
| expression EQ additive.expression
{ $$ = binaryNode("=",, ); }
| expression '>' additive.expression
{ $$ = binaryNode(">", , ); }
| expression '<' additive.expression
{ $$ = binaryNode("<", , ); }
additive.expression
: term
{ $$ = ; }
| additive.expression '+' term
{ $$ = binaryNode("+", , );}
| additive.expression '-' term
{ $$ = binaryNode("-", , );}
term
: Identifier
{ $$ = leafNode();}
| Number
{ $$ = leafNode();}
| Identifier '(' opt.actual.arguments ')' /* function call */
{ $$ = attachChild(,);}
| Identifier '[' expression ']' /* array access */
{ $$ = attachChild(,); }
| '(' expression ')'
{ $$ = ;}
opt.actual.arguments
: /* empty */
{ $$ = NULL;}
| actual.arguments
{ $$=; }
actual.arguments
: expression
{ $$ = ; }
| actual.arguments ',' expression
{ $$ = binaryNode(",",, ); }
%%
yyerror(msg)
char* msg;
{
#if !defined(YYBISON)
extern int yynerrs;
++yynerrs;
#endif
fprintf(stderr, "Error: %s\n",msg);
}
main()
{
extern int yynerrs;
yyparse();
fprintf(stderr, "%d errors.\n", yynerrs);
return 0;
}
}
在编译上述代码时,我收到一条警告,指出代码中存在 1 个 shift/reduce 冲突。我该如何解决?
使用 yacc 的 -v
选项,它将生成一个 y.output
文件,告诉您冲突在哪里以及它是如何触发的。请注意,冲突不是错误——您仍然可以从 yacc 获得有效的解析器——但该解析器可能无法准确识别您的语法定义的语言。
在你的情况下,你会得到类似的东西:
State 81 conflicts: 1 shift/reduce
:
State 81
28 if.statement: IF '(' expression ')' statement .
29 | IF '(' expression ')' statement . ELSE statement
ELSE shift, and go to state 83
ELSE [reduce using rule 28 (if.statement)]
$default reduce using rule 28 (if.statement)
这告诉你你有经典的 dangling else ambiguity,所以你可以忽略冲突,因为生成的解析器将通过将 else 绑定到最接近的 if 来解决歧义,这可能就是你想要。
下面是我解析C源代码的yacc代码。我对此有点陌生,这是一个已经存在的代码。
{
%{
#include <stdio.h>
#include <string.h>
#include "Expression.c"
%}
%token Identifier
%token Number
%token '=' '+' '-' '*' '/' ',' ';' '(' ')' '{' '}' '[' ']' '<' '>'
%token INT
%token CHAR
%token FLOAT
%token LONG
%token DOUBLE
%token RETURN
%token IF
%token ELSE
%token EQ /* == */
%token BADTOKEN
%%
program
: function
{ $$ = ; }
| program function
{ $$ = binaryNode("",,);}
| error '}'
function:
typename Identifier '(' formal.arguments ')' function.body
{ $$ = attachAllChildren(,,,); }
typename
: INT
{ $$ = leafNode("INT");}
| CHAR
{ $$ = leafNode("CHAR"); }
| DOUBLE
{ $$ = leafNode("DOUBLE"); }
| LONG
{ $$ = leafNode("LONG"); }
| FLOAT
{ $$ = leafNode("FLOAT"); }
formal.arguments
: /* empty */
{ $$ = NULL; }
| formal.argument.list
{ $$ = ; }
formal.argument.list
: formal.argument
{ $$ = ; }
| formal.argument.list ',' formal.argument
{ $$ = binaryNode(",", , ); }
formal.argument
: typename Identifier
{ $$ = attachChild(, ); }
function.body
: '{' '}'
{ $$ = NULL; }
| '{' statements '}'
{ $$ = ; }
statements
: statement
{ $$ = ; }
| statements statement
{ $$ = attachChild(,);}
statement
: declaration
{ $$ = ; }
| RETURN expression ';' /* return statement */
{ $$ = unaryNode("RETURN", ); }
| if.statement
{ $$ =; }
| term '=' expression ';' /* assignment */
{ $$ = binaryNode("=", , ); }
| expression ';'
{ $$ = ; }
| '{' statements '}'
{ $$ = ; }
| ';' /* null statement */
{ $$ = NULL; }
declaration
: typename Identifier ';'
{ $$ = attachChild(,); }
| typename Identifier '[' Number ']' ';' /* array */
{ $$ = attachSiblings(, , ); }
if.statement
: IF '(' expression ')' statement
{ $$ = ternaryNode("IF",,, NULL); }
| IF '(' expression ')' statement ELSE statement
{ $$ = ternaryNode("IF", , , ); }
expression
: additive.expression
{ $$ = ; }
| expression EQ additive.expression
{ $$ = binaryNode("=",, ); }
| expression '>' additive.expression
{ $$ = binaryNode(">", , ); }
| expression '<' additive.expression
{ $$ = binaryNode("<", , ); }
additive.expression
: term
{ $$ = ; }
| additive.expression '+' term
{ $$ = binaryNode("+", , );}
| additive.expression '-' term
{ $$ = binaryNode("-", , );}
term
: Identifier
{ $$ = leafNode();}
| Number
{ $$ = leafNode();}
| Identifier '(' opt.actual.arguments ')' /* function call */
{ $$ = attachChild(,);}
| Identifier '[' expression ']' /* array access */
{ $$ = attachChild(,); }
| '(' expression ')'
{ $$ = ;}
opt.actual.arguments
: /* empty */
{ $$ = NULL;}
| actual.arguments
{ $$=; }
actual.arguments
: expression
{ $$ = ; }
| actual.arguments ',' expression
{ $$ = binaryNode(",",, ); }
%%
yyerror(msg)
char* msg;
{
#if !defined(YYBISON)
extern int yynerrs;
++yynerrs;
#endif
fprintf(stderr, "Error: %s\n",msg);
}
main()
{
extern int yynerrs;
yyparse();
fprintf(stderr, "%d errors.\n", yynerrs);
return 0;
}
}
在编译上述代码时,我收到一条警告,指出代码中存在 1 个 shift/reduce 冲突。我该如何解决?
使用 yacc 的 -v
选项,它将生成一个 y.output
文件,告诉您冲突在哪里以及它是如何触发的。请注意,冲突不是错误——您仍然可以从 yacc 获得有效的解析器——但该解析器可能无法准确识别您的语法定义的语言。
在你的情况下,你会得到类似的东西:
State 81 conflicts: 1 shift/reduce
:
State 81
28 if.statement: IF '(' expression ')' statement .
29 | IF '(' expression ')' statement . ELSE statement
ELSE shift, and go to state 83
ELSE [reduce using rule 28 (if.statement)]
$default reduce using rule 28 (if.statement)
这告诉你你有经典的 dangling else ambiguity,所以你可以忽略冲突,因为生成的解析器将通过将 else 绑定到最接近的 if 来解决歧义,这可能就是你想要。