查找 Flex Yacc 中发生语法错误的位置
Find Where Syntax Error in Flex Yacc Happened
我对 lex 和 yacc 还很陌生。
我正在设计一个可以生成三地址代码的编译器。
如何找到代码中发生语法错误的位置?
进入后:
flex lexer.l
bison -dy parser.y
gcc lex.yy.c y.tab.c -o program.exe
我试试这个输入:
{ int abc = 234 ; }
然后它给我语法错误!
我该如何解决?
这是我的词法分析器
lexer.l:
%{
#include "y.tab.h"
#include <string.h>
int yyerror(char *errormsg);
%}
letter [a-zA-z]
digit [0-9]
id {letter}({letter}|{digit})*
ws [ \t]
%%
{ws} ;
\{ { return 300; }
\} { return 301; }
\; { return SEMICOLON; }
"if" { return IF; }
"int" { return INT; }
"float" { return FLOAT; }
"char" { return CHAR; }
\= { return ASSIGN; }
{id} {strcpy(yylval.str,yytext) ; return ID; }
{digit}+ {yylval.ival=atoi(yytext); return NUMBER; }
. {yyerror("Invalid Command");}
%%
int main(void)
{
yyparse();
printf("DONE");
return 0;
}
int yywrap(void)
{
return 0;
}
int yyerror(char *errormsg)
{
fprintf(stderr, "hey!%s\n", errormsg);
exit(1);
}
这是我的解析器
parser.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int yylex(void);
int yyerror(const char *s);
%}
%union{int ival; double dval; char str[120]; }
%token INT ASSIGN NUMBER IF SEMICOLON
%token FLOAT
%token ID CHAR
%%
Program:
Block
;
Block:
'{' Stmts '}'
;
Stmts:
Stmts Stmt
| Stmt
;
Stmt:
Block
|IfStmt
|AssignStmt
|DeclStmt
;
IfStmt:
IF '(' Expr ')' Stmt { printf("if found"); }
;
AssignStmt:
Type ID ASSIGN Expr SEMICOLON { printf("int found!"); }
;
DeclStmt:
Type ID SEMICOLON
;
Type:
INT
|FLOAT
|CHAR
;
Expr:
NUMBER
;
你可以通过-DYYDEBUG=1'
:
编译让野牛输出它正在做的事情
gcc -DYYDEBUG=1 lex.yy.c y.tab.c -o program.exe
然后 运行 将 yydebug
全局变量设置为真值:
int main(void)
{
#ifdef YYDEBUG
yydebug = 1;
#endif
yyparse();
printf("DONE");
return 0;
}
为您的项目执行此操作,产量
Starting parse
Entering state 0
Reading a token: Next token is token $undefined ()
hey!syntax error
IOW,词法分析器返回的第一个标记无法被解析器识别。
您为 {
返回 300
,但解析器期望 '{'
,因此只需修复词法分析器规则:
//WRONG
\{ { return 300; }
\} { return 301; }
至
//OK
\{ { return '{'; }
\} { return '}'; }
然后你得到一个完成的解析,尽管它挂起。
挂起是由您在 yywrap
中返回 0
引起的。将其更改为 1
将删除它。
在尝试找出 Bison 的语法错误时,您要做的第一件事是将 %define parse.error verbose
选项添加到您的 Bison 文件中。这会将错误消息更改为比“语法错误”更有帮助的内容。请注意,这是 Bison 特有的功能,因此您需要在调用 Bison 时删除 -y
标志。这样做,错误消息将更改为:
syntax error, unexpected $undefined, expecting '{'
所以它告诉你它得到了一个 $undefined
而它期望 {
。那么什么是 $undefined
?这就是 Bison 显示它不知道其名称的任何令牌的方式。如果令牌是 ASCII 中的整数,它将显示为 'x'
(而不是 x
,它将是给定的 ASCII 字符)。如果令牌已使用 %token
定义,它将显示为与该 %token
声明关联的名称。只有当两者都不是时,你才会得到 $undefined
.
因此您的词法分析器 return 既不是 ASCII 字符也不是定义的标记。所以让我们看看你的词法分析器是否有类似的东西,果然:
\{ { return 300; }
\} { return 301; }
当你的词法分析器看到大括号时,它会分别 return 300 或 301。这些既不是字符也不是使用 %token
定义的标记,因此它们对 Bison 没有任何意义。
因为你的解析器希望看到 '{'
和 '}'
,上面应该分别说 return '{';
和 return '}';
(或者 return yytext[0];
在这两种情况下,如果你比较喜欢)。或者,您可以在解析器中定义 %token LBRACE RBRACE
,在 Block
规则中使用它们代替 '{'
和 '}'
,在词法分析器中使用 return。无论哪种方式,你绝对不应该 return 词法分析器中的任意整数。
您还需要 return 1 而不是 yywrap
中的 0 或使用 noyywrap
选项完全删除它。返回 0 会使词法分析器在到达文件末尾后等待进一步的输入。
我对 lex 和 yacc 还很陌生。
我正在设计一个可以生成三地址代码的编译器。
如何找到代码中发生语法错误的位置?
进入后:
flex lexer.l
bison -dy parser.y
gcc lex.yy.c y.tab.c -o program.exe
我试试这个输入:
{ int abc = 234 ; }
然后它给我语法错误!
我该如何解决?
这是我的词法分析器
lexer.l:
%{
#include "y.tab.h"
#include <string.h>
int yyerror(char *errormsg);
%}
letter [a-zA-z]
digit [0-9]
id {letter}({letter}|{digit})*
ws [ \t]
%%
{ws} ;
\{ { return 300; }
\} { return 301; }
\; { return SEMICOLON; }
"if" { return IF; }
"int" { return INT; }
"float" { return FLOAT; }
"char" { return CHAR; }
\= { return ASSIGN; }
{id} {strcpy(yylval.str,yytext) ; return ID; }
{digit}+ {yylval.ival=atoi(yytext); return NUMBER; }
. {yyerror("Invalid Command");}
%%
int main(void)
{
yyparse();
printf("DONE");
return 0;
}
int yywrap(void)
{
return 0;
}
int yyerror(char *errormsg)
{
fprintf(stderr, "hey!%s\n", errormsg);
exit(1);
}
这是我的解析器
parser.y:
%{
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int yylex(void);
int yyerror(const char *s);
%}
%union{int ival; double dval; char str[120]; }
%token INT ASSIGN NUMBER IF SEMICOLON
%token FLOAT
%token ID CHAR
%%
Program:
Block
;
Block:
'{' Stmts '}'
;
Stmts:
Stmts Stmt
| Stmt
;
Stmt:
Block
|IfStmt
|AssignStmt
|DeclStmt
;
IfStmt:
IF '(' Expr ')' Stmt { printf("if found"); }
;
AssignStmt:
Type ID ASSIGN Expr SEMICOLON { printf("int found!"); }
;
DeclStmt:
Type ID SEMICOLON
;
Type:
INT
|FLOAT
|CHAR
;
Expr:
NUMBER
;
你可以通过-DYYDEBUG=1'
:
gcc -DYYDEBUG=1 lex.yy.c y.tab.c -o program.exe
然后 运行 将 yydebug
全局变量设置为真值:
int main(void)
{
#ifdef YYDEBUG
yydebug = 1;
#endif
yyparse();
printf("DONE");
return 0;
}
为您的项目执行此操作,产量
Starting parse
Entering state 0
Reading a token: Next token is token $undefined ()
hey!syntax error
IOW,词法分析器返回的第一个标记无法被解析器识别。
您为 {
返回 300
,但解析器期望 '{'
,因此只需修复词法分析器规则:
//WRONG
\{ { return 300; }
\} { return 301; }
至
//OK
\{ { return '{'; }
\} { return '}'; }
然后你得到一个完成的解析,尽管它挂起。
挂起是由您在 yywrap
中返回 0
引起的。将其更改为 1
将删除它。
在尝试找出 Bison 的语法错误时,您要做的第一件事是将 %define parse.error verbose
选项添加到您的 Bison 文件中。这会将错误消息更改为比“语法错误”更有帮助的内容。请注意,这是 Bison 特有的功能,因此您需要在调用 Bison 时删除 -y
标志。这样做,错误消息将更改为:
syntax error, unexpected $undefined, expecting '{'
所以它告诉你它得到了一个 $undefined
而它期望 {
。那么什么是 $undefined
?这就是 Bison 显示它不知道其名称的任何令牌的方式。如果令牌是 ASCII 中的整数,它将显示为 'x'
(而不是 x
,它将是给定的 ASCII 字符)。如果令牌已使用 %token
定义,它将显示为与该 %token
声明关联的名称。只有当两者都不是时,你才会得到 $undefined
.
因此您的词法分析器 return 既不是 ASCII 字符也不是定义的标记。所以让我们看看你的词法分析器是否有类似的东西,果然:
\{ { return 300; }
\} { return 301; }
当你的词法分析器看到大括号时,它会分别 return 300 或 301。这些既不是字符也不是使用 %token
定义的标记,因此它们对 Bison 没有任何意义。
因为你的解析器希望看到 '{'
和 '}'
,上面应该分别说 return '{';
和 return '}';
(或者 return yytext[0];
在这两种情况下,如果你比较喜欢)。或者,您可以在解析器中定义 %token LBRACE RBRACE
,在 Block
规则中使用它们代替 '{'
和 '}'
,在词法分析器中使用 return。无论哪种方式,你绝对不应该 return 词法分析器中的任意整数。
您还需要 return 1 而不是 yywrap
中的 0 或使用 noyywrap
选项完全删除它。返回 0 会使词法分析器在到达文件末尾后等待进一步的输入。