处理同一文件中的不同格式

目前我们看到的输入文件都只包含一种语言,但在实际应用中我们会遇到有些包含多种语言的常用文件格式。例如,Java的文档注释,XML文件等。这些环绕着模板表达式的文本需要不同的处理方式,它们被称为孤岛语言。

ANTLR有提供一个称之为“词法模型”的词法分析器特性,它让我们可以很容易地处理包含混合格式的文件。基本思路是:当词法分析器看到特殊的哨兵字符序列时,让它在模式之间来回切换。

XML是一个很好例子,它通常会在同一个文件中包含不同的词法结构。一个XML语法分析器会把除标签和实体引用(例如♥)之外的任何东西当作文本块。当词法分析器看到<时,它切换到“inside”模式;当它看到>/>时,就切换回默认模式。以下语法展示了该特性是如何工作的:

  1. lexer grammar XMLLexer;
  2. // Default "mode": Everything OUTSIDE of a tag
  3. OPEN : '<' -> pushMode(INSIDE) ;
  4. COMMENT : '<!--' .*? '-->' -> skip ;
  5. EntityRef : '&' [a-z]+ ';' ;
  6. TEXT : ~('<'|'&')+ ; // match any 16 bit char minus < and &
  7. // ----------------- Everything INSIDE of a tag ---------------------
  8. mode INSIDE;
  9. CLOSE : '>' -> popMode ; // back to default mode
  10. SLASH_CLOSE : '/>' -> popMode ;
  11. EQUALS : '=' ;
  12. STRING : '"' .*? '"' ;
  13. SlashName : '/' Name ;
  14. Name : ALPHA (ALPHA|DIGIT)* ;
  15. S : [ \t\r\n] -> skip ;
  16. fragment
  17. ALPHA : [a-zA-Z] ;
  18. fragment
  19. DIGIT : [0-9] ;

把上述语法保存为XMLLexer.g文件,然后使用包含以下内容的t.xml文件作为输入来测试它:

  1. <tools>
  2. <tool name="ANTLR">A parser generator</tool>
  3. </tools>

以下是构建和运行测试的命令:

  1. antlr XMLLexer.g
  2. compile *.java
  3. grun XML tokens -tokens t.xml

这里是输出的内容:

  1. [@0,0:0='<',<1>,1:0]
  2. [@1,1:5='tools',<10>,1:1]
  3. [@2,6:6='>',<5>,1:6]
  4. [@3,7:10='\r\n ',<4>,1:7]
  5. [@4,11:11='<',<1>,2:2]
  6. [@5,12:15='tool',<10>,2:3]
  7. [@6,17:20='name',<10>,2:8]
  8. [@7,21:21='=',<7>,2:12]
  9. [@8,22:28='"ANTLR"',<8>,2:13]
  10. [@9,29:29='>',<5>,2:20]
  11. [@10,30:47='A parser generator',<4>,2:21]
  12. [@11,48:48='<',<1>,2:39]
  13. [@12,49:53='/tool',<9>,2:40]
  14. [@13,54:54='>',<5>,2:45]
  15. [@14,55:56='\r\n',<4>,2:46]
  16. [@15,57:57='<',<1>,3:0]
  17. [@16,58:63='/tools',<9>,3:1]
  18. [@17,64:64='>',<5>,3:7]
  19. [@18,65:66='\r\n',<4>,3:8]
  20. [@19,67:66='<EOF>',<-1>,4:0]

上面输出的每一行代表一个记号,包含记号索引、开始和结束字符、记号文本、记号类型,最后的行和字符位置则告诉我们词法分析器如何标记化输入。

在命令行中,XML tokens序列处通常是一个语法名字后面跟着开始规则,但在这里,我们使用语法名字后面跟着特殊的规则名字tokens来告诉TestRig应该运行词法分析器而不是语法分析器。接着使用选项-tokens打印出匹配的记号列表。