Возвращение значений из одного правила в другое
Допустим, вы хотите проанализировать простые выражения и предоставить карту переменных во время выполнения, которые можно использовать в этих выражениях.Простая грамматика, включающая пользовательский код 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
Обратите внимание, что вы можете определить более одного типа "return":
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;
}
и генерировать пользовательский код через ваши собственные определенные шаблоны.
См .: