antlr4 python 3 печатает или выводит токены из грамматики plsql - PullRequest
0 голосов
/ 06 октября 2018

Я использую antlr4 в Python для чтения следующей грамматики:

https://github.com/antlr/grammars-v4/tree/master/plsql

файл grants.sql просто имеет "begin select 'bob" from dual; end; "

простой код для печати lisp-подобного дерева

from antlr4 import *
from PlSqlLexer import PlSqlLexer
from PlSqlParser import PlSqlParser
from PlSqlParserListener import PlSqlParserListener

input = FileStream('grants.sql')
lexer = PlSqlLexer(input)

stream = CommonTokenStream(lexer)
parser = PlSqlParser(stream)
tree = parser.sql_script()

print ("Tree " + tree.toStringTree(recog=parser));

Вывод такой:

Дерево (sql_script (unit_statement (anonymous_block BEGIN (seq_of_statements (оператор (sql_statement (data_manipulation_language_statements)подзапрос (subquery_basic_elements (query_block SELECT (selected_element (select_list_elements (выражения (выражение (logic_expression (multiset_expression (отношение_экспрессия (составное_экспрессия (соединение_экспрессия (модель-выражение)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) (from_clause FROM (table_ref_list (table_ref (table_ref_aux (table_ref_aux_internal) (dml_table_expression_clause (tableview_name (идентификатор (id_expression (valid_id DUAL)))))))))))))))))) )3))))))

Я хотел бы иметь возможность иметь код на Python, в котором перечислено нев похожем на lisp утверждении, но перечисляет все правила и токены .. т.е.

  1. .sql_script
  2. .. unit_statement
  3. ... anonymous_block
  4. .... НАЧАЛО

и т. Д.

Может кто-нибудь предоставить код Python, который делает это, или дать мне несколько советов.С благодарностью признателен.

1 Ответ

0 голосов
/ 10 октября 2018

Вот начало:

from antlr4 import *
from antlr4.tree.Tree import TerminalNodeImpl
from PlSqlLexer import PlSqlLexer
from PlSqlParser import PlSqlParser

# Generate the lexer nad parser like this:
#
#   java -jar antlr-4.7.1-complete.jar -Dlanguage=Python3 *.g4
#
def main():
    lexer = PlSqlLexer(InputStream("SELECT * FROM TABLE_NAME"))
    parser = PlSqlParser(CommonTokenStream(lexer))
    tree = parser.sql_script()
    traverse(tree, parser.ruleNames)

def traverse(tree, rule_names, indent = 0):
    if tree.getText() == "<EOF>":
        return
    elif isinstance(tree, TerminalNodeImpl):
        print("{0}TOKEN='{1}'".format("  " * indent, tree.getText()))
    else:
        print("{0}{1}".format("  " * indent, rule_names[tree.getRuleIndex()]))
        for child in tree.children:
            traverse(child, rule_names, indent + 1)

if __name__ == '__main__':
    main()

, которое печатает:

sql_script
  unit_statement
    data_manipulation_language_statements
      select_statement
        subquery
          subquery_basic_elements
            query_block
              TOKEN='SELECT'
              TOKEN='*'
              from_clause
                TOKEN='FROM'
                table_ref_list
                  table_ref
                    table_ref_aux
                      table_ref_aux_internal
                        dml_table_expression_clause
                          tableview_name
                            identifier
                              id_expression
                                regular_id
                                  TOKEN='TABLE_NAME'

Обратите внимание, что для правильной работы лексера и анализатора я добавил следующие классы Python:

# PlSqlBaseLexer.py
from antlr4 import *

class PlSqlBaseLexer(Lexer):

    def IsNewlineAtPos(self, pos):
        la = self._input.LA(pos)
        return la == -1 or la == '\n'

и:

# PlSqlBaseParser.py
from antlr4 import *

class PlSqlBaseParser(Parser):

    _isVersion10 = False
    _isVersion12 = True

    def isVersion10(self):
        return self._isVersion10

    def isVersion12(self):
        return self._isVersion12

    def setVersion10(self, value):
        self._isVersion10 = value

    def setVersion12(self, value):
        self._isVersion12 = value

, которые я поместил в ту же папку, что и сгенерированные классы Python.Мне также нужно было добавить оператор импорта from PlSqlBaseLexer import PlSqlBaseLexer в сгенерированный класс PlSqlLexer.py и исправить оператор импорта в PlSqlParser.py с from ./PlSqlBaseParser import PlSqlBaseParser до from PlSqlBaseParser import PlSqlBaseParser.

Обратите внимание, что запуск демо-версии довольномедленный.Если у вас нет строгих требований сделать это в Python, я рекомендую вместо этого использовать (намного!) Более быструю цель Java или C #.

...