Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在antlr4中精确解析n个参数_Python_Python 3.x_Grammar_Antlr4 - Fatal编程技术网

Python 在antlr4中精确解析n个参数

Python 在antlr4中精确解析n个参数,python,python-3.x,grammar,antlr4,Python,Python 3.x,Grammar,Antlr4,我将Antlr4与python3运行时一起使用。在我试图解析的语言中,有许多操作(大约50个)以OPNAME[parameter1,parameter2,parameter3] 我以前的语法规则是这样的: statement: OP1 '[' NUM ']' | OP2 '[' NUM ',' NUM ']' | OP3 '[' NUM ',' NUM ',' NUM ']' | OP2or3 (('[' NUM ',' NUM ']')|('[' NUM ',' NUM

我将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);
但是,为了更清楚,我决定创建一个子规则
parameter[n]
,它完全接受
n
参数。因此,我的(完整示例)语法如下所示:

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);
在下面的
testfile.txt
上运行此语法几乎可以正常工作。我在OP1、OP2和OP3中测试了或多或少的参数,如果我没有确切的对应数量的参数,那么就失败了但是,这对OP2or3不起作用,因为OP2or3对3个参数总是失败。我猜antlr解析器首先尝试使用两个参数进行检查,使谓词失败,然后又无法正确回溯(错误消息是[5:16]处的
error]:规则参数失败的谓词:{$I==$n}?
)。
testfile.txt的内容

OP1 [1] 
OP2 [32, 52]
OP3 [1, 2, 3]
OP2or3 [1, 2]
OP2or3 [1, 2, 3]
我试图用一个更明确的规则替换入口处的谓词,但这仍然不起作用(错误消息是[5:7]处的
错误:在输入“[]”处没有可行的替代方法。

以下是我用来测试语法的python代码:

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))
这是我的
Makefile

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
parameter[n]
locals[i = 1]
    : '[' NUM
        ( ',' NUM {$i += 1} )*
      ']'
      {($i == $n or $i in $n)}?
    ;

您是否知道我是否可以制定一个规则
参数[n]
,该规则也适用于
OP2or3
在一个经常变化的规则上,拥有该子规则确实有助于提高清晰度(有些操作符每隔几个月就会添加或删除一次)

很抱歉打扰了任何人看我的问题,但我自己用python魔法找到了答案。也许有一天这会对某人有所帮助。我修改了
参数[n]
,将
int
元组作为输入:

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
parameter[n]
locals[i = 1]
    : '[' NUM
        ( ',' NUM {$i += 1} )*
      ']'
      {($i == $n or $i in $n)}?
    ;
请注意语义谓词中的括号。您需要将这些括号置于python解析器中,因为它将被翻译为
not(i==n或i in n)
,并且没有不能正确否定的括号(我想这可能被视为antlr4错误)

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

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>)
$python3 test\u grammar.py testfile.txt-p
(程序(语句OP1(参数[1]))
(语句OP2(参数[32,52]))
(语句OP3(参数[1,2,3]))
(语句OP2or3(参数[1,2]))
(语句OP2or3(参数[1,2,3]))
)