Python 如何从ANTLR3中的*规则生成列表?

Python 如何从ANTLR3中的*规则生成列表?,python,parsing,antlr,grammar,antlr3,Python,Parsing,Antlr,Grammar,Antlr3,我的语法如下: grammar Test; options { lang = Python; } declaration returns [value] : 'enum' ID { statement* } { $value = {'id': $ID.text, 'fields': $statement.value} } ; statem

我的语法如下:

grammar Test;

options {
  lang = Python;
}

declaration returns [value]
    :     'enum' ID { statement* }
                 { $value = {'id': $ID.text,
                             'fields': $statement.value}
                 }
    ;

statement returns [value]
    :     ID ':' INT ';' { $value = {'id': $ID.text, 'value': int($INT.text)} }
    ;
要分析类型的语法,请执行以下操作:

enum Test {
  Foo: 3;
  Bar: 5;
}
然而,我正在努力将语句*规则放入语句列表中。我希望最终解析的对象如下所示:

declaration = {
  'id': 'Test',
  'fields': [
    {'id': 'Foo', 'value': 3},
    {'id': 'Bar', 'value': 5},
}
我可以正确解析每个
语句
结果,这样每个
$statement.value
都是正确的。 但是,考虑到规则
声明中
语句*
上的星号,有没有一种方法可以轻松地将其压缩为字段列表?我希望有某种语法可以让我免费使用这个选项

现在,它只接受最后一条语句,因此返回:

declaration = {
  'id': 'Test',
  'fields': [
    {'id': 'Bar', 'value': 5},
}
我想要一个通用的解决方案,因为我的语法有很多形式规则:

some_declaration
      :     keyword ID '{' declaration_statement* '}'
      ;
注意:我是用Python编写的。
我曾尝试将其编码为一个解析器,后跟一个树语法,但即使最后一个元素是我得到的唯一元素,其余元素也会被丢弃。

您可以这样做:

declaration returns [value]
    :     'enum' ID 
                 { $value = {'id': $ID.text,
                             'fields': []}
                 }
           '{' (r=statement
                 { $value['fields'].append($r.value) }
             )*
           '}'
    ;
declaration returns [value]
    :     'enum' ID 
                 { $value = {'id': $ID.text,
                             'fields': []}
                 }
                 { list = $value['fields']
                 }
            '{' statement[list]* '}'
    ;

statement[list]
    :     ID ':' INT ';' { $list.append({'id': $ID.text, 'value': int($INT.text)}) }
    ;
或者,您也可以将字段列表作为参数传递给语句规则,并在其中附加新值。大概是这样的:

declaration returns [value]
    :     'enum' ID 
                 { $value = {'id': $ID.text,
                             'fields': []}
                 }
           '{' (r=statement
                 { $value['fields'].append($r.value) }
             )*
           '}'
    ;
declaration returns [value]
    :     'enum' ID 
                 { $value = {'id': $ID.text,
                             'fields': []}
                 }
                 { list = $value['fields']
                 }
            '{' statement[list]* '}'
    ;

statement[list]
    :     ID ':' INT ';' { $list.append({'id': $ID.text, 'value': int($INT.text)}) }
    ;
这取决于你想要什么,但第一个选择可能更好一些

在这里,您可以找到更多关于将值从一个规则返回到另一个规则的示例:

谢谢。我最终使用了你提到的第一个构造。还有,+=运算符的用法是什么?你是指usng
+=
而不是
append
(例如
$value['fields']+=$r.value
$value['fields']相比。append($r.value)
)?这有点不同,看看啊,不,我是说antlr3+=操作符。我看到了它的一些用法:
c=ID('.'c+=ID)+
Ahha<代码>+=
对于拥有匹配令牌列表或收集AST非常有用,但我认为您不能简单地将其与语法规则结合使用。所以你不能只说
l+=statement
(这里可能需要)。也许,您可以在声明中说
(ids+=ID':'ints+=INT)*
,而不是
语句*
,并处理
ids
ints
列表。但这不是一个好的解决方案;)查看权威ANTLR参考的第4.3节,或者尝试用
ids+=ID
替换
statement
中的
ID
,然后查看生成的Python代码。