你可能希望在同一个程序中使用两个部分或者完全不同的记号语法。一个交互式调试解释器可能需要一个词法分析器用于编程语言,还需要另外一个词法分析器用于调试命令。
有两种基本的方法来使一个程序处理两个词法分析器:合并的词法分析器或者把两个完整的词法分析器放到程序中
合并的词法分析器
你可以使用起始状态合并两个词法分析器。每个词法分析器的模式都被加上特定起始状态作为前缀。当词法分析器开始工作时,你需要写一小段代码来让 它进入合适的初始状态,这样就可以选择特定的词法分析器了,例如下面这一段代码(它将会被拷贝到yylex()的开头):
%s INITA INITB INITC
%%
%{
extern first_tok, fist_lex;
if(first_lex){ // 在调用词法分析器之前,会设置first_lex作为它的起始状态
BEGIN(first_lex);
first_lex = 0;
}
if(first_tok){
int holdtok = fist_tok;
first_tok = 0;
return holdtok;
}
%}
%%
这种合并的词法分析器与合并的语法分析器结合使用时,你通常需要通过代码来产生初始记号,以便于告知语法分析器那种语法正在使用。这种方法的有点是目标代码比较小。缺点就是其因为共享而引入的复杂性,你需要非常小心使用起始状态;你不能够一次激活两种词法分析器;对于不同词法分析器使用不同的输入源的情况处理会比较麻烦。
同一个程序中的多个完整的词法分析器
另外一种方法是在你的程序中包含两个词法分析器。这种技巧要求改变lex默认使用的函数和变量名,这样两个词法分析器才可以分别生成,然后编译到同一个程序中。
flex提供了命令行选项和程序选项来改变生成的词法分析器所使用的名字的前缀。例如,下面这些选项可以让flex使用前缀"foo"而不是"yy",并且生成的词法分析器源文件会是foolex.c。
%option prefix="foo"
%option outfile="foolex.c"
你也可以通过命令行选项来实现这一点:
flex --outfile=foolex.c --prefix=foo foo.l
任何一种方法生成的词法分析器又具有入口函数foolex(),它从标准文件fooin读取输入。不过稍微有点儿迷惑人的是,flex需要在词法分析器的最前面生成一大堆#define宏,它们会把标准的"yy"格式的名字重定义为选定的前缀格式。这使得你可以继续使用标准名字来编写你的词法分析器,而外部可见的名字则会使用选定的前缀。例如:
#define yyin fooin
#define yyleng fooleng
#define yylex foolex
#define yyout fooout
#define yytext footext
#define yylineno foolineno
ronnie88597
原创文章 60获赞 84访问量 4179
关注
私信
展开阅读全文