递归下降解析器 - ClassCastException

时间:2015-05-25 17:23:11

标签: java parsing recursion casting recursive-descent

我有一个Recursive Descent Parser项目,我之前发布了一个关于堆栈溢出错误的问题。我已经能够解决这个问题,但它现在返回一个ClassCastException。

从主SWING GUI表单中,我传递输入字符串,然后将其构建为字符串的链接列表。然后我将它传递给parser.java。错误说:

  

java.lang.ClassCastException:java.lang.String无法强制转换为   compilerfinalproject.Token

以下是一些示例输入:

  1. 1 + 2 + 3
  2. (1 + 2) - (3 + 4)
  3. (1 + 2 + 3)* 4
  4. 以下是我的令牌代码。

    import java.util.LinkedList;
    
    public class Tokenizer {
    
        Tokenizer () {} // EMPTY CONSTRUCTOR FOR INSTANTIATION AT CompilerFinal.java
    
        Tokenizer(String expression) { // CONSTRUCTOR FOR CALLING FROM LOCAL Tokenize METHOD
            this.expression = expression.toCharArray(); // SET EXPRESSION TO TOKENIZE
            this.pos = 0; // INITIALIZE AT INDEX 0
        }
    
        int pos; // STRING INDEX DECLARATION
        char[] expression; // EXPRESSION DECLARATION
        LinkedList <String> tokens = new LinkedList<>(); // ARRAYLIST FOR ALL TOKENS
    
        enum tokenClass {PLUS, MINUS, MULTIPLY, DIVIDE, EXPONENT, NUMBER, IDENTIFIER, OPEN, CLOSE, NEGATIVE, DEFAULT} // TOKEN CLASSES (DEFAULT FOR INITIALIZATION PURPOSES ONLY)
    
        class Lexeme { // EACH LEXEME HAS TOKEN CLASS AND TOKEN VALUE
            String tokenClass, token;
            Lexeme(String tokenClass, String token) {
                this.tokenClass = tokenClass;
                this.token = token;
            }
        }
    
        Lexeme getToken() { // METHOD TO GET TOKENS
            StringBuilder token = new StringBuilder(); // BUILDS TOKEN PER CHARACTER
            boolean endOfToken = false; // FLAG WHETHER TO END TOKEN
            tokenClass type = tokenClass.DEFAULT; // DEFAULT VALUE FOR TOKENCLASS
            while (!endOfToken && hasMoreTokens()) // LOOP UNTIL A TOKEN IS COMPLETED
            {
                while(expression[pos] == ' ') // SKIP ALL LEADING SPACES
                    pos++;
                switch (expression[pos]) 
                {
                    case '+': 
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.PLUS; // SET TOKEN CLASS AS OPERATOR
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case '-':
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.MINUS; // SET TOKEN CLASS AS OPERATOR
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case '*':
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.MULTIPLY; // SET TOKEN CLASS AS OPERATOR
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case '/':
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.DIVIDE; // SET TOKEN CLASS AS OPERATOR
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case '^':
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.EXPONENT; // SET TOKEN CLASS AS OPERATOR
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case '(': // OPEN PARENTHESES
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.OPEN; // SET TOKEN CLASS AS OPEN
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case ')': // CLOSE PARENTHESES
                        if(type != tokenClass.NUMBER && type != tokenClass.IDENTIFIER) 
                        {
                            type = tokenClass.CLOSE; // SET TOKEN CLASS AS CLOSE
                            token.append(expression[pos]);
                            pos++;
                        }
                        endOfToken = true; // END TOKEN IMMEDIATELY
                        break;
    
                    case ' ': // SKIP WHITESPACE
                        endOfToken = true;
                        pos++;
                        break;
    
                    default: 
                        if(Character.isDigit(expression[pos]) || expression[pos] == '.') // FOR NUMBERS AND DECIMAL POINTS
                        {
                            token.append(expression[pos]);
                            type = tokenClass.NUMBER; // SET TOKENCLASS AS NUMBER
                        }
                        else if(Character.isAlphabetic(expression[pos])) // FOR IDENTIFIERS
                        {
                            token.append(expression[pos]);
                            type = tokenClass.IDENTIFIER;
                        }
                        pos++; // NO END TOKEN TO TAKE INTO ACCOUNT MULTIPLE DIGIT NUMBERS
                        break;
                }
            }
            return new Lexeme(type.name().toLowerCase(), token.toString());
        }
    
        boolean hasMoreTokens() { // CONDITION CHECKING
            return pos < expression.length;
        }
    
        public LinkedList tokenize (String expression) { // CALLED FROM CompilerFinal.java TO GET TOKENS IN ARRAYLIST
            Tokenizer tokenizer = new Tokenizer(expression); // INSTANTIATE
            while (tokenizer.hasMoreTokens())  // GETTING ALL TOKENS
            {
                Lexeme nextToken = tokenizer.getToken();
                tokens.add(nextToken.token);
            }
            return tokens;
        }
    
        public String getLexeme (String expression) // CALLED FROM CompilerFinal.java FOR DISPLAYING IN GUI FORM
        {
            StringBuilder lexemeList = new StringBuilder();
            Tokenizer tokenizer = new Tokenizer(expression); // INSTANTIATE
            lexemeList.append("LEXEMES:\n");
            while (tokenizer.hasMoreTokens())  // GETTING ALL TOKENS
            {
                Lexeme nextToken = tokenizer.getToken();
                lexemeList.append(nextToken.token).append("\t").append(nextToken.tokenClass).append("\n");
            }
            return lexemeList.toString();
        }
    
    }
    

    下面是我的解析器代码。我已经包含了我在评论中使用的语法。

    import java.util.LinkedList;
    
    class Token {
        public static final int PLUS = 0;
        public static final int MINUS = 1;
        public static final int MULTIPLY = 2;
        public static final int DIVIDE = 3;
        public static final int EXPONENT = 4;
        public static final int NUMBER = 5;
        public static final int IDENTIFIER = 6;
        public static final int OPEN = 7;
        public static final int CLOSE = 8;
        //public static final int NEGATIVE = 7;
    
        public final int token; // FIELDS TO HOLD DATA PER TOKEN
        public final String sequence;
    
        public Token (int token, String sequence) {
            super();
            this.token = token;
            this.sequence = sequence;
        }
    }
    
    public class Parser {
    
        private Token next; // POINTER FOR NEXT TOKEN
        private final LinkedList<Token> tokens; // LIST OF TOKENS PRODUCED BY TOKENIZER
        private int counter = 0;
    
        public Parser(LinkedList tokens) 
        {
            this.tokens = (LinkedList<Token>) tokens.clone(); // GET LINKEDLIST
            this.tokens.getFirst(); // ASSIGNS FIRST ELEMENT OF LINKEDLIST
        }
    
    
        //////// START OF PARSING METHODS ////////
    
        /*
            GRAMMAR:
            E -> TE' | TE''
            E' -> +E | e
            E'' -> -E | e
    
            T -> FT' | FT''
            T' -> *T | e
            T'' -> /T | e
    
            F -> (E) | -F | "NUMBER" | "IDENTIFIER"
        */
    
        public boolean Parse ()
        {
            return E(); // INVOKE START SYMBOL
        }
    
        private boolean term (int token) // GETS NEXT TOKEN
        {
            boolean flag = false;
    
            if(next.token == token)
                flag = true;
    
            counter++; // INCREMENT COUNTER
    
            if(counter < tokens.size()) // POINT TO NEXT TOKEN
                next = tokens.get(counter);
    
            return flag;
        }
    
        ///////// START OF LIST OF PRODUCTIONS /////////
    
        //////// E -> TE' | TE'' ////////
    
        private boolean E()
        {
            return E1() || E2();
        }
    
        private boolean E1 ()
        {
            // E -> TE'
    
            int flag = counter;
            boolean result = true;
    
            if(!( T() && E_P() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean E2 ()
        {
            // E -> TE''
    
            int flag = counter;
            boolean result = true;
    
            if(!( T() && E_PP() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
    
        //////// E' -> +E | e ////////
    
        private boolean E_P()
        {
            return E_P1() || E_P2();
        }
    
        private boolean E_P1()
        {
            // E' -> +E
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.PLUS) && E() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean E_P2()
        {
            // E' -> e
    
            return true;
        }
    
    
        //////// E'' -> -E | e ////////
    
        private boolean E_PP()
        {
            return E_PP1() || E_PP2();
        }
    
        private boolean E_PP1()
        {
            // E'' -> -E
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.MINUS) && E() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean E_PP2()
        {
            // E'' -> e
    
            return true;
        }
    
    
        //////// T -> FT' | FT'' ////////
    
        private boolean T()
        {
            return T1() || T2();
        }
    
        private boolean T1()
        {
            // T -> FT'
    
            int flag = counter;
            boolean result = true;
    
            if(!( F() && T_P() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean T2()
        {
            // T -> FT''
            int flag = counter;
            boolean result = true;
    
            if(!( F() && T_PP() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
    
        //////// T' -> *T | e ////////
    
        private boolean T_P()
        {
            return T_P1() || T_P2();
        }
    
        private boolean T_P1()
        {
            // T' -> *T
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.MULTIPLY) && T() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean T_P2()
        {
            // T' -> e
    
            return true;
        }
    
    
        //////// T'' -> /T | e ////////
    
        private boolean T_PP()
        {
            return T_PP1() || T_PP2();
        }
    
        private boolean T_PP1()
        {
            // T'' -> /T
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.DIVIDE) && T() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean T_PP2()
        {
            // T'' -> e
    
            return true;
        }
    
    
        //////// F -> (E) | -F | "NUMBER" | "IDENTIFIER" ////////
    
        private boolean F()
        {
            return F1() || F2() || F3() || F4();
        }
    
        private boolean F1()
        {
            // F -> (E)
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.OPEN) && T() && term(Token.CLOSE) ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean F2()
        {
            // F -> -F
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.MINUS) && F() ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean F3()
        {
            // F -> NUMBER
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.NUMBER) ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    
        private boolean F4()
        {
            // F -> NUMBER
    
            int flag = counter;
            boolean result = true;
    
            if(!( term(Token.IDENTIFIER) ))
            {
                counter = flag; // BACKTRACK
    
                if(counter < tokens.size()) // POINT TO PREVIOUS TOKEN
                    next = tokens.get(counter);
    
                result = false;
            }
            return result;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

首先,改变一下:

public LinkedList tokenize (String expression) {...}

到此:

public LinkedList<String> tokenize (String expression) {...}

并改变这一点:

public Parser(LinkedList tokens) {...}

到此:

public Parser(LinkedList<Token> tokens) {...}

LinkedList(没有通用部分)被称为raw type并促进未经检查的转换。如果有更多地方使用原始类型,则还需要更改它们。从代码中删除所有原始类型几乎肯定会导致错误。

我强烈怀疑你的代码基本上是这样的:

Tokenizer t = ...;

// passing LinkedList<String> as a LinkedList<Token>
Parser p = new Parser(t.tokenize(...));

换句话说,您已跳过需要将Strings转换为Tokens的步骤。