两个基本的 ANTLR 问题 [英] Two basic ANTLR questions

查看:24
本文介绍了两个基本的 ANTLR 问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ANTLR 来采用简单的语法并生成汇编输出.我在 ANTLR 中选择的语言是 Python.

I'm trying to use ANTLR to take a simple grammar and produce assembly output. My language of choice in ANTLR is Python.

许多教程看起来很复杂,或者对与我无关的事情进行了详细说明;我只需要一些非常简单的功能.所以我有两个问题:

Many tutorials seem very complicated or elaborate on things that aren't relevant to me; I only really need some very simple functionality. So I have two questions:

将值从一个规则返回"到另一个.

假设我有一个规则:

赋值:name=IDENTIFIER ASSIGNMENT 表达式;

assignment: name=IDENTIFIER ASSIGNMENT expression;

当此规则被识别时,我可以在 {} 中运行 Python 代码,并且我可以通过执行以下操作将 args 传递给 Python 代码以进行表达式:

I can run Python code in {}s when this rule is recognised, and I can pass args to the Python code for expression by doing something like:

赋值:name=IDENTIFIER ASSIGNMENT 表达式[variablesList];

assignment: name=IDENTIFIER ASSIGNMENT expression[variablesList];

然后

表达式[变量列表]:等等

expression[variablesList]: blah blah

但是我如何将一个值返回"到我的原始规则中?例如.如何计算表达式的值,然后将其发送回我的赋值规则以在 Python 中使用?

But how do I 'return' a value to my original rule? E.g. how do I calculate the value of the expression and then send it back to my assignment rule to use in Python there?

如何写出目标语言代码?

所以我有一些 Python 在识别规则时运行,然后我计算我希望该语句生成的程序集.但是我怎么说把这串汇编指令写到我的目标文件中"?

So I have some Python which runs when the rules are recognised, then I calculate the assembly I want that statement to produce. But how do I say "write out this string of assembly instructions to my target file"?

任何与此类内容(属性语法、编译为 AST 以外的内容等)相关的优秀教程也会有所帮助.如果我的问题没有太大意义,请要求我澄清;我很难把头放在 ANTLR 上.

Any good tutorials that are relevant to this kind of stuff (attribute grammars, compiling to something other than an AST, etc.) would be helpful too. If my questions don't make too much sense, please ask me to clarify; I'm having a hard time wrapping my head around ANTLR.

推荐答案


假设您想解析简单的表达式并在运行时提供可用于这些表达式的变量映射.包含自定义 Python 代码、规则中的 returns 语句以及语法入口点的参数 vars 的简单语法可能如下所示:

Let's say you want to parse simple expressions and provide a map of variables at runtime that can be used in these expressions. A simple grammar including the custom Python code, returns statements from the rules, and the parameter vars to the entry point of your grammar could look like this:

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(没有更高版本!)生成解析器:

If you now generate a parser using ANTLR v3.1.3 (no later version!):

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}))

您将看到以下输出正在打印:

you will see the following output being printed:

a + (1.0 + 2) * 3 = 51.0

请注意,您可以定义多个返回"类型:

Note that you can define more than a single "return" type:

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 语句放在自定义代码块中并将输出通过管道传输到文件:

The easiest to go about this is to simply put print statements inside the custom code blocks and pipe the output to a file:

parse_with [vars]
@init{self.variables = vars}
  :  expression EOF                            {print 'OUT:', $expression.value}
  ;

然后像这样运行脚本:

./run.py > out.txt

这将创建一个文件out.txt",其中包含:OUT: 51.0.如果你的语法不是那么大,你可能会逃脱这个.但是,这可能会变得有点混乱,在这种情况下,您可以将解析器的输出设置为 template:

which will create a file 'out.txt' containing: OUT: 51.0. If your grammar isn't that big, you might get away with this. However, this might become a bit messy, in which case you could set the output of your parser to template:

options {
  output=template;
  language=Python;
}

并通过您自己定义的模板发出自定义代码.

and emit custom code through your own defined templates.

见:

这篇关于两个基本的 ANTLR 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