我正在尝试一个示例来检查for
和flex
中bison
循环的正确性。这是flex
文件:
%{
#include "ch.tab.h"
extern int yylval;
%}
%%
for {return (FOR);}
"(" {return (OPBR);}
")" {return (CLBR);}
";" {return (SEMIC);}
"=" {return (EQU);}
"<"|">" {return (RELOP);}
"++" {return (INC);}
"--" {return (DEC);}
[a-zA-Z]+ {yylval=yytext[0];return(ID);}
[0-9]+ {yylval=atoi(yytext);return(NUM);}
%%
int yywrap()
{
return 1;
}
和bison
文件:
%{
#include <stdio.h>
int flag=0;
%}
%token FOR OPBR CLBR SEMIC RELOP EQU ID NUM RELOP INC DEC
%%
S:FOR OPBR E1 SEMIC E2 SEMIC E3 CLBR {printf("Accepted!");flag=1;}
;
E1: ID EQU ID
| ID EQU NUM
;
E2: ID RELOP ID
| ID RELOP NUM
;
E3: ID INC
| ID DEC
;
%%
int main()
{
return yyparse();
}
yyerror(const char *msg)
{
if(flag==0);
printf("Not Accepted!");
}
一切都在第一次运行良好。当我运行示例for(i = 0; i < 2; i++)
时,第一次打印Accepted
,当我再次运行相同的示例而不关闭command prompt
时,我得到Not Accepted!
。为什么?
有没有办法让exe
这样只要我输入正确的语法,它会继续说Accepted
并等待另一个新的输入?
答案 0 :(得分:1)
因为你的语法只接受一个for
语句,因此必须是整个输入。
如果您希望能够接受多个语句,则需要语法来生成多个语句。所以你可以使用非终端,如:
input: /* Empty */ | input S;
将接受任何数字(包括0)的S
s。 (当然,您需要将其作为开始符号,因此您需要一个%start input
指令,或者您需要将该生产放在任何其他作品之前。)
只要输入了有效的语句,它就会继续解析,但是当它无法解析语句时它将失败。您可能更喜欢的是生成错误消息,但在遇到错误的语句时继续解析。一种简单的方法是使用错误生成:
S: error SEMIC { yyerror("Invalid for statement"); }
将通过丢弃令牌进行错误恢复,直到找到分号,然后恢复正常解析。 (在该操作中,我假设您修改yyerror
以打印作为参数传递的字符串,而不是忽略它。)
顺便说一下,正常的野牛风格是使用UPPER案例作为代币(FOR
),小写作为非终端(statement
),单字符文字使用单字符代币({ {1}})。
对于使用flex扫描程序的单字符文字,您需要从扫描程序操作返回字符而不是标记名称:
';'
在不必编写大量样板规则的情况下执行此操作的常用方法是在弹性规则的末尾添加一个全能回退词法规则:
";" { return ';'; }