在yacc中解析赋值语句时出现语法错误

时间:2014-02-15 17:01:52

标签: c yacc lex

[警告作业]

当我尝试运行测试用例时,我需要提示以下代码失败的原因:int a = 3;所有代码都编译时没有警告或错误,据我所知,结构是正确的。我觉得assignment的规则中一定存在问题。

错误消息显示:ERROR: syntax error at symbol "a" on line 1

这是.lex文件:

%{

#include "calc.h"
#include "symbol-table.h"
#include "tok.h"
int yyerror(char *s);
int yylinenum = 1;
%}

digit        [0-9]
int_const    {digit}+
float_const  {digit}+[.]{digit}+
id           [a-zA-Z]+[a-zA-Z0-9]*

%%

{int_const}    { yylval.int_val = atoi(yytext); return INTEGER_LITERAL; }
{float_const}  { yylval.float_val = atof(yytext); return FLOAT_LITERAL; }
"="            { yylval.str_val = strdupclean(yylval.str_val, yytext); return EQUALS; }
"+"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return PLUS; }
"*"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return MULT; }
"-"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return MINUS; }
"/"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return DIV; }
"("            { yylval.str_val = strdupclean(yylval.str_val, yytext); return OPAREN; }
")"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return CPAREN; }
";"            { yylval.str_val = strdupclean(yylval.str_val, yytext); return SEMIC; }
"sqrt"         { yylval.str_val = strdupclean(yylval.str_val, yytext); return SQRT; }
{id}           { yylval.str_val = strdupclean(yylval.str_val, yytext); 
                 /*HINT: One way to simplify parsing is to have lex return what
                  * type of variable we have.  IVAR = int, FVAR = float
                  * UVAR = unknown var.
                  * Naturally, you may use your own solution.
                  */
              if (strcmp(yylval.str_val, "int")) {return IVAR;}
              else if (strcmp(yylval.str_val, "float")) {return FVAR;}
                  else {return UVAR;} 
               }

[ \t]*         {}
[\n]           { yylinenum++;    }

.              { yyerror("Unknown Symbol"); exit(1); }
%%

这是yacc文件:

%{
#include "calc.h"
#include "symbol-table.h"
int yyerror(char *s);
int yylex(void);
%}

%union{
int         int_val;
float       float_val;
char*       str_val;
}

%start input

%token <int_val>   INTEGER_LITERAL
%token <float_val> FLOAT_LITERAL
%token <float_val> SQRT
%token OPAREN CPAREN SEMIC IVAR FVAR UVAR
%type  <int_val>   int_exp
%type  <float_val> float_exp
%type  <str_val>  IVAR FVAR UVAR
%right EQUALS /*right associative, everything on the right side of the = should be evaluated and stored*/
%left  PLUS MINUS/*The order matters, by listing PLUS/MIUS first and then MULT/DIV we are */
%left  MULT DIV /*telling yacc to evaluate MULTs & DIVs before PLUSes and MINUSes*/

%%

input:           /*empty*/
            | int_exp                   { printf("Result %d\n", $1); }
            | float_exp                 { printf("Result %f\n", $1); }
            | assignment                { printf("Result \n"); }
            ;

int_exp:          INTEGER_LITERAL           { $$ = $1; }
            | int_exp PLUS int_exp      { $$ = $1 + $3; }
            | int_exp MULT int_exp      { $$ = $1 * $3; }
            | int_exp MINUS int_exp     { $$ = $1 - $3; }
            | int_exp DIV int_exp       { $$ = $1 / $3; }
            | OPAREN int_exp CPAREN     { $$ = $2; }
            ;

