在 Bison 中找不到 'syntax error' 消息的原因
Cannot find cause of 'syntax error' message in Bison
我正在尝试创建一个简单的 parser/compiler,主要用于家庭作业,但最终也用于学习和娱乐。我已经编写了词法分析器和解析器文件(用于命令的初始子集)并且我想输出一个 AST。但是,即使我试图解析一个简单的“1+1”,我仍然卡在 "syntax error" 消息中。这是词法分析器文件:
%{
#include "parser.tab.h"
%}
DIGIT [0-9]
LETTER [a-zA-Z]
%%
[ \t\n] ;
{DIGIT}+ {yylval = atoi(yytext); return NUMBER;}
{LETTER}* { if (strlen(yytext) <= 8){
printf( "<ID, %s> ", yytext );
} else {
yytext[8] = '[=11=]';
printf("WARNING! Long identifier. Truncating to 8 chars\n");
printf( "<ID, %s> ", yytext );
}
}
"+" {printf("Found '+' symbol\n");return(PLUS);}
"-" return(MINUS);
"*" return(TIMES);
"/" return(DIVIDE);
"(" return(LEFT_PARENTHESIS);
")" return(RIGHT_PARENTHESIS);
<<EOF>> return(END_OF_FILE);
%%
int yywrap (void) {return 1;}
这是解析器文件:
%{
#include <stdio.h>
/*#include "tree.h"
#include "treedefs.h"*/
int yylex();
#define YYSTYPE int
%}
%start program
%token NUMBER
%token ID
%token PLUS MINUS TIMES EQUAL
%token LEFT_PARENTHESIS RIGHT_PARENTHESIS
%token LET IN AND
%token END_OF_FILE
%left PLUS MINUS
%left TIMES DIVIDE
%%
program: /* empty */
| exp { printf("Result: %d\n", ); }
| END_OF_FILE {printf("Encountered EOF\n");}
;
exp: NUMBER { $$ = ;}
| exp PLUS exp { $$ = + ; }
| exp TIMES exp { $$ = * ; }
| '(' exp ')' { $$ = ;}
;
%%
int yyerror (char *s) {fprintf (stderr, "%s\n", s);
}
此外,我创建了一个 main.c,以单独保留 main() 函数。您可以省略 tree*.h 文件,因为它们只包含与 AST 相关的函数。
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "treedefs.h"
int main(int argc, char **argv){
yyparse();
TREE *RootNode = malloc(sizeof(TREE));
return 0;
}
我已经阅读了大量的例子,但我找不到与我写的有什么(非常)不同的地方。我究竟做错了什么?任何帮助,将不胜感激。
代码有一些问题。
首先,你的词法分析器应该包括:
%{
#include "parser.tab.h"
extern int yylval; // this line was missing
%}
其次,假设您希望代码在语句末尾进行计算,您必须在语句末尾包含一个规则。也就是说,假设它是面向行的,您将用这些替换当前的空白规则:
[ \t] {}
[\n] { return 0; }
第三,你的其中一句台词被篡改了。而不是这个:
printf("WARNING! Long identifier. Truncating to 8 chars\n"$
应该是这样的:
printf("WARNING! Long identifier. Truncating to 8 chars\n");
您的语法接受表达式或文件结尾。所以如果你给它一个表达式后跟一个文件结尾,你会得到一个错误。
另一个问题是您 return 输入末尾的标记 END_OF_FILE
,而不是 0
-- bison 期望 EOF 为 0
令牌,如果在输入末尾没有看到令牌,将给出语法错误。
最简单的解决方法是去掉 END_OF_FILE
标记并让 <<EOF>>
规则 return 0。然后你的语法变成:
program: /* empty */ { printf("Empty input\n"); }
| exp { printf("Result: %d\n", ); }
;
...rest of the grammar
现在您遇到了(潜在的)问题,即您的语法只接受单个表达式。您可能希望支持由换行符或其他一些分隔符分隔的多个表达式
(也许是;
?),这可以通过多种方式完成。
我正在尝试创建一个简单的 parser/compiler,主要用于家庭作业,但最终也用于学习和娱乐。我已经编写了词法分析器和解析器文件(用于命令的初始子集)并且我想输出一个 AST。但是,即使我试图解析一个简单的“1+1”,我仍然卡在 "syntax error" 消息中。这是词法分析器文件:
%{
#include "parser.tab.h"
%}
DIGIT [0-9]
LETTER [a-zA-Z]
%%
[ \t\n] ;
{DIGIT}+ {yylval = atoi(yytext); return NUMBER;}
{LETTER}* { if (strlen(yytext) <= 8){
printf( "<ID, %s> ", yytext );
} else {
yytext[8] = '[=11=]';
printf("WARNING! Long identifier. Truncating to 8 chars\n");
printf( "<ID, %s> ", yytext );
}
}
"+" {printf("Found '+' symbol\n");return(PLUS);}
"-" return(MINUS);
"*" return(TIMES);
"/" return(DIVIDE);
"(" return(LEFT_PARENTHESIS);
")" return(RIGHT_PARENTHESIS);
<<EOF>> return(END_OF_FILE);
%%
int yywrap (void) {return 1;}
这是解析器文件:
%{
#include <stdio.h>
/*#include "tree.h"
#include "treedefs.h"*/
int yylex();
#define YYSTYPE int
%}
%start program
%token NUMBER
%token ID
%token PLUS MINUS TIMES EQUAL
%token LEFT_PARENTHESIS RIGHT_PARENTHESIS
%token LET IN AND
%token END_OF_FILE
%left PLUS MINUS
%left TIMES DIVIDE
%%
program: /* empty */
| exp { printf("Result: %d\n", ); }
| END_OF_FILE {printf("Encountered EOF\n");}
;
exp: NUMBER { $$ = ;}
| exp PLUS exp { $$ = + ; }
| exp TIMES exp { $$ = * ; }
| '(' exp ')' { $$ = ;}
;
%%
int yyerror (char *s) {fprintf (stderr, "%s\n", s);
}
此外,我创建了一个 main.c,以单独保留 main() 函数。您可以省略 tree*.h 文件,因为它们只包含与 AST 相关的函数。
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "treedefs.h"
int main(int argc, char **argv){
yyparse();
TREE *RootNode = malloc(sizeof(TREE));
return 0;
}
我已经阅读了大量的例子,但我找不到与我写的有什么(非常)不同的地方。我究竟做错了什么?任何帮助,将不胜感激。
代码有一些问题。
首先,你的词法分析器应该包括:
%{
#include "parser.tab.h"
extern int yylval; // this line was missing
%}
其次,假设您希望代码在语句末尾进行计算,您必须在语句末尾包含一个规则。也就是说,假设它是面向行的,您将用这些替换当前的空白规则:
[ \t] {}
[\n] { return 0; }
第三,你的其中一句台词被篡改了。而不是这个:
printf("WARNING! Long identifier. Truncating to 8 chars\n"$
应该是这样的:
printf("WARNING! Long identifier. Truncating to 8 chars\n");
您的语法接受表达式或文件结尾。所以如果你给它一个表达式后跟一个文件结尾,你会得到一个错误。
另一个问题是您 return 输入末尾的标记 END_OF_FILE
,而不是 0
-- bison 期望 EOF 为 0
令牌,如果在输入末尾没有看到令牌,将给出语法错误。
最简单的解决方法是去掉 END_OF_FILE
标记并让 <<EOF>>
规则 return 0。然后你的语法变成:
program: /* empty */ { printf("Empty input\n"); }
| exp { printf("Result: %d\n", ); }
;
...rest of the grammar
现在您遇到了(潜在的)问题,即您的语法只接受单个表达式。您可能希望支持由换行符或其他一些分隔符分隔的多个表达式
(也许是;
?),这可以通过多种方式完成。