Bison 我应该如何处理Flex lexer中的词汇错误?
我目前正在尝试使用Flex+Bison编写一个小型编译器,但我对如何处理错误,特别是如何使所有内容都协调一致,有点不知所措。为了激发讨论,请考虑下面我使用的字符串字符串:Bison 我应该如何处理Flex lexer中的词汇错误?,bison,yacc,lex,flex-lexer,lexer,Bison,Yacc,Lex,Flex Lexer,Lexer,我目前正在尝试使用Flex+Bison编写一个小型编译器,但我对如何处理错误,特别是如何使所有内容都协调一致,有点不知所措。为了激发讨论,请考虑下面我使用的字符串字符串: ["] { BEGIN(STRING_LITERAL); init_string_buffer(); } <STRING_LITERAL>{ \\\\ { add_char_to_buffer('\\'); } \\\" { add_char_to_buffer('\"
["] { BEGIN(STRING_LITERAL); init_string_buffer(); }
<STRING_LITERAL>{
\\\\ { add_char_to_buffer('\\'); }
\\\" { add_char_to_buffer('\"'); }
\\. { /*Invalid escape. How do I treat this error?*/ }
["] { BEGIN(INITIAL); yylval = get_string_buffer(); return TK_STRING; }
}
[“]{BEGIN(STRING_LITERAL);init_STRING_buffer();}
{
\\\\{将字符添加到缓冲区('\\');}
\\\{将字符添加到缓冲区(“\”);}
\\.{/*转义无效。如何处理此错误?*/}
[“]{BEGIN(INITIAL);yylval=get_string_buffer();return TK_string;}
}
我如何处理无效逃逸的情况?现在我只是打印一条错误消息并调用exit
,但我更希望能够继续运行,并在可能的情况下检测每个文件中的多个错误
我的问题是:
- 我使用什么功能打印错误消息?和野牛后来预期的一样?如果我有单独的lexer和parser文件,那么我应该把yyerror的定义放在哪里李>
- 我应该从我的操作返回什么令牌代码?0表示“文件结束”?一些特殊的TK_无效字符串标记
- 如何确保语法分析器在出现词法错误(无效的文本、零散的标点符号等)后可以继续解析
- 直接从lexer打印错误消息。告诉您错误检测系统编译失败:您可以使用全局错误计数(yuk,globals!)或传递给
的共享数据结构作为附加参数。然后忽略字符并继续词法分析yylex
- 向解析器返回类似于
的内容。解析器将需要有适当的TK\u INVALID\u STRING
产品,以便适当地处理和恢复此错误,这需要大量的工作,但其优点是将所有错误处理都放在解析器中。但是,在字符串的特殊情况下,您可能需要完成字符串的词法分析,直到结束引号;否则,继续解析将是徒劳的错误
至于
- 有很多选择。哪一个最好可能是意见的问题。(请注意,对于回答为观点而非事实的问题,SO并不友好。)
这在很大程度上取决于您通常如何处理应用程序中的错误消息。但这里有两种可能性:
yyerror
:关于yyerror
,没有什么神奇之处。这完全是你的责任。bison所做的唯一一件事就是用一组指定的参数调用它。如果您发现它对记录lexer中注意到的错误很有用(我认为可能是这样),那么就继续使用它。您完全负责声明yyrorm
,因此将其定义放在您在lexer和解析器中包含的任何共享头文件中。或者摆弄bison代码生成选项,以获得包含在使用bison创建的头文件中的定义。什么都容易。一旦你弄明白了如何声明yyrorm
,你可以在任何你想要的地方定义它:在lexer文件中,在bison文件中,或者(我的首选)在一个单独的支持函数库中
(FWIW,我尝试了选项2,在我看来,这真的是太多的工作了;选项1对我来说很好。但是口味不同,YMMV;我不打算在这里捍卫我的选择,但我不介意承认。)最简单的事情就是有一个最终的规则
. return yytext[0];
这包括所有单个特殊字符以及所有非法字符。直接在语法中使用特殊字符,如“:”、“;”等。然后,如果获得非法字符,将调用解析器的错误处理,从而提供一些恢复的可能性。如果你在lexer中处理它们,你所能做的就是打印一个错误并忽略它们
它也减少了Lax文件的大小。
< P>如果你使用的是带有C++输出的BySon,另一个选项是抛出异常。. throw yy::parser::syntax_error("invalid character: " + std::string(yytext, yyleng);
如果使用选项1,当lexer发现无效的字符串文本时,它会返回什么?你会假装它是一个有效的(返回TK_字符串),然后让负责调用解析器的高级代码检查全局错误变量吗?@missingno:没错。这是继续解析的最简单方法。在准备生成代码之前,不需要检查错误。从这个意义上讲,它与超出范围的整数没有什么不同,例如:您希望确保编译失败,但从解析的角度来看,您应该能够继续检查其余的语法。FWIW我经常使用选项1,但调用yyerror发出错误消息,以便所有的“语法错误”只能在一个地方进行处理。@akim:请在我的回答中搜索“我认为可能是”。这是一个合理的方法,但接下来您如何处理OP中的最后一个问题:“我如何确保语法分析器在出现词法错误后可以继续进行语法分析?”假设,一旦您将flex内部构件从中取出,它们就会被烤熟,?否?@rici:生成的解析器捕获
语法错误
,然后触发常规错误报告/恢复序列。至于yylex
函数本身,我看不出它会发生什么:它的控制流被设计为通过返回是可中断的代码>,继续代码>等等。在实践中,我从来没有遇到过任何问题。