如何告诉 flex 和 bison 等待新的输入?

How to tell flex and bison to wait for new input?

我正在尝试一个示例来检查 flexbisonfor 循环的正确性。这是 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 并等待另一个新输入?

因为您的语法只接受一个 for 语句,因此它必须是整个输入。

如果你希望能够接受多个语句,你需要你的语法来产生多个语句。所以你可以使用 non-terminal 比如:

input: /* Empty */ | input S;

这将接受任意数量(包括 0)的 Ss。 (当然,你需要它作为开始符号,所以你要么需要一个 %start input 指令,要么你需要将该产生式放在任何其他产生式之前。)

只要输入了有效的语句,它就会继续解析,但是当它无法解析语句时就会失败。您可能更喜欢生成一条错误消息,但在遇到不正确的语句时继续解析。一种简单的方法是使用错误生成,例如:

S: error SEMIC { yyerror("Invalid for statement"); }

它将通过丢弃标记直到找到分号来进行错误恢复,然后恢复正常解析。 (在该操作中,我假设您修改 yyerror 以打印作为参数传递的字符串,而不是忽略它。)


顺便说一下,正常的 bison 风格是使用大写字母表示标记 (FOR),使用小写字母表示非终结符 (statement),以及 single-character 文字表示 single-character 代币 (';').

要使 single-character 字面量与 flex 扫描仪一起使用,您需要 return 扫描仪操作中的字符而不是标记名称:

";"  { return ';'; }

无需编写大量样板规则即可做到这一点的常用方法是在 flex 规则的末尾放置 catch-all 回退词法规则:

.    { return yytext[0]; }