Bison 解析器总是打印 "syntax error"
Bison parser always prints "syntax error"
我正在尝试构建一个 3 地址代码生成器,它将生成:
input:x=a+3*(b/7)
output: t1=b/7
t2=3*t1
t3=a+t2
x=t3
无论我输入什么,输出都是"syntax error"。
我正在使用 Windows 10.
Yacc 代码:
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define YYDEBUG 1
int yylex(void);
int t_count = 1;
void yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
return;
}
char * generateToken(int i)
{
char* ch=(char*)malloc(sizeof(char)*5);
sprintf(ch,"t%d",i++);
return ch;
}
%}
%union { double dval; char ivar[50]; }
%token <ivar> NUMBER
%token <ivar> NAME
%type <ivar> expr
%type <ivar> term
%left '+' '-'
%left '*' '/'
%left '(' ')'
%right '='
%%
program:
line {
}
| program line {
}
;
line:
expr '\n' {
t_count =1;
}
| NAME '=' expr '\n' {
printf("%s = %s", ,);
t_count=1;
}
;
expr:
expr '+' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s + %s",$$,,);
}
| expr '-' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s - %s",$$,,);
}
| expr '*' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s * %s",$$,,);
}
| expr '/' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s / %s",$$,,);
}
| term {
strcpy($$, );
}
| '(' expr ')' {
strcpy($$,generateToken(t_count));
printf("%s =( %s )" ,$$,);
}
;
term:
NAME {
strcpy($$, );
}
| NUMBER {
strcpy($$, );
}
;
%%
int main(void)
{
if (getenv("YYDEBUG")) yydebug = 1;
yyparse();
return 0;
}
莱克斯代码:
%option noyywrap
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "threeAdd.tab.h"
void yyerror(char*);
extern YYSTYPE yylval;
%}
NAME [a-zA-Z]
DIGIT [0-9]+
NUMBER [-]?{DIGIT}+(\.{DIGIT}+)?
%%
[ \t]+ { }
{NUMBER}
{
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"+" {
return *yytext;
}
"-" {
return *yytext;
}
"*" {
return *yytext;
}
"/" {
return *yytext;
}
"=" {
return *yytext;
}
"(" {
return *yytext;
}
")" {
return *yytext;
}
{NAME} {
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"\n" {
return *yytext;
}
exit {
return 0;
}
. {
char msg[25];
sprintf(msg," <%s>","invalid character",yytext);
yyerror(msg);
}
%%
示例构建 & 运行:
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>弹性 file.l
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>bison -d file.y
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>gcc lex.yy.c file.tab.c -o ICG.exe
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>ICG.exe
3+9
syntax error
基本问题是您在 yacc 文件中对标记使用双引号("
-- 字符串)(没有为它们定义任何代码,因此它们没有用),并且 returning lex 文件中的单个字符标记。因此,none 个标记将在您的解析器中被识别。
将 yacc 文件中所有单字符标记上的所有 "
字符替换为 '
字符(因此 "+"
变为 '+'
和 "\n"
变成 '\n'
).
一旦你解决了这个问题,你就会遇到另一个问题:你的 {DIGITS}+
和 {NAME}
的 lex 规则没有 return 一个标记,所以这个标记将被忽略(导致语法错误)
对于调试一般的解析器问题,通常值得在调用 yyparse 之前使用 -DYYDEBUG
进行编译并将 yydebug = 1;
粘贴到 main 中,这将导致解析器打印所见标记的踪迹和状态访问过。我经常放
if (getenv("YYDEBUG")) yydebug = 1;
进入 main 并把它留在那里——这样通常不会启用调试,但是如果你在 运行 你的程序之前设置环境变量 YYDEBUG=1
,你会看到调试跟踪(无需重新编译)
为了 return 一个标记,你的词法分析器规则需要 return
这个标记。所以 NUMBER
的词法分析器规则应该是:
{NUMBER} {
strcpy(yylval.ivar,yytext);
return NUMBER;
}
与 NAME
类似。请注意,代码块的开头 {
必须与模式在同一行——如果它在不同的行,则不会与模式相关联。
我正在尝试构建一个 3 地址代码生成器,它将生成:
input:x=a+3*(b/7)
output: t1=b/7
t2=3*t1
t3=a+t2
x=t3
无论我输入什么,输出都是"syntax error"。
我正在使用 Windows 10.
Yacc 代码:
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define YYDEBUG 1
int yylex(void);
int t_count = 1;
void yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
return;
}
char * generateToken(int i)
{
char* ch=(char*)malloc(sizeof(char)*5);
sprintf(ch,"t%d",i++);
return ch;
}
%}
%union { double dval; char ivar[50]; }
%token <ivar> NUMBER
%token <ivar> NAME
%type <ivar> expr
%type <ivar> term
%left '+' '-'
%left '*' '/'
%left '(' ')'
%right '='
%%
program:
line {
}
| program line {
}
;
line:
expr '\n' {
t_count =1;
}
| NAME '=' expr '\n' {
printf("%s = %s", ,);
t_count=1;
}
;
expr:
expr '+' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s + %s",$$,,);
}
| expr '-' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s - %s",$$,,);
}
| expr '*' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s * %s",$$,,);
}
| expr '/' expr {
strcpy($$,generateToken(t_count));
printf("%s = %s / %s",$$,,);
}
| term {
strcpy($$, );
}
| '(' expr ')' {
strcpy($$,generateToken(t_count));
printf("%s =( %s )" ,$$,);
}
;
term:
NAME {
strcpy($$, );
}
| NUMBER {
strcpy($$, );
}
;
%%
int main(void)
{
if (getenv("YYDEBUG")) yydebug = 1;
yyparse();
return 0;
}
莱克斯代码:
%option noyywrap
%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "threeAdd.tab.h"
void yyerror(char*);
extern YYSTYPE yylval;
%}
NAME [a-zA-Z]
DIGIT [0-9]+
NUMBER [-]?{DIGIT}+(\.{DIGIT}+)?
%%
[ \t]+ { }
{NUMBER}
{
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"+" {
return *yytext;
}
"-" {
return *yytext;
}
"*" {
return *yytext;
}
"/" {
return *yytext;
}
"=" {
return *yytext;
}
"(" {
return *yytext;
}
")" {
return *yytext;
}
{NAME} {
strcpy(yylval.ivar,yytext);
return *yylval.ivar;
}
"\n" {
return *yytext;
}
exit {
return 0;
}
. {
char msg[25];
sprintf(msg," <%s>","invalid character",yytext);
yyerror(msg);
}
%%
示例构建 & 运行:
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>弹性 file.l
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>bison -d file.y
C:\Users\USER\OneDrive\Desktop\Compiler\ICG>gcc lex.yy.c file.tab.c -o ICG.exe C:\Users\USER\OneDrive\Desktop\Compiler\ICG>ICG.exe 3+9syntax error
基本问题是您在 yacc 文件中对标记使用双引号("
-- 字符串)(没有为它们定义任何代码,因此它们没有用),并且 returning lex 文件中的单个字符标记。因此,none 个标记将在您的解析器中被识别。
将 yacc 文件中所有单字符标记上的所有 "
字符替换为 '
字符(因此 "+"
变为 '+'
和 "\n"
变成 '\n'
).
一旦你解决了这个问题,你就会遇到另一个问题:你的 {DIGITS}+
和 {NAME}
的 lex 规则没有 return 一个标记,所以这个标记将被忽略(导致语法错误)
对于调试一般的解析器问题,通常值得在调用 yyparse 之前使用 -DYYDEBUG
进行编译并将 yydebug = 1;
粘贴到 main 中,这将导致解析器打印所见标记的踪迹和状态访问过。我经常放
if (getenv("YYDEBUG")) yydebug = 1;
进入 main 并把它留在那里——这样通常不会启用调试,但是如果你在 运行 你的程序之前设置环境变量 YYDEBUG=1
,你会看到调试跟踪(无需重新编译)
为了 return 一个标记,你的词法分析器规则需要 return
这个标记。所以 NUMBER
的词法分析器规则应该是:
{NUMBER} {
strcpy(yylval.ivar,yytext);
return NUMBER;
}
与 NAME
类似。请注意,代码块的开头 {
必须与模式在同一行——如果它在不同的行,则不会与模式相关联。