Подтвердить что ты не робот

Ошибка распознавания маркера ANTLR4 после импорта

Я использую грамматику парсер и лексерную грамматику для antlr4 из GitHub для анализа PHP в Python3,

Когда я использую эти грамматики непосредственно, мой 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
4b9b3361

Ответ 1

Импорт ANTLR4 является довольно грязным.

Во-первых, tokenVocab не может сгенерировать лексер, который вам нужен. Это просто означает, что в этой грамматике используются токены PHPLexer. Если вы удалите PHPLexer.tokens, он даже не будет скомпилирован!

Взгляните на PHPParser.g4, где мы также используем options { tokenVocab=PHPLexer; }. Однако в python script нам все равно нужно использовать lexer из PHPLexer, чтобы он работал. Ну, этот PHPParentLexer не используется вообще. Вот почему вы получили всю ошибку.

Чтобы создать новый лексер из комбинированной грамматики, вам необходимо импортировать его следующим образом:

grammar PHPParent;
import PHPLexer;

Однако при импорте mode не поддерживается. PHPLexer сам использует mode много. Так что это тоже не вариант.

Можно ли просто заменить PHPParentLexer на PHPLexer? К сожалению нет. Поскольку PHPParentParser генерируется с помощью PHPParentLexer, они плотно связаны и не могут использоваться отдельно. Если вы используете PHPLexer, PHPParentParser также не будет работать. Что касается этой грамматики, то благодаря восстановлению ошибок она действительно работает, но дает некоторую ошибку.

Кажется, нет лучшего способа, но переписать часть грамматики. В этой части import ANTLR4 есть определенные проблемы с дизайном.