目前我们看到的输入文件都只包含一种语言,但在实际应用中我们会遇到有些包含多种语言的常用文件格式。例如,Java的文档注释,XML文件等。这些环绕着模板表达式的文本需要不同的处理方式,它们被称为孤岛语言。
ANTLR有提供一个称之为“词法模型”的词法分析器特性,它让我们可以很容易地处理包含混合格式的文件。基本思路是:当词法分析器看到特殊的哨兵字符序列时,让它在模式之间来回切换。
XML是一个很好例子,它通常会在同一个文件中包含不同的词法结构。一个XML语法分析器会把除标签和实体引用(例如♥)之外的任何东西当作文本块。当词法分析器看到
<
时,它切换到“inside”模式;当它看到
>
或
/>
时,就切换回默认模式。以下语法展示了该特性是如何工作的:
lexer grammar XMLLexer;
// Default "mode": Everything OUTSIDE of a tag
OPEN : '<' -> pushMode(INSIDE) ;
COMMENT : '<!--' .*? '-->' -> skip ;
EntityRef : '&' [a-z]+ ';' ;
TEXT : ~('<'|'&')+ ; // match any 16 bit char minus < and &
// ----------------- Everything INSIDE of a tag ---------------------
mode INSIDE;
CLOSE : '>' -> popMode ; // back to default mode
SLASH_CLOSE : '/>' -> popMode ;
EQUALS : '=' ;
STRING : '"' .*? '"' ;
SlashName : '/' Name ;
Name : ALPHA (ALPHA|DIGIT)* ;
S : [ \t\r\n] -> skip ;
fragment
ALPHA : [a-zA-Z] ;
fragment
DIGIT : [0-9] ;
把上述语法保存为XMLLexer.g文件,然后使用包含以下内容的t.xml文件作为输入来测试它:
<tools>
<tool name="ANTLR">A parser generator</tool>
</tools>
以下是构建和运行测试的命令:
antlr XMLLexer.g
compile *.java
grun XML tokens -tokens t.xml
这里是输出的内容:
[@0,0:0='<',<1>,1:0]
[@1,1:5='tools',<10>,1:1]
[@2,6:6='>',<5>,1:6]
[@3,7:10='\r\n ',<4>,1:7]
[@4,11:11='<',<1>,2:2]
[@5,12:15='tool',<10>,2:3]
[@6,17:20='name',<10>,2:8]
[@7,21:21='=',<7>,2:12]
[@8,22:28='"ANTLR"',<8>,2:13]
[@9,29:29='>',<5>,2:20]
[@10,30:47='A parser generator',<4>,2:21]
[@11,48:48='<',<1>,2:39]
[@12,49:53='/tool',<9>,2:40]
[@13,54:54='>',<5>,2:45]
[@14,55:56='\r\n',<4>,2:46]
[@15,57:57='<',<1>,3:0]
[@16,58:63='/tools',<9>,3:1]
[@17,64:64='>',<5>,3:7]
[@18,65:66='\r\n',<4>,3:8]
[@19,67:66='<EOF>',<-1>,4:0]
上面输出的每一行代表一个记号,包含记号索引、开始和结束字符、记号文本、记号类型,最后的行和字符位置则告诉我们词法分析器如何标记化输入。
在命令行中,XML tokens序列处通常是一个语法名字后面跟着开始规则,但在这里,我们使用语法名字后面跟着特殊的规则名字tokens来告诉TestRig应该运行词法分析器而不是语法分析器。接着使用选项-tokens打印出匹配的记号列表。