Lex 中的串联标记
Concatenated tokens in Lex
我正在为 C 预处理器和其他一些 C 语法编写词法分析器。作为其中的一部分,我必须在#include 中识别文件名。我遇到的问题是识别文件名。文件名包含两部分:基本名称和扩展名。 Basename 可以使用 lexer 的 "IDENTIFIER" 正则表达式来识别;所以可以是“。”将它们分开。
"IDENTIFIER" 和“.”有一个单独的正则表达式。对于文件名,我正在考虑编写另一个正则表达式,它基本上是 "IDENTIFIER"、"." 的串联。和 "h"。我的问题是,如果按照我的描述为文件名编写正则表达式;它将如何处理。考虑到已经有单独令牌的规则这一事实;它将识别 3 个标记(IDENTIFIER、DOT 和 IDENTIFIER)而不是识别文件名,还是识别文件名?
据我所知,预处理器词法分析器没有充分理由将 include 指令中的文件名视为不透明的字符序列以外的任何内容。精确名称与预处理器无关;它可能不包含扩展名或包含多个 .
(前提是操作系统允许,现在大多数情况下都是如此);它可能包含特殊字符,例如斜杠;它可能是一个数字;等等
此外,尖括号和引号的处理在 include 指令的参数中是特殊的。因此,处理包含指令的常用方法是使用上下文相关模式,例如使用 (f)lex start conditions.
由于换行符也在所有预处理器指令中进行了特殊处理,因此您通常也需要它们的上下文相关模式。
使用 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);
}
我正在为 C 预处理器和其他一些 C 语法编写词法分析器。作为其中的一部分,我必须在#include 中识别文件名。我遇到的问题是识别文件名。文件名包含两部分:基本名称和扩展名。 Basename 可以使用 lexer 的 "IDENTIFIER" 正则表达式来识别;所以可以是“。”将它们分开。
"IDENTIFIER" 和“.”有一个单独的正则表达式。对于文件名,我正在考虑编写另一个正则表达式,它基本上是 "IDENTIFIER"、"." 的串联。和 "h"。我的问题是,如果按照我的描述为文件名编写正则表达式;它将如何处理。考虑到已经有单独令牌的规则这一事实;它将识别 3 个标记(IDENTIFIER、DOT 和 IDENTIFIER)而不是识别文件名,还是识别文件名?
据我所知,预处理器词法分析器没有充分理由将 include 指令中的文件名视为不透明的字符序列以外的任何内容。精确名称与预处理器无关;它可能不包含扩展名或包含多个 .
(前提是操作系统允许,现在大多数情况下都是如此);它可能包含特殊字符,例如斜杠;它可能是一个数字;等等
此外,尖括号和引号的处理在 include 指令的参数中是特殊的。因此,处理包含指令的常用方法是使用上下文相关模式,例如使用 (f)lex start conditions.
由于换行符也在所有预处理器指令中进行了特殊处理,因此您通常也需要它们的上下文相关模式。
使用 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);
}