2012-02-02 67 views
1

我使用從CommonTree派生的自定義AST節點類型構建了AST。如何避免在使用自定義AST節點類型進行樹過濾時拋出ClassCastException?

這似乎工作正常,直到我使用包含*通配符的樹過濾語法。

this頁的評論認爲,這是不得不做的代碼引起的:

(MyCustomType)input.LT(1); 

此拋出,當它遇到一個向上或向下的節點,因爲它們是類CommonTree的。 評論中的解決方案是針對可選(?)元素,但我真的需要一種使用*通配符來捕獲事物列表的方法,而不用拋出它。

編輯:

這是示出了我有問題的一個小例子。

source.txt顯示了我需要解析的幾個例子。 問題來了,當我去使用樹沃克重寫任何陣列分配(第3行source.txt)調用功能的數組對象。

使用source.txt運行以下代碼會導致節點類型之間出現ClassCastException。

Sccee.g:

grammar Sscce; 

options 
{ 
    output = AST; 
    ASTLabelType = SscceAST; 
} 

tokens 
{ 
    ASSIGN; 
    ARGS; 
    FUNCCALL; 
    REF; 
    INDEXOP; 
} 


@lexer::header 
{ 
package com.dummyco.dummypack; 
} 

@parser::header 
{ 
package com.dummyco.dummypack; 
} 

stmts: singleStatement+ 
    ; 

singleStatement 
    : memberExpression '=' (expr | listAssignment) -> 
    ^(ASSIGN '=' memberExpression expr? listAssignment?) 
    ; 

expr 
    : memberExpression 
    | functionCall 
    ; 

functionCall 
    : memberExpression args -> ^(FUNCCALL args) 
    ; 

args 
    : '(' memberExpression? (',' memberExpression)* ')' -> 
     ^(ARGS memberExpression*) 
    ; 

indexSuffix: 
    '[' ID? ']' -> ^(INDEXOP ID?) 
    ; 

memberExpression 
    : ID ('.' ID)* indexSuffix? -> ^(REF ID+ indexSuffix?) 
    ; 

idList 
    : memberExpression (',' memberExpression)* -> memberExpression+ 
    ; 

listAssignment 
    : '{' idList '}' -> ^(ARGS idList) 
    ; 

assignmentOperator 
    : '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|=' 
    ; 

ID : ('a'..'z'|'A'..'Z'|'_')*emphasized text* ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* { setText(getText().toLowerCase()); } 
    ; 

WS : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;} 
    ; 

SscceWalker.g:

tree grammar SscceWalker; 

options 
{ 
    output = AST; 
    ASTLabelType = SscceAST; 
    tokenVocab = Sscce; 
    filter = true; 
} 

@header 
{ 
    package com.dummyco.dummypack; 
} 

topdown 
    : arrayAssignment 
    ; 

arrayAssignment 
    : ^(ASSIGN '=' ^(REF memexp+=.* INDEXOP) ^(ARGS args+=.*)) -> 
     ^(FUNCCALL ^(REF $memexp*) ID["push"] ^(ARGS $args*)) 
    ; 

Main.java:

package com.dummyco.dummypack; 

import java.io.*; 
import java.util.*; 
import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 

public class Main 
{ 

    private static final TreeAdaptor sscceAdaptor = new CommonTreeAdaptor() 
    { 
     @Override 
     public Object create(Token token) 
     { 
      return new SscceAST(token); 
     } 

     @Override 
     public Object dupNode(Object t) 
     { 
      if(t == null) 
       return null; 

      return create(((SscceAST)t).token); 
     } 

     @Override 
     public Object errorNode(TokenStream input, Token start, Token stop, RecognitionException e) 
     { 
      return new SscceASTErrorNode(input, start, stop, e); 
     } 
    }; 

    public static void main(String[] args) throws IOException 
    { 

     SscceLexer lexer = null; 
     try 
     { 
      lexer = new SscceLexer(
       new ANTLRFileStream("source.txt", "UTF8")); 
     } 
     catch(IOException e) 
     { 
      System.err.println("Can't open the specified file."); 
      System.exit(1); 
     } 

     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     SscceParser parser = new SscceParser(tokens); 
     parser.setTreeAdaptor(sscceAdaptor); 
     SscceParser.stmts_return r = null; 
     try 
     { 
      r = parser.stmts(); 
     } 
     catch(RecognitionException e) 
     { 
      System.err.println("Parser exception."); 
      System.exit(1); 
     } 

     SscceAST t = (SscceAST)r.getTree(); 
     CommonTreeNodeStream nodes = new CommonTreeNodeStream(t); 
     nodes.setTokenStream(tokens); 
     SscceWalker walker = new SscceWalker(nodes); 
     walker.setTreeAdaptor(sscceAdaptor); 
     t = (SscceAST)walker.downup(t, false); 
     System.out.println(t.toStringTree()); 
    } 
} 

