我正在使用 parser grammar和 lexer grammar用于来自 GitHub 的 antlr4 以在 Python3 中解析 PHP。
当我直接使用这些语法时,我的 PoC 代码可以工作:
antlr-test.py
from antlr4 import *
# from PHPParentLexer import PHPParentLexer
# from PHPParentParser import PHPParentParser
# from PHPParentParser import PHPParentListener
from PHPLexer import PHPLexer as PHPParentLexer
from PHPParser import PHPParser as PHPParentParser
from PHPParser import PHPParserListener as PHPParentListener
class PhpGrammarListener(PHPParentListener):
def enterFunctionInvocation(self, ctx):
print("enterFunctionInvocation " + ctx.getText())
if __name__ == "__main__":
scanner_input = FileStream('test.php')
lexer = PHPParentLexer(scanner_input)
stream = CommonTokenStream(lexer)
parser = PHPParentParser(stream)
tree = parser.htmlDocument()
walker = ParseTreeWalker()
printer = PhpGrammarListener()
walker.walk(printer, tree)
给出输出
/opt/local/bin/python3.4 /Users/d/PycharmProjects/name/antlr-test.py
enterFunctionInvocation echo("hi")
enterFunctionInvocation another_method("String")
enterFunctionInvocation print("print statement")
Process finished with exit code 0
当我使用下面的 PHPParent.g4 语法时,我得到了很多错误:
grammar PHPParent;
options { tokenVocab=PHPLexer; }
import PHPParser;
在 pythons 导入上交换注释后,我收到此错误
/opt/local/bin/python3.4 /Users/d/PycharmProjects/name/antlr-test.py
line 1:1 token recognition error at: '?'
line 1:2 token recognition error at: 'p'
line 1:3 token recognition error at: 'h'
line 1:4 token recognition error at: 'p'
line 1:5 token recognition error at: '\n'
...
line 2:8 no viable alternative at input '<('
line 2:14 mismatched input ';' expecting {<EOF>, '<', '{', '}', ')', '?>', 'list', 'global', 'continue', 'return', 'class', 'do', 'switch', 'function', 'break', 'if', 'for', 'foreach', 'while', 'new', 'clone', '&', '!', '-', '~', '@', '$', <INVALID>, 'Interface', 'abstract', 'static', Array, RequireOperator, DecimalNumber, HexNumber, OctalNumber, Float, Boolean, SingleQuotedString, DoubleQuotedString_Start, Identifier, IncrementOperator}
line 3:28 mismatched input ';' expecting {<EOF>, '<', '{', '}', ')', '?>', 'list', 'global', 'continue', 'return', 'class', 'do', 'switch', 'function', 'break', 'if', 'for', 'foreach', 'while', 'new', 'clone', '&', '!', '-', '~', '@', '$', <INVALID>, 'Interface', 'abstract', 'static', Array, RequireOperator, DecimalNumber, HexNumber, OctalNumber, Float, Boolean, SingleQuotedString, DoubleQuotedString_Start, Identifier, IncrementOperator}
line 4:28 mismatched input ';' expecting {<EOF>, '<', '{', '}', ')', '?>', 'list', 'global', 'continue', 'return', 'class', 'do', 'switch', 'function', 'break', 'if', 'for', 'foreach', 'while', 'new', 'clone', '&', '!', '-', '~', '@', '$', <INVALID>, 'Interface', 'abstract', 'static', Array, RequireOperator, DecimalNumber, HexNumber, OctalNumber, Float, Boolean, SingleQuotedString, DoubleQuotedString_Start, Identifier, IncrementOperator}
但是,在语法上运行 antlr4 工具时,我没有收到任何错误。我被难住了 - 是什么导致了这个问题?
$ a4p PHPLexer.g4
warning(146): PHPLexer.g4:363:0: non-fragment lexer rule DoubleQuotedStringBody can match the empty string
$ a4p PHPParser.g4
warning(154): PHPParser.g4:523:0: rule doubleQuotedString contains an optional block with at least one alternative that can match an empty string
$ a4p PHPParent.g4
warning(154): PHPParent.g4:523:0: rule doubleQuotedString contains an optional block with at least one alternative that can match an empty string
最佳答案
导入是 ANTLR4 有点乱。
首先,tokenVocab
无法生成你需要的词法分析器。它只是意味着这个语法正在使用 PHPLexer
的标记。如果你删除 PHPLexer.tokens
,它甚至不会编译!
看看 PHPParser.g4
,我们也使用 options { tokenVocab=PHPLexer; }
。然而在 python 脚本中,我们仍然需要使用来自 PHPLexer
的词法分析器来使其工作。好吧,这个 PHPParentLexer
根本不可用。这就是为什么你得到了所有的错误。
要从组合语法中生成新的词法分析器,您需要像这样导入它:
grammar PHPParent;
import PHPLexer;
但是,导入时不支持mode
。 PHPLexer
本身就大量使用了mode
。所以这也不是一个选择。
我们可以简单地将 PHPParentLexer
替换为 PHPLexer
吗?可悲的是没有。因为 PHPParentParser
是用 PHPParentLexer
生成的,所以它们是紧耦合的,不能单独使用。如果您使用 PHPLexer
,PHPParentParser
也将不起作用。至于这个语法,感谢错误恢复,它确实有效,但给出了一些错误。
似乎没有更好的办法,只能重写一些语法。 ANTLR4的这个import
部分肯定有一些设计问题。
关于python - 导入后ANTLR4语法标记识别错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29630026/