Yacc 的语法错误,即使语法是每个语法
Syntax error by Yacc even though the syntax is per grammar
我的 yacc 解析器显示语法错误,即使语法符合语法。
我的 Yacc 代码:
%{
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int symbols[100];
int yylex();
int symbolVal(char symbol);
void updateSymbolVal(char symbol,int val);
%}
%union {int num; char id;}
%start line
%token WHILE
%token lt
%token gt
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%type <num> condition
%%
line: assignment {;}
|line assignment {;}
|exit_command {exit(EXIT_SUCCESS);}
|line exit_command {exit(EXIT_SUCCESS);}
|whileLoop {;}
|condition {;}
;
whileLoop: WHILE '(' condition ')' '{' assignment '}' {printf("while loop condition var:%d\n",);}
;
assignment : identifier '=' exp {updateSymbolVal(,);}
;
exp : term {$$ = ;}
| exp '+' term {$$ = + ;}
| exp '-' term {$$ = - ;}
;
term : number {$$ = ;}
| identifier {$$ = symbolVal();}
;
condition : identifier cond_op identifier {$$ = ;}
|identifier cond_op number {$$ = ;}
;
cond_op : lt
| gt
;
%%
int computeSymbolIndex(char token){
int idx = -1;
if(islower(token)){
idx = token - 'a' +26;
}
else if(isupper(token)){
idx = token - 'A' + 26;
}
return idx;
}
int symbolVal(char symbol){
int bucket = computeSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol, int val){
int bucket = computeSymbolIndex(symbol);
symbols[bucket] = val;
}
int main(void){
int i;
for(i=0;i<52;i++){
symbols[i] = 0;
}
return yyparse();
}
void yyerror (char *s){fprintf (stderr, "%s\n",s);}
我的 Lex 代码:
%{
#include "y.tab.h"
%}
%%
"while" {printf("while\n"); return WHILE;}
"exit" {return exit_command;}
[a-zA-Z] {yylval.id = yytext[0]; return identifier;}
[0-9]+ {yylval.num = atoi(yytext); return number;}
"<" {return lt;}
">" {return gt;}
[ \t\n] ;
[-+=;] {return yytext[0];}
. ;
%%
int yywrap (void)
{
return 1;
}
显示语法错误的示例文本:
while(i>0){i = i-1}
“while”按照 lex 打印,但下一行输出是“Syntax Error”。
甚至连“while 循环条件变量”都没有打印出来。
语法错误尤其是while循环。
条件语句赋值等所有其他事情似乎工作正常。
为什么会这样?
您有一个词法分析器后备规则,它会自动丢弃无法识别的字符:
. ;
正如您刚刚发现的那样,这确实不是一个好主意。在这种情况下,没有其他规则识别 (
或 )
,因此它们被上述规则忽略。但是,您的解析器需要一个括号。它没有得到一个,所以它报告一个语法错误。
更好的是以下后备规则,它可以替代前面的规则:
/* [-+=;] {return yytext[0];} */ /* now redundant*/
. {return yytext[0];}
这接受词法分析器中的任何字符。但是,大多数字符在语法中的任何地方都不会用作字符文字,因此它们将被解析器视为无效标记,从而导致语法错误。
您可以通过在您的 lex 后备规则中写入错误来获得更准确的错误消息,但是您需要确保识别所有 vslid 字符:
[-+=;(){}] {return yytext[0];}
. {return yytext[0];}
就个人而言,我会将 <>
添加到该列表中,而不是使用专门的规则(和不必要的标记名称。)
我的 yacc 解析器显示语法错误,即使语法符合语法。 我的 Yacc 代码:
%{
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int symbols[100];
int yylex();
int symbolVal(char symbol);
void updateSymbolVal(char symbol,int val);
%}
%union {int num; char id;}
%start line
%token WHILE
%token lt
%token gt
%token exit_command
%token <num> number
%token <id> identifier
%type <num> line exp term
%type <id> assignment
%type <num> condition
%%
line: assignment {;}
|line assignment {;}
|exit_command {exit(EXIT_SUCCESS);}
|line exit_command {exit(EXIT_SUCCESS);}
|whileLoop {;}
|condition {;}
;
whileLoop: WHILE '(' condition ')' '{' assignment '}' {printf("while loop condition var:%d\n",);}
;
assignment : identifier '=' exp {updateSymbolVal(,);}
;
exp : term {$$ = ;}
| exp '+' term {$$ = + ;}
| exp '-' term {$$ = - ;}
;
term : number {$$ = ;}
| identifier {$$ = symbolVal();}
;
condition : identifier cond_op identifier {$$ = ;}
|identifier cond_op number {$$ = ;}
;
cond_op : lt
| gt
;
%%
int computeSymbolIndex(char token){
int idx = -1;
if(islower(token)){
idx = token - 'a' +26;
}
else if(isupper(token)){
idx = token - 'A' + 26;
}
return idx;
}
int symbolVal(char symbol){
int bucket = computeSymbolIndex(symbol);
return symbols[bucket];
}
void updateSymbolVal(char symbol, int val){
int bucket = computeSymbolIndex(symbol);
symbols[bucket] = val;
}
int main(void){
int i;
for(i=0;i<52;i++){
symbols[i] = 0;
}
return yyparse();
}
void yyerror (char *s){fprintf (stderr, "%s\n",s);}
我的 Lex 代码:
%{
#include "y.tab.h"
%}
%%
"while" {printf("while\n"); return WHILE;}
"exit" {return exit_command;}
[a-zA-Z] {yylval.id = yytext[0]; return identifier;}
[0-9]+ {yylval.num = atoi(yytext); return number;}
"<" {return lt;}
">" {return gt;}
[ \t\n] ;
[-+=;] {return yytext[0];}
. ;
%%
int yywrap (void)
{
return 1;
}
显示语法错误的示例文本:
while(i>0){i = i-1}
“while”按照 lex 打印,但下一行输出是“Syntax Error”。
甚至连“while 循环条件变量”都没有打印出来。
语法错误尤其是while循环。
条件语句赋值等所有其他事情似乎工作正常。
为什么会这样?
您有一个词法分析器后备规则,它会自动丢弃无法识别的字符:
. ;
正如您刚刚发现的那样,这确实不是一个好主意。在这种情况下,没有其他规则识别 (
或 )
,因此它们被上述规则忽略。但是,您的解析器需要一个括号。它没有得到一个,所以它报告一个语法错误。
更好的是以下后备规则,它可以替代前面的规则:
/* [-+=;] {return yytext[0];} */ /* now redundant*/
. {return yytext[0];}
这接受词法分析器中的任何字符。但是,大多数字符在语法中的任何地方都不会用作字符文字,因此它们将被解析器视为无效标记,从而导致语法错误。
您可以通过在您的 lex 后备规则中写入错误来获得更准确的错误消息,但是您需要确保识别所有 vslid 字符:
[-+=;(){}] {return yytext[0];}
. {return yytext[0];}
就个人而言,我会将 <>
添加到该列表中,而不是使用专门的规则(和不必要的标记名称。)