Flex 和 Bison C 加法器在不执行表达式后给出错误
Flex and Bison C adder gives error after not executing expression
我一直在尝试实现一个计算器,但找不到此 Flex、Bison 和 C 程序的源代码。我真的不知道我做错了什么。这是我的文件:
henry@FusionReactor:~/Downloads/YASPLANG$ ls
a.out compiler.output compiler.y lex.yy.c
compiler.l compiler.tab.c file.o README
我的语法:
henry@FusionReactor:~/Downloads/YASPLANG$ cat compiler.y
%{
#include <stdio.h>
void yyerror(const char *msg) {
fprintf(stderr, "%s\n", msg);
}
int yydebug = 1;
%}
%code requires
{
#define YYSTYPE double
}
/*
%union {
char c;
char *s;
double d;
}
*/
%define parse.error verbose
%define parse.lac full
%token NUM
%token PLUS
%token NEWLINE
%left PLUS
%%
answered: %empty {; }
| answered answer {; }//{ printf("%lg is answered.\n",); $$ = ; }
;
answer: NEWLINE { $$ = 0.0; }
| expr NEWLINE { $$ = ; }
;
expr: expr PLUS expr { $$ = + ; }//printf("%lg\n", $$ = + ); printf("Doing %lg + %lg.\n", , ); }
| NUM { $$ = ; }//printf("%lg\n", $$ = ); printf("Found number: %lg.\n", ); }
;
%%
还有我的词法分析器:
henry@FusionReactor:~/Downloads/YASPLANG$ cat compiler.l
%{
int yylex(void);
#include "compiler.tab.c"
%}
%%
[ \t] ;
'\n' ;//{ return NEWLINE; }
'+' { return PLUS; }
^[0-9]+(\.[0-9]+)? { sscanf(yytext, "%lf", &yylval); printf("%lf = %s\n", yylval, yytext); return NUM; }
%%
int main(const char **argv, int argc) {
return yyparse();
}
我用这些命令编译了它(我把所有的东西都放在我的下载中,文件夹名称是一个首字母缩写词,我们不要太担心):
henry@FusionReactor:~/Downloads/YASPLANG$ bison --report=all --verbose --debug compiler.y
henry@FusionReactor:~/Downloads/YASPLANG$ flex compiler.l
henry@FusionReactor:~/Downloads/YASPLANG$ gcc lex.yy.c -lfl
当我执行并键入“5 + 5 [NEWLINE]”两次时,我得到:
henry@FusionReactor:~/Downloads/YASPLANG$ ./a.out
Starting parse
Entering state 0
Reducing stack by rule 1 (line 26):
-> $$ = nterm answered ()
Stack now 0
Entering state 1
Reading a token: 5 + 5
5.000000 = 5
Next token is token NUM ()
Shifting token NUM ()
Entering state 3
Reducing stack by rule 6 (line 34):
= token NUM ()
-> $$ = nterm expr ()
Stack now 0 1
Entering state 6
Reading a token: +5
5 + 5
5.000000 = 5
Next token is token NUM ()
LAC: initial context established for NUM
LAC: checking lookahead NUM: Err
Constructing syntax error message
LAC: checking lookahead $end: Err
LAC: checking lookahead NUM: Err
LAC: checking lookahead PLUS: S7
LAC: checking lookahead NEWLINE: S8
syntax error, unexpected NUM, expecting PLUS or NEWLINE
Error: popping nterm expr ()
Stack now 0 1
Error: popping nterm answered ()
Stack now 0
Cleanup: discarding lookahead token NUM ()
Stack now 0
henry@FusionReactor:~/Downloads/YASPLANG$
我很困惑,如果能说出它是如何以及为什么不起作用,那将非常有帮助。
在 (f)lex 中,模式 '+'
匹配两个或多个 ' 的序列,因为 '
只是一个普通字符。如果要匹配单个 +,请使用 "+"
或 \+
或 [+]
。
类似地,'\n'
匹配三字符序列'ENTER'.只需使用 \n
.
最后,^[0-9]+(\.[0-9]+)?
只会匹配行首的数字,因为模式以^
开头。您希望它在任何地方都匹配,所以去掉 ^
。
没有报告明显错误的原因是 (f)lex 添加了一个隐含的默认规则,该规则匹配任何单个字符并执行 ECHO 操作(将字符写入 stdout
。该默认规则很难无论你想要什么;我强烈建议使用
%option nodefault
压制它。然后您必须提供您自己的默认规则,以及更明智的操作。
我一直在尝试实现一个计算器,但找不到此 Flex、Bison 和 C 程序的源代码。我真的不知道我做错了什么。这是我的文件:
henry@FusionReactor:~/Downloads/YASPLANG$ ls
a.out compiler.output compiler.y lex.yy.c
compiler.l compiler.tab.c file.o README
我的语法:
henry@FusionReactor:~/Downloads/YASPLANG$ cat compiler.y
%{
#include <stdio.h>
void yyerror(const char *msg) {
fprintf(stderr, "%s\n", msg);
}
int yydebug = 1;
%}
%code requires
{
#define YYSTYPE double
}
/*
%union {
char c;
char *s;
double d;
}
*/
%define parse.error verbose
%define parse.lac full
%token NUM
%token PLUS
%token NEWLINE
%left PLUS
%%
answered: %empty {; }
| answered answer {; }//{ printf("%lg is answered.\n",); $$ = ; }
;
answer: NEWLINE { $$ = 0.0; }
| expr NEWLINE { $$ = ; }
;
expr: expr PLUS expr { $$ = + ; }//printf("%lg\n", $$ = + ); printf("Doing %lg + %lg.\n", , ); }
| NUM { $$ = ; }//printf("%lg\n", $$ = ); printf("Found number: %lg.\n", ); }
;
%%
还有我的词法分析器:
henry@FusionReactor:~/Downloads/YASPLANG$ cat compiler.l
%{
int yylex(void);
#include "compiler.tab.c"
%}
%%
[ \t] ;
'\n' ;//{ return NEWLINE; }
'+' { return PLUS; }
^[0-9]+(\.[0-9]+)? { sscanf(yytext, "%lf", &yylval); printf("%lf = %s\n", yylval, yytext); return NUM; }
%%
int main(const char **argv, int argc) {
return yyparse();
}
我用这些命令编译了它(我把所有的东西都放在我的下载中,文件夹名称是一个首字母缩写词,我们不要太担心):
henry@FusionReactor:~/Downloads/YASPLANG$ bison --report=all --verbose --debug compiler.y
henry@FusionReactor:~/Downloads/YASPLANG$ flex compiler.l
henry@FusionReactor:~/Downloads/YASPLANG$ gcc lex.yy.c -lfl
当我执行并键入“5 + 5 [NEWLINE]”两次时,我得到:
henry@FusionReactor:~/Downloads/YASPLANG$ ./a.out
Starting parse
Entering state 0
Reducing stack by rule 1 (line 26):
-> $$ = nterm answered ()
Stack now 0
Entering state 1
Reading a token: 5 + 5
5.000000 = 5
Next token is token NUM ()
Shifting token NUM ()
Entering state 3
Reducing stack by rule 6 (line 34):
= token NUM ()
-> $$ = nterm expr ()
Stack now 0 1
Entering state 6
Reading a token: +5
5 + 5
5.000000 = 5
Next token is token NUM ()
LAC: initial context established for NUM
LAC: checking lookahead NUM: Err
Constructing syntax error message
LAC: checking lookahead $end: Err
LAC: checking lookahead NUM: Err
LAC: checking lookahead PLUS: S7
LAC: checking lookahead NEWLINE: S8
syntax error, unexpected NUM, expecting PLUS or NEWLINE
Error: popping nterm expr ()
Stack now 0 1
Error: popping nterm answered ()
Stack now 0
Cleanup: discarding lookahead token NUM ()
Stack now 0
henry@FusionReactor:~/Downloads/YASPLANG$
我很困惑,如果能说出它是如何以及为什么不起作用,那将非常有帮助。
在 (f)lex 中,模式 '+'
匹配两个或多个 ' 的序列,因为 '
只是一个普通字符。如果要匹配单个 +,请使用 "+"
或 \+
或 [+]
。
类似地,'\n'
匹配三字符序列'ENTER'.只需使用 \n
.
最后,^[0-9]+(\.[0-9]+)?
只会匹配行首的数字,因为模式以^
开头。您希望它在任何地方都匹配,所以去掉 ^
。
没有报告明显错误的原因是 (f)lex 添加了一个隐含的默认规则,该规则匹配任何单个字符并执行 ECHO 操作(将字符写入 stdout
。该默认规则很难无论你想要什么;我强烈建议使用
%option nodefault
压制它。然后您必须提供您自己的默认规则,以及更明智的操作。