Flex新线扫描野牛

我想使用相同的flex / bison扫描器/解析器作为解释器并加载要解释的文件。 在这两种情况下,我都无法让换行解析正常工作。

  1. 解释器:有一个提示,我可以按ENTER键输入命令终止。
  2. 文件:这是一个示例输入文件:

– – -切 – – – – –

begin( print("well done"), 1) 

– – 切 – – – –

所以,第一行和’(’应该被吃掉之后有一个换行符。

在我的scanner.l我有

 %% [ \t] { errorLineCol += strlen(yytext); } \n { errorLineNumber++; errorLineCol = 0; } ("-"?[0-9])[0-9]* { errorLineCol += strlen(yytext); yylval = stringToInteger(yytext); return TINTEGER; } 

…..

这适用于文件方案,但不适用于解释器。 我必须在ENTER之后按下并按Ctrl + D. 如果我换到

 \n { errorLineNumber++; errorLineCol = 0; return 0; } 

然后翻译工作,但不是文件阅读; 然后在它遇到的第一个换行符后停止。 解决这个问题的好方法是什么?

编辑:

这是解析器的顶级:

 input: uexpr { parseValue = $1; } | /* empty */ { parseValue = myNull; } | error { parseValue = myNull; } ; uexpr: list | atom ; 

可能的解决方案:似乎是要使用

 \n { errorLineNumber++; errorLineCol = 0; if (yyin == stdin) return 0; } 

主要问题是你的解析器函数ypparse在它将整个语言缩减为起始符号之前不会返回。

如果您的语法的顶级是这样的:

 language : commands ; commands : command commands | /* empty */ ; 

当然机器会期望一个完整的脚本(由你按Ctrl-D终止)。 如果你的翻译是这样的逻辑:

 loop: print("prompt>") yyparse() if (empty statement) break 

由于yyparse在返回之前使用整个脚本,因此无法正常工作。

return 0; 解决了此交互模式的问题,因为标记值0表示解析器的EOF ,使其认为脚本已结束。

我不同意制作令牌的解决方案。 它只会使语法复杂化(一个迄今为止无关紧要的空白片段现在很重要)并且最终无法工作,因为yyparse函数仍然需要处理完整的语法。 也就是说,如果您将换行符作为标记,但语法的开始符号表示整个脚本,则yyparse仍将不会返回到您的交互式提示循环。

快速而肮脏的黑客是让词法分析器知道交互模式是否有效。 然后它可以条件地return 0; 对于换行的每个实例,如果它处于交互模式。 如果输入不是完整语句,则会出现语法错误,因为整个脚本在换行符处结束。 在正常的文件读取模式下,你的词法分析器可以在不返回的情况下占用所有空格,就像之前允许使用单个yyparse处理整个文件一样。

如果您希望交互式输入和文件读取而不在词法分析器中实现两种行为模式,那么您可以做的是更改语法,以便它只解析一种语言语句: yyparse函数返回语言的每个顶级语句。 (并且词法分析器像以前一样吃新行,没有返回0)。 即语法的开始符号只是一个语句(可能是空的)。 然后你的文件解析器必须实现为一个循环(由你编写),它调用yyparse来获取文件中的所有语句,直到yyparse遇到空输入。 这种方法的缺点是,如果用户键入不完整的语法(例如悬空开括号),解析器将继续扫描输入,直到满足为止。 这是不友好的,就像使用scanf进行交互式用户输入的程序一样(这是同样的问题: scanf是一个在满意之前不会返回的解析器)。

另一种可能性是具有交互模式,该模式执行其自己的用户输入而不是调用yyparse来获取输入解析它。 在此模式下,您将用户的输入读入行缓冲区。 然后你让解析器处理行缓冲区。 完全可以处理行缓冲区而不是FILE *流。 您只需编写自定义输入处理(您自己定义的YY_INPUT宏)。 如果您使用行编辑和历史记录实现一个体面的交互模式,例如使用libeditGNU readline ,这将是您最终需要的方法。

如果按ENTER键终止命令,则词法分析器应返回\ n的标记。 返回0告诉解析器输入源是完整的(文件的文件结尾或终端的^ D)。 在你的语法中添加行尾令牌,让词法分析器在看到\ n时返回。

ETA:但是不要忘记处理不以ENTER结尾的最后一行的情况。 让你的词法分析器在文件末尾返回一个行尾令牌,除非最后一个字符是\ n。