Parsing can';在使用YACC解析时,找不到简单的错误
我试图在Pascal语言上创建一个非常简单的YACC解析器,它只包含整数声明、一些基本表达式和if-else语句。然而,我几个小时都找不到错误,我很快就会发疯的。终端在第0行显示Parsing can';在使用YACC解析时,找不到简单的错误,parsing,pascal,yacc,lex,parser-generator,Parsing,Pascal,Yacc,Lex,Parser Generator,我试图在Pascal语言上创建一个非常简单的YACC解析器,它只包含整数声明、一些基本表达式和if-else语句。然而,我几个小时都找不到错误,我很快就会发疯的。终端在第0行显示错误,但这是不可能的!。我使用flex和byacc作为解析器。如果您能帮助我,我将非常高兴。这是我的lex文件,你可以看到 %{ #include <stdio.h> #include <string.h> #include "y.tab.h" extern int yylval; int lin
错误,但这是不可能的!。我使用flex和byacc作为解析器。如果您能帮助我,我将非常高兴。这是我的lex文件,你可以看到
%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern int yylval;
int linenum=0;
%}
digit [0-9]
letter [A-Za-z]
%%
if return IF;
then return THEN;
else return ELSE;
for return FOR;
while return WHILE;
PROGRAM return PROGRAM_SYM;
BEGIN return BEGIN_SYM;
VAR return VAR_SYM;
END return END_SYM;
INTEGER return INTEGER_SYM;
{letter}({letter}|{digit})* return identifier;
[0-9]+ return NUMBER;
[\<][\=] return CON_LE;
[\>][\=] return CON_GE;
[\=] return CON_EQ;
[\:][\=] return ASSIGNOP;
; return semiColon;
, return comma;
\n {linenum++;}
. return (int) yytext[0];
%%
词法分析器返回空格和制表符作为标记,但语法无法识别它们
添加解析器规则:
[ \t\r] { }
这将使您在遇到错误之前进入第6行而不是第0行。出现该错误是因为在声明之间不允许使用分号:
dec_block:
dec_list semiColon;
dec_list:
dec_list dec
|
dec
;
dec:
int_dec_list
;
这可能是:
dec_block:
dec_block dec
|
dec
;
dec:
int_dec_list semiColon
;
这样做会使您到达输入中的第14行
顺便说一句,我做的第一件事是通过修改如下规则,确保词法分析器告诉我它在做什么:
if { printf("IF\n"); return IF; }
在长期代码中,我会在运行时选择该诊断输出
您在期望分号的位置有一个一般性问题。您是否应该在语句
的规则中允许一个表达式列表
(或者,可能是“尚未”-当您有函数调用时,这可能是合适的,但允许3+2/4
作为“语句”并没有多大帮助)
此语法到达输入的末尾:
%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern FILE *yyin;
extern int linenum;
%}
%token PROGRAM_SYM VAR_SYM BEGIN_SYM END_SYM INTEGER_SYM NUMBER
%token identifier INTEGER ASSIGNOP semiColon comma THEN
%token IF ELSE FOR WHILE
%token CON_EQ CON_LE CON_GE GE LE
%left '*' '/'
%left '+' '-'
%start program
%%
program: PROGRAM_SYM identifier semiColon VAR_SYM dec_block BEGIN_SYM statement_list END_SYM '.'
;
dec_block:
dec_block dec
|
dec
;
dec:
int_dec_list semiColon
;
int_dec_list:
int_dec_list int_dec ':' type
|
int_dec ':' type
;
int_dec:
int_dec comma identifier
|
identifier
;
type:
INTEGER_SYM
;
statement_list:
statement_list statement
|
statement
;
statement:
assignment
|
selection
;
assignment:
identifier ASSIGNOP expression semiColon
;
expression:
'(' expression ')'
|
expression '*' expression
|
expression '/' expression
|
expression '+' expression
|
expression '-' expression
|
factor
;
factor:
identifier
|
NUMBER
;
selection:
IF '(' logical_expression ')' THEN statement_list ELSE statement_list
;
logical_expression:
expression '=' expression
|
expression '>' expression
|
expression '<' expression
;
%%
void yyerror(char *s){
fprintf(stderr,"Error at line: %d\n",linenum);
}
int yywrap(){
return 1;
}
int main(int argc, char *argv[])
{
/* Call the lexer, then quit. */
yyin=fopen(argv[1],"r");
yyparse();
fclose(yyin);
return 0;
}
%{
#包括
#包括
#包括“y.tab.h”
外部文件*yyin;
外部内部行数;
%}
%令牌程序\符号变量\符号开始\符号结束\符号整数\符号编号
%令牌标识符整数赋值分号逗号然后
%如果暂时还需要令牌
%令牌CON_EQ CON_LE CON_GE LE
%左'*''/'
%左'+''-'
%启动程序
%%
程序:程序\u SYM标识符分号VAR\u SYM dec\u块开始\u SYM语句\u列表结束\u SYM''
;
dec_区块:
十二月十日
|
12月
;
12月:
int_dec_列表分号
;
int_dec_列表:
int_dec_list int_dec':'类型
|
int_dec':'类型
;
国际12月:
int_dec逗号标识符
|
标识符
;
类型:
整数符号
;
报表清单:
语句列表语句
|
陈述
;
声明:
分配
|
选择
;
任务:
标识符赋值表达式分号
;
表达方式:
“(“表达式”)”
|
表达式“*”表达式
|
表达式“/”表达式
|
表达式“+”表达式
|
表达式'-'表达式
|
因素
;
因素:
标识符
|
数
;
选择:
如果是“(“逻辑表达式”),则语句列表为ELSE语句列表
;
逻辑表达式:
表达式“=”表达式
|
表达式“>”表达式
|
表达式“您的词法分析器返回空格和制表符作为标记,但语法无法识别它们
添加解析器规则:
[ \t\r] { }
这将使您在遇到错误之前进入第6行而不是第0行。出现该错误是因为在声明之间不允许使用分号:
dec_block:
dec_list semiColon;
dec_list:
dec_list dec
|
dec
;
dec:
int_dec_list
;
这可能是:
dec_block:
dec_block dec
|
dec
;
dec:
int_dec_list semiColon
;
这样做会使您到达输入中的第14行
顺便说一句,我做的第一件事是通过修改如下规则,确保词法分析器告诉我它在做什么:
if { printf("IF\n"); return IF; }
在长期代码中,我会在运行时选择该诊断输出
您在期望分号的位置有一个一般性问题。您是否应该在语句
的规则中允许一个表达式列表
(或者,可能是“尚未”-当您有函数调用时,这可能是合适的,但允许3+2/4
作为“语句”并没有多大帮助)
此语法到达输入的末尾:
%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern FILE *yyin;
extern int linenum;
%}
%token PROGRAM_SYM VAR_SYM BEGIN_SYM END_SYM INTEGER_SYM NUMBER
%token identifier INTEGER ASSIGNOP semiColon comma THEN
%token IF ELSE FOR WHILE
%token CON_EQ CON_LE CON_GE GE LE
%left '*' '/'
%left '+' '-'
%start program
%%
program: PROGRAM_SYM identifier semiColon VAR_SYM dec_block BEGIN_SYM statement_list END_SYM '.'
;
dec_block:
dec_block dec
|
dec
;
dec:
int_dec_list semiColon
;
int_dec_list:
int_dec_list int_dec ':' type
|
int_dec ':' type
;
int_dec:
int_dec comma identifier
|
identifier
;
type:
INTEGER_SYM
;
statement_list:
statement_list statement
|
statement
;
statement:
assignment
|
selection
;
assignment:
identifier ASSIGNOP expression semiColon
;
expression:
'(' expression ')'
|
expression '*' expression
|
expression '/' expression
|
expression '+' expression
|
expression '-' expression
|
factor
;
factor:
identifier
|
NUMBER
;
selection:
IF '(' logical_expression ')' THEN statement_list ELSE statement_list
;
logical_expression:
expression '=' expression
|
expression '>' expression
|
expression '<' expression
;
%%
void yyerror(char *s){
fprintf(stderr,"Error at line: %d\n",linenum);
}
int yywrap(){
return 1;
}
int main(int argc, char *argv[])
{
/* Call the lexer, then quit. */
yyin=fopen(argv[1],"r");
yyparse();
fclose(yyin);
return 0;
}
%{
#包括
#包括
#包括“y.tab.h”
外部文件*yyin;
外部内部行数;
%}
%令牌程序\符号变量\符号开始\符号结束\符号整数\符号编号
%令牌标识符整数赋值分号逗号然后
%如果暂时还需要令牌
%令牌CON_EQ CON_LE CON_GE LE
%左'*''/'
%左'+''-'
%启动程序
%%
程序:程序\u SYM标识符分号VAR\u SYM dec\u块开始\u SYM语句\u列表结束\u SYM''
;
dec_区块:
十二月十日
|
12月
;
12月:
int_dec_列表分号
;
int_dec_列表:
int_dec_list int_dec':'类型
|
int_dec':'类型
;
国际12月:
int_dec逗号标识符
|
标识符
;
类型:
整数符号
;
报表清单:
语句列表语句
|
陈述
;
声明:
分配
|
选择
;
任务:
标识符赋值表达式分号
;
表达方式:
“(“表达式”)”
|
表达式“*”表达式
|
表达式“/”表达式
|
表达式“+”表达式
|
表达式'-'表达式
|
因素
;
因素:
标识符
|
数
;
选择:
如果是“(“逻辑表达式”),则语句列表为ELSE语句列表
;
逻辑表达式:
表达式“=”表达式
|
表达式“>”表达式
|
表达式“对于调试语法,YYDEBUG是您的朋友。要么在.y文件顶部的%{
.%}
中粘贴#定义YYDEBUG 1
,要么使用-DYYDEBUG
编译,并粘贴YYDEBUG=1在调用yyparse
之前,在main
中的code>中,您将获得一系列关于解析器看到的标记以及它正在使用这些标记做什么的信息……对于调试语法,YYDEBUG是您的朋友。在%{
中,选择粘贴#定义YYDEBUG 1
。