SscceAST.java:

package com.dummyco.dummypack; 

import org.antlr.runtime.Token; 
import org.antlr.runtime.tree.Tree; 
import org.antlr.runtime.tree.CommonTree; 

public class SscceAST extends CommonTree 
{ 
    public SscceAST() 
    { 
     super(); 
    } 

    public SscceAST(Token t) 
    { 
     super(t); 
    } 

    public SscceAST(SscceAST tree) 
    { 
     super(tree); 
    } 

    @Override 
    public Tree dupNode() 
    { 
     return new SscceAST(this); 
    } 
} 

SscceeASTErrorNode.java:

package com.dummyco.dummypack; 

import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 

public class SscceASTErrorNode extends SscceAST { 
     public IntStream input; 
     public Token start; 
     public Token stop; 
     public RecognitionException trappedException; 

     public SscceASTErrorNode(TokenStream input, Token start, Token stop, 
                RecognitionException e) 
     { 
       //System.out.println("start: "+start+", stop: "+stop); 
       if (stop==null || 
         (stop.getTokenIndex() < start.getTokenIndex() && 
          stop.getType()!=Token.EOF)) 
       { 
         // sometimes resync does not consume a token (when LT(1) is 
         // in follow set. So, stop will be 1 to left to start. adjust. 
         // Also handle case where start is the first token and no token 
         // is consumed during recovery; LT(-1) will return null. 
         stop = start; 
       } 
       this.input = input; 
       this.start = start; 
       this.stop = stop; 
       this.trappedException = e; 
     } 

     public boolean isNil() { 
       return false; 
     } 

     public int getType() { 
       return Token.INVALID_TOKEN_TYPE; 
     } 

     public String getText() { 
       String badText = null; 
       if (start instanceof Token) { 
         int i = ((Token)start).getTokenIndex(); 
         int j = ((Token)stop).getTokenIndex(); 
         if (((Token)stop).getType() == Token.EOF) { 
           j = ((TokenStream)input).size(); 
         } 
         badText = ((TokenStream)input).toString(i, j); 
       } 
       else if (start instanceof Tree) { 
         badText = ((TreeNodeStream)input).toString(start, stop); 
       } 
       else { 
         // people should subclass if they alter the tree type so this 
         // next one is for sure correct. 
         badText = "<unknown>"; 
       } 
       return badText; 
     } 

     public String toString() { 
       if (trappedException instanceof MissingTokenException) { 
         return "<missing type: "+ 
            ((MissingTokenException)trappedException).getMissingType()+ 
            ">"; 
       } 
       else if (trappedException instanceof UnwantedTokenException) { 
         return "<extraneous: "+ 
            ((UnwantedTokenException)trappedException).getUnexpectedToken()+ 
            ", resync="+getText()+">"; 
       } 
       else if (trappedException instanceof MismatchedTokenException) { 
         return "<mismatched token: "+trappedException.token+", resync="+getText()+">"; 
       } 
       else if (trappedException instanceof NoViableAltException) { 
         return "<unexpected: "+trappedException.token+ 
            ", resync="+getText()+">"; 
       } 
       return "<error: "+getText()+">"; 
     } 
} 

的Source.txt:

this.something = this.somecall(someparam, anotherparam) 
this.dummy1 = this.dummy2 
this.control[]={this.control1, this.control2, this.control3} 
+0

你可以發表演示CCE的[sscce](http://sscce.org)嗎? – 2012-02-03 18:30:25

+0

我一直在試圖把它們放在一起,但我無法按照我的預期複製這個例子中的問題。將繼續工作,並在我到達某個地方後發佈。 – mcnicholls 2012-02-06 12:29:44

+0

我已經添加了一些代碼。對不起,它不是非常緊湊,但我似乎能夠證明這個問題,當我添加了一些基本知識。讓我知道你是否需要其他東西。 – mcnicholls 2012-02-06 14:49:20

回答

0

使用instanceof操作?它用於確定給定的對象是否具有某種類型,並且可以防止在運行時拋出ClassCastExceptions

Object object = input.LT(1); 
if (object instanceof MyCustomType){ 
    MyCustomType type = (MyCustomType)object; 
} 
+0

感謝您的建議,但上面的行出現在生成的代碼中。我真的在尋找一種可以避免這種情況的選項或指定語法的方法。 – mcnicholls 2012-02-02 16:10:21

相關問題