我在python3运行时使用Antlr4。在我尝试分析的语言中,有许多操作(大约50个)接受固定数量的参数,这些参数的形式为OPNAME [ parameter1, parameter2, parameter3 ]
我以前有一个语法规则是这样的:
statement: OP1 '[' NUM ']'
| OP2 '[' NUM ',' NUM ']'
| OP3 '[' NUM ',' NUM ',' NUM ']'
| OP2or3 (('[' NUM ',' NUM ']')|('[' NUM ',' NUM ',' NUM ']'))
;
但是,为了更清楚起见,我决定制定一个子规则parameter[n]
,它完全接受n
参数。因此,我的(完整示例)语法如下所示:
在下面的testfile.txt
上运行此语法几乎可以工作。我测试了OP1、OP2和OP3中或多或少的参数,如果没有对应数量的参数,那就失败了。但是,这对OP2or3不起作用,它总是在3个参数下失败。我猜antlr解析器尝试先用2个参数进行检查,谓词失败,然后无法正确回溯(错误消息是Error at [5:16] : rule parameter failed predicate: {$i == $n}?
)。testfile.txt
的含量:
OP1 [1]
OP2 [32, 52]
OP3 [1, 2, 3]
OP2or3 [1, 2]
OP2or3 [1, 2, 3]
我试图用一个更显式的规则替换入口处的谓词,但仍然不起作用(错误消息是Error at [5:7] : no viable alternative at input '['
)
parameter[n]
: {$n == 1}? '[' NUM ']'
| {$n == 2}? '[' NUM ',' NUM ']'
| {$n == 3}? '[' NUM ',' NUM ',' NUM ']'
;
下面是我用来测试语法的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]
,它也适用于OP2or3
?对于一个经常更改的规则(一些运算符每隔几个月添加或删除一次),使用该子规则确实有助于清晰明了
很抱歉打扰了任何人看我的问题,但是我自己用python魔术找到了答案。也许有一天能帮到别人。我修改了
parameter[n]
以将int
或tuple
作为输入:注意语义谓词中的括号。您需要将这些括号放在python解析器中,因为它将被转换为
not (i == n or i in n)
,如果没有括号,则不能正确地求反(我想这可能被视为antlr4错误)因此,现在我的陈述规则是:
^{pr2}$在我的测试文件中:
相关问题 更多 >
编程相关推荐