如何让ANTLR4词法分析器多消费字符并在已有规则处停止?
合并ANTLR4 PhpLexer的INLINE_HTML Token解决方案
现有如下PhpLexer词法规则:
lexer grammar PhpLexer; options { superClass = PhpLexerBase; caseInsensitive = true; } T_OPEN_TAG_WITH_ECHO: '<?=' -> pushMode(PHP); T_OPEN_TAG: PhpOpenTag -> pushMode(PHP); T_INLINE_HTML: .+?; // 问题点 mode PHP; T_CLOSE_TAG: '?>'; T_BAD_CHARACTER: .; fragment NEWLINE: '\r'? '\n' | '\r'; fragment PhpOpenTag : '<?php' ([ \t] | NEWLINE) | '<?php' EOF ;
输入内容为:
<html><?php echo "Hello, world!"; ?></html>
当前识别结果为每个HTML字符均被识别为独立的T_INLINE_HTML Token,期望将<html>这类连续HTML内容合并为单个T_INLINE_HTML Token,让词法分析器消费更多字符直到遇到已定义的PHP标签规则时终止。
问题原因
原规则中的.+?是非贪婪匹配,它会尽可能少地匹配字符——由于没有明确的终止条件,ANTLR会每次只匹配一个字符就生成Token,最终导致每个HTML字符都被拆分成独立的T_INLINE_HTML。
解决方案
修改T_INLINE_HTML的规则,使用贪婪匹配并通过否定预查明确终止条件:匹配所有字符,直到即将出现PHP开标签(<?=或<?php)为止。
修改后的完整词法规则:
lexer grammar PhpLexer; options { superClass = PhpLexerBase; caseInsensitive = true; } T_OPEN_TAG_WITH_ECHO: '<?=' -> pushMode(PHP); T_OPEN_TAG: PhpOpenTag -> pushMode(PHP); // 合并连续HTML内容为单个Token T_INLINE_HTML: ( . (?! PhpTagStart ) )+; mode PHP; T_CLOSE_TAG: '?>'; T_BAD_CHARACTER: .; fragment NEWLINE: '\r'? '\n' | '\r'; // 统一定义PHP标签的起始序列 fragment PhpTagStart : '<?=' | '<?php' ; fragment PhpOpenTag : '<?php' ([ \t] | NEWLINE) | '<?php' EOF ;
规则说明
(?! PhpTagStart)是否定预查,确保当前位置之后不会出现PHP标签的起始序列;- 外层的
( . ... )+是贪婪匹配,会尽可能多地消费字符,直到遇到PHP标签起始或文件结束,从而将连续的HTML内容合并为单个T_INLINE_HTMLToken。
内容的提问来源于stack exchange,提问作者eaglewu
相关产品推荐
相关产品推荐

