变量未传递给ANTLR中的谓词方法

时间:2011-09-22 07:23:56

标签: antlr

从ANTLR生成的java代码是一条规则,大多数时候都是一种方法。但是对于以下规则:

switchBlockLabels[ITdcsEntity _entity,TdcsMethod _method,List<IStmt> _preStmts]
    :   ^(SWITCH_BLOCK_LABEL_LIST switchCaseLabel[_entity, _method, _preStmts]* switchDefaultLabel? switchCaseLabel*)
    ;

它生成一个名为synpred125_TreeParserStage3_fragment()的子方法,其中调用了switchCaseLabel(_entity, _method, _preStmts)

synpred125_TreeParserStage3_fragment(){
    ......
    switchCaseLabel(_entity, _method, _preStmts);//variable not found error        
    ......
}

switchBlockLabels(ITdcsEntity _entity,TdcsMethod _method,List<IStmt> _preStmts){
    ......
    synpred125_TreeParserStage3_fragment();
    ......
}

问题是switchCaseLabel有参数且参数来自switchBlockLabels()方法的参数,因此发生“未找到变量错误”。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

我的猜测是你已经在语法中启用了全局回溯:

options {
  backtrack=true;
}

在这种情况下,您无法将参数传递给不明确的规则。要在启用全局回溯时在不明确的规则之间进行通信,必须使用规则范围。 “谓词方法”可以访问规则范围变量。


演示

假设我们有这种含糊不清的语法:

grammar Scope;

options { 
  backtrack=true;
}

parse
  :  atom+ EOF
  ;

atom
  :  numberOrName+
  ;

numberOrName
  :  Number
  |  Name
  ;

Number : '0'..'9'+;
Name   : ('a'..'z' | 'A'..'Z')+;
Space  : ' ' {skip();};

(对于记录,atom+numberOrName+会使其模糊不清)

如果你现在想要在parsenumberOrName规则之间传递信息,比如整数n,那么这样的事情就会失败(这是你试过的方式):< / p>

grammar Scope;

options { 
  backtrack=true;
}

parse
@init{int n = 0;}
  :  (atom[++n])+ EOF
  ;

atom[int n]
  :  (numberOrName[n])+
  ;

numberOrName[int n]
  :  Number {System.out.println(n + " = " + $Number.text);}
  |  Name   {System.out.println(n + " = " + $Name.text);}
  ;

Number : '0'..'9'+;
Name   : ('a'..'z' | 'A'..'Z')+;
Space  : ' ' {skip();};

为了使用规则范围执行此操作,您可以这样做:

grammar Scope;

options { 
  backtrack=true;
}

parse
scope{int n;         /* define the scoped variable          */ }
@init{$parse::n = 0; /* important: initialize the variable! */ }
  :  atom+ EOF
  ;

atom
  :  numberOrName+
  ;

numberOrName /* increment and print the scoped variable from the parse rule */
  :  Number {System.out.println(++$parse::n + " = " + $Number.text);} 
  |  Name   {System.out.println(++$parse::n + " = " + $Name.text);}
  ;

Number : '0'..'9'+;
Name   : ('a'..'z' | 'A'..'Z')+;
Space  : ' ' {skip();};

测试

如果您现在运行以下类:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String src = "foo 42 Bar 666";
    ScopeLexer lexer = new ScopeLexer(new ANTLRStringStream(src));
    ScopeParser parser = new ScopeParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

您将看到以下内容正在打印到控制台:

1 = foo
2 = 42
3 = Bar
4 = 666

P.S。

我不知道你正在解析什么语言,但启用全局回溯通常是过度的,并且会对解析器的性能产生很大影响。在少数情况下,计算机语言通常是模糊的。您应该考虑添加语法谓词,或者启用那些不明确的规则的回溯,而不是启用全局回溯。有关详细信息,请参阅The Definitive ANTLR Reference