Compiler construction 查找Flex Yacc中发生语法错误的位置
我对莱克斯和亚克还很陌生 我正在设计一个编译器,它可以生成三个地址代码 如何在代码中找到语法错误发生的位置 进入后:Compiler construction 查找Flex Yacc中发生语法错误的位置,compiler-construction,bison,yacc,lex,Compiler Construction,Bison,Yacc,Lex,我对莱克斯和亚克还很陌生 我正在设计一个编译器,它可以生成三个地址代码 如何在代码中找到语法错误发生的位置 进入后: 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 yy
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);
}
%{
#包括“y.tab.h”
#包括
int yyerror(字符*错误消息);
%}
字母[a-zA-z]
数字[0-9]
id{letter}({letter}{digit})*
ws[\t]
%%
{ws};
\{{return 300;}
\}{返回301;}
\; {返回分号;}
“if”{返回if;}
“int”{return int;}
“float”{返回float;}
“char”{return char;}
\={返回赋值;}
{id}{strcpy(yylval.str,yytext);返回id;}
{digit}+{yylval.ival=atoi(yytext);返回编号;}
. {yyerror(“无效命令”);}
%%
内部主(空)
{
yyparse();
printf(“完成”);
返回0;
}
int-yywrap(无效)
{
返回0;
}
int yyerror(字符*错误消息)
{
fprintf(stderr,“嘿!%s\n”,errormsg);
出口(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
;
%{
#包括
#包括
#包括
int yylex(无效);
int yyerror(常量字符*s);
%}
%并集{int ival;双dval;字符str[120];}
%标记INT如果分号指定数字
%代币浮动
%令牌ID字符
%%
节目:
块
;
区块:
“{'Stmts'}”
;
STMT:
Stmts Stmt
|Stmt
;
Stmt:
块
|IfStmt
|转让STMT
|十二月
;
IfStmt:
如果“('Expr')”Stmt{printf(“如果找到”);}
;
转让STMT:
类型ID分配Expr分号{printf(“int found!”);}
;
十二月
类型ID分号
;
类型:
国际的
|浮动
|煤焦
;
表达式:
数
;
通过使用-DYYDEBUG=1'
进行编译,您可以让bison输出它正在做的事情:
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
注意,语法分析器无法识别lexer返回的第一个标记
对于{
,您将返回300
,但解析器需要{'
,因此只需修复lexer规则:
//WRONG
\{ { return 300; }
\} { return 301; }
到
然后,您将得到一个完成的解析,尽管它挂起了
挂起是由您在
yywrap
中返回0
引起的。将其更改为1
将删除它。当您试图找出Bison的语法错误时,要做的第一件事是将%define parse.error verbose
选项添加到Bison文件中。这将把错误消息更改为更详细的内容elpful不仅仅是“语法错误”。请注意,这是Bison特有的功能,因此在调用Bison时需要删除-y
标志。执行此操作时,错误消息将更改为:
syntax error, unexpected $undefined, expecting '{'
所以它告诉你它得到了一个$undefined
,而它期望得到一个{
。那么$undefined
是什么呢?这是Bison如何显示任何它不知道名称的令牌。如果令牌是ASCII中的整数,它将显示为'x'
(这里不是x
,而是给定的ASCII字符)。如果已使用%token
定义了令牌,则它将显示为与该%token
声明关联的名称。只有在两者都不存在的情况下,才会获得$undefined
因此,您的lexer返回的内容既不是ASCII字符,也不是已定义的标记。因此,让我们看看您的lexer是否有类似的内容,并确信:
\{ { return 300; }
\} { return 301; }
当你的lexer看到大括号时,它将分别返回300或301。它们既不是字符,也不是使用%token
定义的标记,因此它们对Bison来说毫无意义
因为您的解析器希望看到'{'
和'}'
,所以上面应该分别说返回'{';
和返回'}';
(或者返回yytext[0];
,如果您愿意的话,在这两种情况下都是如此)。或者您可以在解析器中定义%LBRACE RBRACE
,使用它们代替'{'
和'}'
在块
规则中,并在lexer中返回它们。无论哪种方式,都不应该在lexer中返回任意整数
您还需要在
yywrap
中返回1而不是0,或者使用noyywrap
选项将其完全删除。返回0会使lexer在到达文件末尾后等待进一步输入。语法错误是什么?请在帖子中写下语法错误是“语法错误”.这正是Bison使用默认选项时出现的语法错误。
\{ { return 300; }
\} { return 301; }