将值从一个规则返回到另一规则
假设您想要解析简单的表达式并在运行时提供可在这些表达式中使用的变量映射。一个简单的语法,包括自定义 Python 代码,returns
规则中的语句和参数vars
语法的入口点可能如下所示:
grammar T;
options {
language=Python;
}
@members {
variables = {}
}
parse_with [vars] returns [value]
@init{self.variables = vars}
: expression EOF {value = $expression.value}
;
expression returns [value]
: addition {value = $addition.value}
;
addition returns [value]
: e1=multiplication {value = $e1.value}
( '+' e2=multiplication {value = value + $e2.value}
| '-' e2=multiplication {value = value - $e2.value}
)*
;
multiplication returns [value]
: e1=unary {value = $e1.value}
( '*' e2=unary {value = value * $e2.value}
| '/' e2=unary {value = value / $e2.value}
)*
;
unary returns [value]
: '-' atom {value = -1 * $atom.value}
| atom {value = $atom.value}
;
atom returns [value]
: Number {value = float($Number.text)}
| ID {value = self.variables[$ID.text]}
| '(' expression ')' {value = $expression.value}
;
Number : '0'..'9'+ ('.' '0'..'9'+)?;
ID : ('a'..'z' | 'A'..'Z')+;
Space : ' ' {$channel=HIDDEN};
如果您现在使用 ANTLR v3.1.3(没有更高版本!)生成解析器:
java -cp antlr-3.1.3.jar org.antlr.Tool T.g
并运行脚本:
#!/usr/bin/env python
import antlr3
from antlr3 import *
from TLexer import *
from TParser import *
input = 'a + (1.0 + 2) * 3'
lexer = TLexer(antlr3.ANTLRStringStream(input))
parser = TParser(antlr3.CommonTokenStream(lexer))
print '{0} = {1}'.format(input, parser.parse_with({'a':42}))
您将看到打印以下输出:
a + (1.0 + 2) * 3 = 51.0
请注意,您可以定义多个“返回”类型:
parse
: foo {print 'a={0} b={1} c={2}'.format($foo.a, $foo.b, $foo.c)}
;
foo returns [a, b, c]
: A B C {a=$A.text; b=$B.text; b=$C.text}
;
如何写出目标语言代码
最简单的方法就是简单地把print
自定义代码块内的语句并将输出通过管道传输到文件:
parse_with [vars]
@init{self.variables = vars}
: expression EOF {print 'OUT:', $expression.value}
;
然后像这样运行脚本:
./run.py > out.txt
这将创建一个文件“out.txt”,其中包含:OUT: 51.0
。如果你的语法不是那么高,你可能会侥幸逃脱。但是,这可能会变得有点混乱,在这种情况下,您可以将解析器的输出设置为template
:
options {
output=template;
language=Python;
}
并通过您自己定义的模板发出自定义代码。
See:
- StringTemplate:5 分钟简介 http://www.antlr.org/wiki/display/ST/Five+minute+Introduction
- 哪里可以获取Python ANTLR包来使用StringTemplate? https://stackoverflow.com/questions/5198902/where-to-get-python-antlr-package-to-use-stringtemplate