float_exp:        FLOAT_LITERAL             { $$ = $1; }
            | float_exp PLUS float_exp  { $$ = $1 + $3; }
            | float_exp MULT float_exp  { $$ = $1 * $3; }
            | float_exp MINUS float_exp { $$ = $1 - $3; }
            | float_exp DIV float_exp   { $$ = $1 / $3; }
            | int_exp PLUS float_exp    { $$ = (float)$1 + $3; }
            | int_exp MULT float_exp    { $$ = (float)$1 * $3; }
            | int_exp MINUS float_exp   { $$ = (float)$1 - $3; }
            | int_exp DIV float_exp     { $$ = (float)$1 / $3; }
            | float_exp PLUS int_exp    { $$ = (float)$1 + $3; }
            | float_exp MULT int_exp    { $$ = (float)$1 * $3; }
            | float_exp MINUS int_exp   { $$ = (float)$1 - $3; }
            | float_exp DIV int_exp     { $$ = (float)$1 / $3; }
            | OPAREN float_exp CPAREN   { $$ = $2; }
            | SQRT OPAREN float_exp CPAREN  { $$ = sqrt((double)$3); }
            | SQRT OPAREN int_exp CPAREN    { $$ = sqrt((double)$3); }
            ;

assignment:       UVAR EQUALS float_exp SEMIC           { //if UVAR exists and is float, update value
                                          //if UVAR doesn't exist, error: unknown type
                                          symbol_table_node *n1 = symbol_table_find( $1, *st);
                                          if(n1) { 
                                            if(n1->type == FLOAT_TYPE) {
                                                n1->val.float_val = $3;
                                            } else {
                                                //error
                                            }
                                            //error, variable not defined
                                          //if UVAR is not float, error: illegal assignment
                                          }
                                        }
            | UVAR EQUALS int_exp SEMIC         { 
                                          symbol_table_node *n1 = symbol_table_find( $1, *st);
                                          if(n1) { 
                                            if(n1->type == INT_TYPE) {
                                                n1->val.int_val = $3;
                                            } else {
                                                //error
                                            }
                                          }
                                        }
            | IVAR UVAR EQUALS int_exp SEMIC { //UVAR should not be in symbol table
                                          if(symbol_table_find($2, *st)) {
                                            //error
                                          } else {
                                            //how to handle errors?
                                            symbol_table_add_i($2, $4, *st);
                                          }
                                        }
            | FVAR UVAR EQUALS float_exp SEMIC { 
                                          if(symbol_table_find($2, *st)) {

                                          } else {
                                            symbol_table_add_f($2, $4, *st);
                                          }
                                        }
            ;

%%

int yyerror(char *s){
extern int yylinenum; /* defined and maintained in lex.c*/
extern char *yytext;  /* defined and maintained in lex.c*/

printf("ERROR: %s at symbol \"%s\" on line %d\n", s, yytext, yylinenum);
return -1;
}

1 个答案:

答案 0 :(得分:1)

这个错误很简单:

if (strcmp(yylval.str_val, "int"))

不符合您的想法。如果两个字符串相等,则strcmp返回0;如果第一个字符串在字典上较早,则返回负值;如果第一个字符串稍后按字典顺序,则返回正值。用作布尔值,表示如果字符串比较相等,则strcmpfalse,否则为true。因此,令牌int不会生成令牌值IVAL

但我不认为这真的是你想要做的事情。您的教师提示让词法分析器返回与令牌的已知数据类型相对应的令牌类型,这是指在符号表中查找变量并返回与变量声明相对应的令牌类型。它并不是指识别保留字intfloat,而应使用简单的词法规则来完成,就像保留字sqrt的规则一样。

如上所述,你的语法不允许表达式使用变量,所以(即使你修复了我提到的错误),以下内容也会失败:

int b = 0;
int a = b + 3;

因为b不会被识别为int_exp。在这种情况下,教师的提示适用。 (虽然就个人而言,我建议采用不同的方式。)

最后,我不知道strdupclean做了什么,但我认为它涉及制作yytext的副本。在运算符令牌(+-等)或保留字的情况下,这几乎肯定是不必要的,因为您永远不会引用这些令牌的“语义值”。 (作为证据,您不会声明这些令牌中的任何一个甚至具有语义类型。)不必要的复制确实有成本,特别是如果您需要清理为副本分配的内存。

祝你好运。