两个基本的 ANTLR 问题

2024-05-07

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

许多教程看起来非常复杂或详细阐述与我无关的事情;我真的只需要一些非常简单的功能。所以我有两个问题:

将值从一个规则“返回”到另一规则。

假设我有这样的规则:

赋值:name=IDENTIFIER ASSIGNMENT 表达式;

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

赋值:名称=IDENTIFIER ASSIGNMENT 表达式[变量列表];

and then

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

但是我如何将值“返回”到原来的规则呢?例如。如何计算表达式的值,然后将其发送回我的赋值规则以在 Python 中使用?

如何写出我的目标语言代码?

所以我有一些Python,它在识别规则时运行,然后我计算我想要该语句生成的程序集。但是我怎么说“将这串汇编指令写到我的目标文件中”呢?

任何与此类内容相关的优秀教程(属性语法、编译为 AST 以外的内容等)也会有所帮助。如果我的问题没有太多意义,请让我澄清;我很难理解 ANTLR。



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

假设您想要解析简单的表达式并在运行时提供可在这些表达式中使用的变量映射。一个简单的语法,包括自定义 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

两个基本的 ANTLR 问题 的相关文章

随机推荐