ANTLR v.3-使用语法谓词进行前瞻

ANTLR v.3-使用语法谓词进行前瞻,antlr,abstract-syntax-tree,Antlr,Abstract Syntax Tree,仍在学习如何正确使用ANTLR。。。这是我的问题 假设您有一个UML语法的(子集)和一个具有以下规则的ANTLR词法分析器/解析器: // Parser Rules model : 'MODEL' IDENTIFIER list_dec ; list_dec : declaration* ; declaration : class_dec ';' | association ';'

仍在学习如何正确使用ANTLR。。。这是我的问题

假设您有一个UML语法的(子集)和一个具有以下规则的ANTLR词法分析器/解析器:

    // Parser Rules

    model
    :   'MODEL' IDENTIFIER list_dec
    ;

    list_dec
    :   declaration*
    ;

    declaration
    :   class_dec ';' 
    |   association ';' 
    |   generalization ';'
    |   aggregation ';'
    ; 

    class_dec
    :   'CLASS' IDENTIFIER class_content
    ;

    ...

    association
    :   'RELATION' IDENTIFIER 'ROLES' two_roles
    ;

    two_roles
    :   role ',' role
    ;

    role
    :   'CLASS' IDENTIFIER multiplicity
    ;

    ...
我希望“角色”规则仅允许标识符令牌与现有类标识符匹配。换句话说,如果您得到一个输入文件并在其上运行lexer/parser,那么引用的所有类(例如关联规则中的标识符)都应该存在。问题是类在运行时可能不存在(还不存在)(可以在文件中的任何位置声明)。最好的方法是什么


提前感谢…

这可能最好在解析后完成。解析器为您创建某种类型的树,然后遍历该树并收集有关已声明类的信息,然后再次遍历它以验证
角色
树/规则

当然,有些事情可以通过一些自定义代码来完成:

grammar G;

options {
  ...
}

@parser::members {
  java.util.Set<String> declaredClasses = new java.util.HashSet<String>();
}

model
:   'MODEL' IDENTIFIER list_dec
;

...

class_dec
:   'CLASS' id=IDENTIFIER class_content 
    {
      declaredClasses.add($id.text);
    }
;

...

role
:   'CLASS' id=IDENTIFIER multiplicity
    {
      if(!declaredClasses.contains($id.text)) {
        // warning or exception in here
      }
    }
;

...
语法G; 选择权{ ... } @解析器::成员{ java.util.Set declaredClasses=new java.util.HashSet(); } 模型 :“模型”标识符列表\u dec ; ... 十二年级 :“CLASS”id=标识符CLASS\u内容 { declaredClasses.add($id.text); } ; ... 角色 :“CLASS”id=标识符的多重性 { 如果(!declaredClasses.contains($id.text)){ //这里是警告还是例外 } } ; ... 编辑 或使用自定义方法:

@parser::members {
  java.util.Set<String> declaredClasses = new java.util.HashSet<String>();

  void addClass(String id) {
    boolean added = declaredClasses.add(id);
    if(!added) {
      // 'id' was already present, do something, perhaps?
    }
  }

  void checkClass(String id) {
    if(!declaredClasses.contains(id)) {
      // exception, error or warning?
    }
  }
}

...

class_dec
:   'CLASS' id=IDENTIFIER class_content {addClass($id.text);}
;

role
:   'CLASS' id=IDENTIFIER multiplicity {checkClass($id.text);}
;
@parser::members{
java.util.Set declaredClasses=new java.util.HashSet();
void addClass(字符串id){
添加的布尔值=declaredClasses.add(id);
如果(!已添加){
//“id”已经出现了,也许做点什么?
}
}
void checkClass(字符串id){
如果(!declaredClasses.contains(id)){
//异常、错误或警告?
}
}
}
...
十二年级
:'CLASS'id=标识符CLASS_content{addClass($id.text);}
;
角色
:'CLASS'id=标识符的多重性{checkClass($id.text);}
;

这似乎是个好主意。我甚至不知道你可以使用成员变量…我得多读一些!顺便问一下,我可以在members部分添加一些函数来获取/设置变量(例如'DeclaredClass')?或者这被认为是不好的做法?@ALefebvre,是的,你也可以添加方法,也就是说,IMHO,甚至更愿意在自定义代码中尽可能保持语法规则本身为空。你的第二个版本在我的情况下不起作用,因为类可以在文件中的任何位置声明。不过,我确实添加了“addClass”函数,以及一个公共的“getter”,我的树行者将调用该函数以确保所有引用的类都存在。再次感谢您的快速回复。