0
下面是我解析C源代码的yacc代码。我对此有点新,这是一个已经存在的代码。编译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
{ $$ = $1; }
| program function
{ $$ = binaryNode("",$1,$2);}
| error '}'
function:
typename Identifier '(' formal.arguments ')' function.body
{ $$ = attachAllChildren($2,$1,$4,$6); }
typename
: INT
{ $$ = leafNode("INT");}
| CHAR
{ $$ = leafNode("CHAR"); }
| DOUBLE
{ $$ = leafNode("DOUBLE"); }
| LONG
{ $$ = leafNode("LONG"); }
| FLOAT
{ $$ = leafNode("FLOAT"); }
formal.arguments
: /* empty */
{ $$ = NULL; }
| formal.argument.list
{ $$ = $1; }
formal.argument.list
: formal.argument
{ $$ = $1; }
| formal.argument.list ',' formal.argument
{ $$ = binaryNode(",", $1, $3); }
formal.argument
: typename Identifier
{ $$ = attachChild($2, $1); }
function.body
: '{' '}'
{ $$ = NULL; }
| '{' statements '}'
{ $$ = $2; }
statements
: statement
{ $$ = $1; }
| statements statement
{ $$ = attachChild($1,$2);}
statement
: declaration
{ $$ = $1; }
| RETURN expression ';' /* return statement */
{ $$ = unaryNode("RETURN", $2); }
| if.statement
{ $$ =$1; }
| term '=' expression ';' /* assignment */
{ $$ = binaryNode("=", $1, $3); }
| expression ';'
{ $$ = $1; }
| '{' statements '}'
{ $$ = $2; }
| ';' /* null statement */
{ $$ = NULL; }
declaration
: typename Identifier ';'
{ $$ = attachChild($2,$1); }
| typename Identifier '[' Number ']' ';' /* array */
{ $$ = attachSiblings($2, $1, $4); }
if.statement
: IF '(' expression ')' statement
{ $$ = ternaryNode("IF",$3,$5, NULL); }
| IF '(' expression ')' statement ELSE statement
{ $$ = ternaryNode("IF", $3, $5, $7); }
expression
: additive.expression
{ $$ = $1; }
| expression EQ additive.expression
{ $$ = binaryNode("=",$1, $3); }
| expression '>' additive.expression
{ $$ = binaryNode(">", $1, $3); }
| expression '<' additive.expression
{ $$ = binaryNode("<", $1, $3); }
additive.expression
: term
{ $$ = $1; }
| additive.expression '+' term
{ $$ = binaryNode("+", $1, $3);}
| additive.expression '-' term
{ $$ = binaryNode("-", $1, $3);}
term
: Identifier
{ $$ = leafNode($1);}
| Number
{ $$ = leafNode($1);}
| Identifier '(' opt.actual.arguments ')' /* function call */
{ $$ = attachChild($1,$3);}
| Identifier '[' expression ']' /* array access */
{ $$ = attachChild($1,$3); }
| '(' expression ')'
{ $$ = $2;}
opt.actual.arguments
: /* empty */
{ $$ = NULL;}
| actual.arguments
{ $$=$1; }
actual.arguments
: expression
{ $$ = $1; }
| actual.arguments ',' expression
{ $$ = binaryNode(",",$1, $3); }
%%
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冲突。我该如何解决这个问题?
绝对是的,但是我的词法分析器应该生成什么样的标记(我主要希望只生成算术操作及其相应的操作符?我也可以直接删除节点赋值语句,直到抽象语法树在上面的解析器中有关吗? –
@AbhijeetMohanty:我不确定我是否理解你的后续问题,你的词法分析器需要生成你的解析器使用的标记,你的.y文件的赋值语句(在动作中)建立一个AST 。如果你不想要/需要一个AST,那么你可以摆脱它们 - 动作对解析的语言没有影响(除非它们将信息反馈给词法分析器),它们只是在解析器减少规则时运行。 –