2014-02-15 71 views
1

[注意作業]在YACC解析賦值語句時得到一個語法錯誤

我需要一個提示,爲什麼下面的代碼失敗時,我嘗試運行測試用例: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

的錯誤是很簡單的:

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。對於運營商令牌(+,-等)或保留字,這幾乎肯定是不必要的,因爲您永遠不會引用這些令牌的「語義值」。 (作爲證據,您不會聲明任何這些令牌甚至具有語義類型。)不必要的複製確實會產生成本,特別是如果您需要清理爲副本分配的內存。

好運。