有flex / bison的问题。我执行一个语句,结果只在我执行第二个语句后出现。为什么呢?
这就是我想要的:
d>5
3 = 5
5+6=
11
PR 2+3
5
d>5
3 = 5
这是我得到的(注意结果的底部部分):
d>5
3 = 5
5+6=
11
PR 2+3
d>5
53 = 5
这是flex:
%{
#include "calc.tab.h"
#include <stdlib.h>
%}
%%
[ ] {}
[0-9]+ { yylval = atoi( yytext ); return NUM; }
[a-z] { yylval = yytext[0] - 'a'; return NAME; }
. { return (int) yytext[0]; }
"PR" { return PR; }
%%
int yywrap(void)
{
return 1;
}
这是yacc / bison:
/* Infix notation calculator--calc */
%{
#define YYDEBUG 1
#define YYSTYPE int
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* prototypes */
void yyerror (char* s);
int yylex(void);
void storeVar (char vName, int vValue);
void printVar (int value);
int sym[30];
%}
/* BISON Declarations */
%start input /* what rule starts */
%token NUM
%token NAME
%token PR
%left '-' '+' /* these done for precdence */
%left '*' '/'
%right '^' /* exponentiation */
/* Grammar follows */
%%
input: /* empty string */
| input line
;
/* line: '\n' */
/* | exp '\n' { printf ("\t%.10g\n", $1); } */
line: '\n' { printf(" "); }
| var '>' NUM { printf("%d %s %d", $1, "=", $3); }
| PR exp { printVar($2); }
| exp '=' { printf("%d", $1); }
;
exp: NUM { $$ = $1; }
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
var: NAME { $$ = $1; }
%%
int main ()
{
yyparse ();
}
void yyerror (char *s) /* Called by yyparse on error */
{
printf ("%s\n", s);
}
void storeVar (char vName, int vValue)
{
sym[(int)vName-97] = vValue;
}
void printVar (int value)
{
printf("%d", value);
//printf("%d", array[0]);
}
答案 0 :(得分:2)
该计算器定义存在两个问题,它们的组合有点令人困惑。
首先,扫描程序永远不会返回令牌\n
,因为没有规则匹配\n
。在flex
中,.
正则表达式字符匹配“除换行符之外的任何字符 ”(请参阅flex manual)。因此,当扫描程序看到\n
时,它会采用默认操作ECHO
,然后立即读取下一个标记,这会导致读取下一个输入行。因此,当您键入 P R 2 + 3 NL ,你看到的第一件事是回显 NL ,导致空白行,并读取另一行。扫描程序依次传递给解析器 PR NUM + NAME NAME 大骨节病>。由于 PR NUM + NAME 是有效的行以及以下 NAME 无法转移,生产line: PR exp
现已减少,导致行动{ printVar($2); }
被执行。
这是第二个问题:你的printf
语句都没有打印换行符。因此,该操作只输出字符5
。随后,行 d>5
减少并打印3 = 5
。最后,再次调用扫描仪,此时它会扫描\n
并回显它。
将扫描仪和解析器的输出混合起来通常不是一个好主意,因为执行顺序并不明显;有时解析器在缩小之前需要一个先行令牌,有时它不会,所以你不能轻易地看到扫描器的输出是在扫描令牌之前的缩减输出之前还是之后。无论如何,我不认为这是你的意图,但仍然值得一提。总的来说,我会完全避免ECHO
动作,包括作为默认动作,除非你只使用flex编写一个传感器。
修复弹性输入很容易;您只需要将\n
明确添加到您的捕获规则中:
.|\n { return yytext[0]; }
int
的演员阵容毫无意义。如果您的目的是防止返回负面签名字符,则应使用:
.|\n { return (unsigned char)yytext[0]; }
但是如果你只是进行了改变,你会发现你的输出有点混乱,因为它永远不会输出换行符。我只是为每种格式添加\n
,但您可能有不同的需求。
进行更改后,您还会发现无法再跨行分割表达式。你可以通过忽略扫描仪中的换行来解决这个问题,但是你必须做出选择,因为如果表达式可以跨行分割,那么在读取下一个标记之前就不可能知道表达式的结束位置,你将会是回到“延迟”执行。
答案 1 :(得分:0)
嗯,这里是:语句在这个特定的语法中没有终止符。
我一实施&#34;;&#34;作为声明的终结者,一切似乎都在完美无缺。
在.l文件中添加:
";" { return TERM; }
在.y文件中... ...添加:
%token TERM
......并改变:
| input line
使用:
| input line TERM
我相信里奇回答了我的问题,更详细一点,我只想在挖掘约2天后说出我的解决方案。
答案 2 :(得分:-1)
Bison在字符上使用前瞻,如LALR(1)。
不会减少
line: '\n'
直到'\ n'之后的字符。
要修复,您可以重复调用yyparse或重构语法,使'\ n'是您要对其执行操作的表达式的先行标记。
line: someactiontriggeredbynl '\n'