当前位置: 首页 > 知识库问答 >
问题:

antlr4中n个参数的精确解析

太叔英卫
2023-03-14

我将Antlr4与python3运行时一起使用。在我试图解析的语言中,有许多操作(大约50个)接受固定数量的参数,其形式为opname[parameter1,parameter2,parameter3]

我以前有一个语法,规则是这样的:

statement: OP1 '[' NUM ']'
    | OP2 '[' NUM ',' NUM ']'
    | OP3 '[' NUM ',' NUM ',' NUM ']'
    | OP2or3 (('[' NUM ',' NUM ']')|('[' NUM ',' NUM ',' NUM ']'))
    ;
grammar test;

program: (statement? NEWLINE)* EOF;

statement: OP1 parameter[1]
    | OP2 parameter[2]
    | OP3 parameter[3]
    | OP2or3 (parameter[2]|parameter[3])
    ;

parameter[n]
locals[i = 1]
    : '[' NUM 
        ( ',' NUM {$i += 1} )*
      ']' 
      {$i == $n}?
    ;



OP1     : 'OP1'     ;
OP2     : 'OP2'     ;
OP3     : 'OP3'     ;
OP2or3  : 'OP2or3'  ;

NUM     : ('0'..'9')+;
NEWLINE : '\n'      ;
WS      : [ \t\r] -> channel(1);
OP1 [1] 
OP2 [32, 52]
OP3 [1, 2, 3]
OP2or3 [1, 2]
OP2or3 [1, 2, 3]
parameter[n]
    : {$n == 1}? '[' NUM ']'
    | {$n == 2}? '[' NUM ',' NUM ']'
    | {$n == 3}? '[' NUM ',' NUM ',' NUM ']'
    ;
import codecs
from antlr4 import *
from antlr4.error.ErrorListener import ErrorListener
from testParser import testParser as Parser
from testLexer import testLexer as Lexer

class SimpleErrorThrower(ErrorListener):
    def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
        msg = msg.replace('\n', '\\n')
        raise RuntimeError("Error at [%s:%s] : %s" % (line, column, msg))

def load_code(filename):
    return codecs.decode(open(filename, 'rb').read(), 'utf-8')

def ParseFromRule(input_string, rule_to_call='program'):
    '''Try to parse a given string (case insensitive) from a given rule.
        Raises 'AttrivuteError' if rule does not exist.
        Raises 'ParsingException' if parsing failed.
        Returns the parse tree if parsing was successfull.'''
    source = InputStream(input_string)
    lexer = Lexer(source)
    stream = CommonTokenStream(lexer)
    parser = Parser(stream)
    parser.removeErrorListeners()
    parser.addErrorListener(SimpleErrorThrower())
    parseTree = getattr(parser, rule_to_call)()
    return parseTree


if __name__ == '__main__':
    from argparse import ArgumentParser

    args = ArgumentParser()
    args.add_argument("-p", "--print", help="Print resulting tree.", action='store_true')
    args.add_argument("filename", metavar="Source filename", help="file containing the code to test.", type=str)
    options = args.parse_args()

    input_string = load_code(options.filename)
    try:
        tree = ParseFromRule(input_string, 'program')
    except RuntimeError as e:
        print(str(e))
        exit(1)

    if options.print:
        print(tree.toStringTree(recog=tree.parser))
ANTLR_CP=/usr/local/bin/antlr-4.5.1-complete.jar
ANTLR=java -Xmx500M -cp "$(ANTLR_CP):$$CLASSPATH" org.antlr.v4.Tool

all: testParser.py

clean:
    rm -f *Lexer.py *Listener.py *Parser.py *.tokens *.pyc

testParser.py: *.g4
    $(ANTLR) -Dlanguage=Python3 test.g4

您是否知道我是否可以创建一个规则参数[n],该规则也适用于op2or3?根据一个经常变化的规则(每隔几个月就会添加或删除一些操作符),拥有这个子库确实有助于清晰

共有1个答案

寿元白
2023-03-14

好吧,很抱歉打扰任何人看我的问题,但我自己找到了一个答案,使用python魔法。也许哪天能帮到某人。我重新处理了参数[n],以接受int元组:

parameter[n]
locals[i = 1]
    : '[' NUM
        ( ',' NUM {$i += 1} )*
      ']'
      {($i == $n or $i in $n)}?
    ;

注意语义谓词中的括号。您需要将thoses放入括号,因为它将在python解析器中被翻译为not(i==n或i in n),如果没有括号,将不会被正确地否定(我想这可能被视为antlr4 bug。)

因此,现在我的陈述规则是:

statement: OP1 parameter[1]
    | OP2 parameter[2]
    | OP3 parameter[3]
    | OP2or3 parameter[(2, 3)]
    ;

我的测试文件中的工作:

$ python3 test_grammar.py testfile.txt -p
(program (statement OP1 (parameter [ 1 ]))
(statement OP2 (parameter [ 32 , 52 ]))
(statement OP3 (parameter [ 1 , 2 , 3 ]))
(statement OP2or3 (parameter [ 1 , 2 ]))
(statement OP2or3 (parameter [ 1 , 2 , 3 ]))
<EOF>)
 类似资料:
  • 我正在寻找Python的第n个根函数/算法,但在发布之前:没有整数根,见鬼 我从哪里至少可以获得一个指南,指导如何编程生成精确的/ 对于(第一个参数是数字,第二个参数是根深度(或其他内容))不返回或的函数。 编辑:所以,你给了我这个解决方案:,当我问这个问题时,我就知道了,但它不适用于,例如,。你不能用有理数来表示,因此给出了不正确的结果

  • 我可以在parser中而不是在lexer中定义范围吗?

  • 我正在通过自定义语法处理输入文件,提取标记,并在中返回它们。在ANTLR 3中,我能够通过调用解析器上的方法来解析文件,并获得类似于。 这在ANTLR 4中似乎不起作用。我参考了这本书,似乎我必须调用开始解析,但我在解析器中没有看到任何方法。 我使用ANTLRWorks 2生成我的词法分析器和解析器文件。我没有生成侦听器类。

  • 可能在内部使用的代码将在规则之后被取消,如下所示: ANTLR4就是这样做事的吗?