我正在为C预处理器编写一些其他C语法的词法分析器。作为其中的一部分,我必须在#include中识别文件名。我遇到的问题是识别文件名。文件名包含基底名和扩展名两部分。Basename可以使用lexer的"IDENTIFIER"正则表达式来标识;所以可以用"。"分隔。
对于"IDENTIFIER"one_answers"。"有一个单独的正则表达式。对于文件名,我正在考虑编写另一个正则表达式,它基本上是"IDENTIFIER","。"one_answers"h"的连接。我的问题是,如果写一个正则表达式的文件名,我所描述的;它将如何被处理?考虑到已经有单独代币的规则;它会识别3个令牌(IDENTIFIER, DOT和IDENTIFIER),还是会识别文件名?
据我所知,对于一个预处理器词法分析器来说,没有什么好的理由将包含指令中的文件名视为不透明的字符序列以外的任何东西。确切的名称与预处理器无关;它可以不包含扩展或包含多个.
(如果操作系统允许的话,这是目前大多数操作系统允许的);它可能包含特殊字符,如斜杠;它可能是一个数字;等。
同样,对尖括号和引号的处理在include指令的参数中是特殊的。因此,处理include指令的通常方法是使用上下文敏感的模式,例如使用(f)lex启动条件。
由于换行符在所有预处理器指令中都是特别处理的,因此您通常还需要为它们设置一个上下文敏感的模式。
使用flex语法的粗略草图。很多细节都被遗漏了。
%x PP_DIRECT PP_ARG PP_INCLUDE
%%
^[[:blank:]]*"#" { BEGIN(PP_DIRECT); }
<PP_DIRECT>include { BEGIN(PP_INCLUDE); return T_INCLUDE; }
/* You might want to recognize other include directives as
* specific keyword tokens. In particular, the scanner needs
* to be aware of conditionals, since it might have to put itself
* into a mode where it skips to the matching #endif
*/
<PP_DIRECT>[[:alpha:]]+ { BEGIN(PP_ARG); /* ... */ }
/* Normally newlines are not returned to the parser, but here we do. */
<PP_ARG>n { BEGIN(INITIAL); return 'n'; }
/* This should actually be done in a previous step */
<PP_ARG>\n /* IGNORE */
<PP_INCLUDE>["][^"]*["] { yytext[yyleng-1] = 0;
do_include(yytext+1);
/* Really, should check that only whitespace follows */
BEGIN(PP_ARG);
}
<PP_INCLUDE>[<][^>]*[>] { yytext[yyleng-1] = 0;
do_system_include(yytext+1);
BEGIN(PP_ARG);
}