Reputation: 65
I have a Recursive Descent Parser project, and I earlier posted a problem that I was having regarding stack overflow error. I have been able to fix that issue, however it is now returning a ClassCastException.
From a main SWING GUI form, I pass input string then build it into a linked list of Strings. I then pass it to the parser.java. The error says:
java.lang.ClassCastException: java.lang.String cannot be cast to compilerfinalproject.Token
Here are some example inputs:
Below is my tokenizer code.
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();
}
}
Below is my parser code. I have included the grammar I used in the comments.
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;
}
}
Upvotes: 0
Views: 291
Reputation: 37875
First thing, change this:
public LinkedList tokenize (String expression) {...}
to this:
public LinkedList<String> tokenize (String expression) {...}
And change this:
public Parser(LinkedList tokens) {...}
to this:
public Parser(LinkedList<Token> tokens) {...}
LinkedList
(without a generic part) is called a raw type and facilitates an unchecked conversion. If there are more places where you use raw types, they also need to be changed. Removing all raw types from your code will almost certainly lead you to the error.
I strongly suspect you have code essentially like this:
Tokenizer t = ...;
// passing LinkedList<String> as a LinkedList<Token>
Parser p = new Parser(t.tokenize(...));
In other words you have skipped a step where you need to convert Strings
to Tokens
.
Upvotes: 1