package jmathlib.core.interpreter;
import jmathlib.core.tokens.*;
import jmathlib.core.tokens.numbertokens.*;
import jmathlib.core.constants.*;
import java.util.Vector;
import java.util.Stack;
/**The parser uses the Lexer to produce a list of tokens which it builds into an abstract syntax tree. */
public class Parser extends RootObject implements TokenConstants, ErrorCodes
{
/** the token which is currently processed */
private Token currentToken = null;
/** the token which will be parsed next */
private Token peekNextToken = null;
/** indicator wether the next token to be parsed was already requested from the
lexical analyser */
private boolean peekNextTokenBool = false;
/**The lexical analyser which separates an expression into tokens*/
private LexicalAnalyser lex = new LexicalAnalyser();
//private boolean endOfTokens = false;
/** */
public String evaluationLockWords;
/**default constructor - creates the Parser object with an empty string*/
public Parser()
{
evaluationLockWords += " global isglobal ";
}
/**Parse an expression and return an operand tree of the expression
@param expression = a vector of tokens
@return the parsed expressions as a tree of operands*/
public OperandToken parseExpression(String expression)
{
// show indention for every logging message
//ErrorLogger.setDisplayIndent(true);
lex.analyseExpression(expression);
//endOfTokens = false;
// parse ALL available Tokens
OperandToken expr = parseCommandList();
//ErrorLogger.setDisplayIndent(false);
return expr;
}
/** set expression of a m-function file or m-script file.
This method is used for parsing m-scripts/functions.
@param expression = code of a function as a string*/
public void setExpression(String expression)
{
// display indention while parsing
//ErrorLogger.setDisplayIndent(true);
lex.analyseExpression(expression);
//endOfTokens = false;
//ErrorLogger.setDisplayIndent(false);
}
/** parse remaining tokens of a m-function file or m-script file
@return the parsed expresssion*/
public OperandToken parseRemainingExpression()
{
// display indention while parsing
//ErrorLogger.setDisplayIndent(true);
// parse ALL available Tokens
OperandToken expr = parseCommandList();
//ErrorLogger.setDisplayIndent(false);
return expr;
}
/** return the currently scanned line of code to identify the
possible errors. (e.g. a=sin(3]+4 is an eroror and
returns a=sin(3] to display to the user
@return the currently scanned line of code */
public String getScannedLineOfCode()
{
return lex.getScannedLineOfCode();
}
/*****************************************************************************/
/* Methods to return/inspect/work on single tokens returned from the scanner */
/**get next token from the lexical analyser
@return the next token*/
public Token getNextToken()
{
return getNextToken(SINGLE);
}
/**get next token from the lexical analyser
@param indicator if lexical analyser should consider whitespaces or not
@return the next token*/
private Token getNextToken(int type)
{
//ErrorLogger.debugLine("Parser: getNextToken");
// copy peek next token to next token OR get new next token
if (!peekNextTokenBool)
{
currentToken = lex.getNextToken(type);
}
else
{
currentToken = peekNextToken;
peekNextTokenBool = false;
}
return currentToken;
}
/**get next Token from lexical analyser, without moving forward
@return the next token*/
public Token peekNextToken()
{
return peekNextToken(SINGLE);
}
/**get next Token from lexical analyser, without moving forward
@param indicator if lexical analyser should consider whitespaces or not
@return the next token*/
private Token peekNextToken(int type)
{
//ErrorLogger.debugLine("Parser: peekNextToken");
if (!peekNextTokenBool)
{
peekNextToken = lex.getNextToken(type);
peekNextTokenBool = true;
//if (peekNextToken == null)
// endOfTokens = true;
}
return peekNextToken;
}
/*****************************************************************************/
/**parse the expression contained in exp, this method is also called recursivly
to find the parameters of functions and matrices
@param deliTyp - shows whether parser is parsing expressions or a matrix
@return the parsed operand/expression */
private OperandToken parseSingle(Stack operandStack, int deliTyp)
{
// ==SINGLE, this is a parameter of a function (e.g.: sin(3) or 3 or a )
// ==MATRIX, also consider whitespaces during parsing of matrices
if (deliTyp==MATRIX) ErrorLogger.debugLine("Parser parseSingle matrix");
else ErrorLogger.debugLine("Parser parseSingle");
ErrorLogger.increaseIndent();
OperandToken retToken = null; // holds token to be returned
Token peekToken = peekNextToken(deliTyp); // holds next (actual) token
if (peekToken == null)
{
// No more tokens available
// Do nothing
}
else if(peekToken instanceof DelimiterToken)
{
DelimiterToken token = ((DelimiterToken)peekToken);
if (token.value == '(' )
{
ErrorLogger.debugLine("Parser: found (");
getNextToken(deliTyp); // remove (
//parse expression, e.g.: (a+1)+2
retToken = parseArithExpression(SINGLE);
// get current token to see if closing ')'
if (!isExpectedDelimiter(peekNextToken(deliTyp), ')' ))
Errors.throwParserException(" missing )");
else
getNextToken(deliTyp);
// (e.g. (2+3) is hidden inside in expression to avoid problems with
// expressions of higher priority. (e.g. (2+3)*4 )
retToken = new Expression(null, retToken);
}
else if (token.value == '[')
{
ErrorLogger.debugLine("Parser: matrix begin [");
getNextToken(deliTyp); // remove [
retToken = parseMatrix();
//ErrorLogger.debugLine("Parser: Matrix: ] end");
}
else if (token.value == '{')
{
ErrorLogger.debugLine("Parser: cell array begin {");
getNextToken(deliTyp); // remove {
retToken = parseCellArray();
//ErrorLogger.debugLine("Parser: CellArray: ] end");
}
else
{
// Delimiter: ] , ; \r \n ) } -
// end, endif, elseif, else
// The parser found an unspecified delimiter, this can mark
// the end of a parameter
// or the end of a function
// or the end of a line/command
// The delimiter will be consumed by a the parser function
// which is expecting a delimiter
ErrorLogger.debugLine("Parser closing "+token.toString());
}
}
else if(peekToken instanceof VariableToken)
{
// variables (e.g. aaa or b)
retToken = (OperandToken)getNextToken(deliTyp);
ErrorLogger.debugLine("Parser parseSingle ppp "+retToken.toString());
// check if the variable is followed by a dot operator
if (peekNextToken(deliTyp) instanceof DotOperatorToken)
{
// e.g. a.something or a.sin() or a.getObject().getColor()
operandStack.push(retToken);
getNextToken(deliTyp); // remove "." from scanner
retToken = parseDotOperator(operandStack, deliTyp);
}
else if (peekNextToken(deliTyp) instanceof DelimiterToken)
{
// this might be something like e.g. ( sin ( )
DelimiterToken token = ((DelimiterToken)peekNextToken(deliTyp));
if (token.value == '(')
{
ErrorLogger.debugLine("Parser: found function while parsing variable");
String name = ((VariableToken)peekToken).getName();
retToken = parseFunctionAndParameters( new FunctionToken(name), null );
}
else if (token.value == '{')
{
ErrorLogger.debugLine("Parser: found cell array structure");
String name = ((VariableToken)peekToken).getName();
retToken = parseFunctionAndParameters( new FunctionToken(name), null );
}
}
else if ( (peekNextToken(deliTyp) instanceof VariableToken) ||
(peekNextToken(deliTyp) instanceof CharToken) )
{
// parse something like disp hello instead of disp("hello")
// parse something like disp "hello" instead of disp("hello")
// convert arguments into char arrays
String name = ((VariableToken)retToken).getName();
FunctionToken func = new FunctionToken(name);
Token next = null ;
while(true)
{
next = peekNextToken();
if (next==null)
break;
//ErrorLogger.debugLine("Parser: var var "+next.toString());
if (next instanceof DelimiterToken)
{
break;
}
else if ( (next instanceof VariableToken) ||
(next instanceof CharToken) )
{
String s = next.toString();
ErrorLogger.debugLine("Parser: var var variable "+next.toString());
getNextToken();
func.setOperands(new OperandToken[] {(OperandToken)new CharToken(s)});
}
else
Errors.throwMathLibException("Parser: var var");
}
return func;
}
else
ErrorLogger.debugLine("Parser: VariableToken: " + retToken.toString());
}
else if(peekToken instanceof FunctionToken)
{
// * / + - ' sin() cos() and more
// something like sin() cos() somefunction() if() switch()
String name = ((FunctionToken)getNextToken(deliTyp)).getName();
/* if-then-else, while, for, switch */
if( name.equals("if"))
{
ErrorLogger.debugLine("Parser: if");
retToken = parseIf();
ErrorLogger.debugLine("Parser: if end");
}
else if( name.equals("while"))
{
ErrorLogger.debugLine("Parser: while");
retToken = parseWhile();
ErrorLogger.debugLine("Parser: while end");
}
else if( name.equals("for"))
{
ErrorLogger.debugLine("Parser: for");
retToken = parseFor();
ErrorLogger.debugLine("Parser: for end");
}
else if( name.equals("switch"))
{
ErrorLogger.debugLine("Parser: switch");
retToken = parseSwitch();
ErrorLogger.debugLine("Parser: switch end");
}
else
{
/* Some function */
ErrorLogger.debugLine("Parser: function "+name);
retToken = parseFunctionAndParameters( (FunctionToken)peekToken, null );
}
}
else if(peekToken instanceof OperandToken)
{
// numbers, variables (e.g 3 or a or b)
retToken = (OperandToken)getNextToken(deliTyp);
ErrorLogger.debugLine("Parser: operand: " + retToken.toString());
}
else if(peekToken instanceof OperatorToken)
{
Token nextToken = getNextToken(deliTyp);
Token pToken = peekNextToken(deliTyp);
// throw exception for multiple operands
// e.g. a=/7 a=*8 +*5 -*8 -/9
if (( (nextToken instanceof AssignmentOperatorToken) ||
(nextToken instanceof AddSubOperatorToken) ||
(nextToken instanceof MulDivOperatorToken) ) &&
(pToken instanceof MulDivOperatorToken) )
Errors.throwParserException("multiple operators * /");
// e.g. a=^7 +^3 -^6 *^5 ^^5 !^7
if (( (nextToken instanceof AssignmentOperatorToken) ||
(nextToken instanceof AddSubOperatorToken) ||
(nextToken instanceof PowerOperatorToken) ) &&
(pToken instanceof PowerOperatorToken) )
Errors.throwParserException("multiple operators ^");
ErrorLogger.debugLine("PARSER op+op: "+nextToken);
ErrorLogger.debugLine("PARSER op+op: "+pToken);
if(nextToken instanceof AssignmentOperatorToken)
{
ErrorLogger.debugLine("Parser: <x> = <y>");
retToken = parseAssignmentOperator(nextToken, operandStack);
}
else if(nextToken instanceof ColonOperatorToken)
{
ErrorLogger.debugLine("Parser: <x> : <y>");
retToken = parseColonOperator(nextToken, operandStack);
}
else if(nextToken instanceof DotOperatorToken)
{
ErrorLogger.debugLine("Parser: dot-operator");
retToken = parseDotOperator(operandStack, deliTyp);
}
else if((nextToken instanceof AddSubOperatorToken) &&
(pToken instanceof AssignmentOperatorToken))
{
// += or -=
ErrorLogger.debugLine("Parser: += or -=");
getNextToken(deliTyp);
retToken = parseAssignmentOperator(nextToken, operandStack);
}
else if((nextToken instanceof MulDivOperatorToken) &&
(pToken instanceof AssignmentOperatorToken))
{
// *= or /=
ErrorLogger.debugLine("Parser: *= or /=");
getNextToken(deliTyp);
retToken = parseAssignmentOperator(nextToken, operandStack);
}
else if( (nextToken instanceof AddSubOperatorToken)
|| (nextToken instanceof MulDivOperatorToken)
|| (nextToken instanceof PowerOperatorToken)
|| (nextToken instanceof BinaryOperatorToken)
|| (nextToken instanceof RelationOperatorToken))
{
/* Binary tokens: +, -, *, /, ^, <=, >=, ~=, == */
ErrorLogger.debugLine("Parser: <x> " + nextToken.toString() + " <y>");
retToken = parseBinaryOperator(nextToken, operandStack);
}
else if(nextToken instanceof UnaryOperatorToken)
{
ErrorLogger.debugLine("Parser: unary operator "+nextToken.toString());
retToken = parseUnaryOperator(nextToken, operandStack);
}
}
else
{
// every valid token must have been analyzed above
Errors.throwParserException(" unknown token: "+peekToken.toString());
}
ErrorLogger.decreaseIndent();
if (retToken!=null) ErrorLogger.debugLine("Parser return: " + retToken.toString());
else ErrorLogger.debugLine("Parser return: null");
return retToken;
} // end parseSingle
/**parse the expression contained in exp, this method is also called recursivly
to find the parameters of functions and matrices (e.g. something like 2+3+(2*4) )
@param deliTyp indicates if an argument is part of a matrix (whitespaces are treated
as delimiters in this case)
@return expression (e.g. 3 or 2+3 or sin(cos(3)) ) */
private OperandToken parseArithExpression(int deliTyp)
{
// expressions have their own stack
Stack operandStack = new Stack();
ErrorLogger.debugLine("Parser parseArithmeticExpr begin");
ErrorLogger.increaseIndent();
while(true)
{
// parsing is not useful if the next token will be a closing ")"
// (e.g. who() or a.getColor() )
if ( isExpectedDelimiter(peekNextToken(deliTyp), ')') )
break;
// parse next token
OperandToken subExpr = parseSingle(operandStack, deliTyp);
// Put parsed token on the operand stack
// If nothing useful was parsed then break
if (subExpr != null)
operandStack.push(subExpr);
Token peekToken = peekNextToken(deliTyp);
// arithmetic expressions are terminated by the following delimiters
if(peekToken instanceof DelimiterToken)
{
DelimiterToken token = ((DelimiterToken)peekToken);
// check wether or not the next token is a closing delimiter
if ( (token.value == ',') || (token.value == ';') ||
(token.value == '\r') || (token.value == '\n') ||
(token.value == '}') || (token.value == '-') ||
(token.value == ' ') || (token.value == ')') ||
(token.value == ']') )
{
ErrorLogger.debugLine("Parser delimiter break "+token.value);
break;
}
}
// if no more tokens are available return
if(peekToken==null)
break;
} // end while
// Check if the currently parsed expression is terminated by a delimiter
// which has the display property.
// (e.g: display "a=4," don't display "a=4;")
//if ((getCurrentToken() instanceof DelimiterToken) &&
// isDisplayResultToken(getCurrentToken()) &&
// !operandStack.isEmpty())
//{
// OperandToken op = (OperandToken)operandStack.pop();
// ErrorLogger.debugLine("Parser: display true "+op.toString());
// op.setDisplayResult(true);
// operandStack.push(op);
//}
// build return token
OperandToken retT = null;
if (!operandStack.isEmpty())
retT = (OperandToken)operandStack.pop();
// throw error if stacksize > 1
ErrorLogger.decreaseIndent();
ErrorLogger.debugLine("Parser parseArithmeticExpr end ");
return retT;
}
/** parse a list of commands (e.g. a=2+3;if(a=2){b=3};c=sin(pi) )
@return OperantToken tree of operand tokens (e.g. a=2+3) */
private OperandToken parseCommandList()
{
// these could be concatenated expressions (e.g.: "a=1;b=sin(4);c=3")
ErrorLogger.debugLine("Parser parseCommandList begin");
ErrorLogger.increaseIndent();
Stack operandStack = new Stack();
OperandToken command;
while (true)
{
// parse next token/command
ErrorLogger.debugLine("Parser parseCommandList next");
//command = parseSingle(operandStack, SINGLE);
// handling of {...} for commands is done here only, there has
// to be a difference in order to parse cell arrays
if (isExpectedDelimiter(peekNextToken(), '{' ))
{
getNextToken();
// get commands inside {...}
// get commands (e.g. if(3) ... endif or if(3) ... elseif
command = parseCommandList();
if (!isExpectedDelimiter( peekNextToken(), '}' ))
Errors.throwParserException(" parseCommandList ERROR missing }");
else
getNextToken();
}
else
command = parseSingle(operandStack, SINGLE);
Token peekToken = peekNextToken();
// Check if the currently parsed expression will be terminated by a delimiter
// which has the display property.
// (e.g: display "a=4," don't display "a=4;")
if (isDisplayResultToken(peekToken) && (command != null))
{
ErrorLogger.debugLine("Parser: display true "+command.toString());
command.setDisplayResult(true);
}
// put parsed token on the operand stack
if (command != null)
operandStack.push(command);
// Check if the token, why the parser is returned is correct
// Command lists are terminated by "}" "endif" "end" "else"
if ( isExpectedDelimiter(peekToken, "elseif") ||
isExpectedDelimiter(peekToken, "else") ||
isExpectedDelimiter(peekToken, "endif") ||
isExpectedDelimiter(peekToken, "end") ||
isExpectedDelimiter(peekToken, "endfunction") ||
isExpectedDelimiter(peekToken, "case") ||
isExpectedDelimiter(peekToken, "default") ||
isExpectedDelimiter(peekToken, "otherwise") ||
isExpectedDelimiter(peekToken, "endswitch") ||
isExpectedDelimiter(peekToken, "endwhile") ||
isExpectedDelimiter(peekToken, "endfor") ||
isExpectedDelimiter(peekToken, '}') )
{
// this path is only called from parseSingle( .. parseCommandList() )
ErrorLogger.debugLine("Parser parseCommandList break");
break;
}
else if (isExpectedDelimiter(peekToken, ',') ||
isExpectedDelimiter(peekToken, ';') ||
isExpectedDelimiter(peekToken, '\r') ||
isExpectedDelimiter(peekToken, '\n') )
{
// remove delimiters from parseSingle
getNextToken();
}
else if (peekToken == null)
{
// command lists may be terminated by end of file
break;
}
else
{
// is none of the above delimiters occured, there is an
// error e.g. ceil(5;8]
//Errors.throwParserException("parseCommandList wrong delimiter");
//break;
}
} // end while
// put all code parts from the stack into one expression object
OperandToken tree = null;
int stackSize = operandStack.size();
if (stackSize > 0)
{
//The expressions have been put onto the stack in reversed order
OperandToken[] opTokenArray = new OperandToken[stackSize];
for(int i=stackSize-1; i>=0; i--)
{
OperandToken ob = ((OperandToken)operandStack.pop());
opTokenArray[i] = ob;
}
tree = new Expression(null, opTokenArray, stackSize);
}
ErrorLogger.decreaseIndent();
ErrorLogger.debugLine("Parser parseCommandList end");
return tree;
}
/***************************************************************************************/
/***** individual parsing methods ******/
/***************************************************************************************/
/** parse <variable><=><operand> (e.g. a=3 or a=2+3+4 or [a,b]=step(x) ) */
/* @param */
/* @param */
/* @return expression of assignment (e.g. a=3) */
private OperandToken parseAssignmentOperator(Token currentToken, Stack operandStack)
{
// operator (this should be a "=" or ("+" for +=) or ("-" for -=))
// or "*" for *= or "/" for /=
OperatorToken operator = (OperatorToken)currentToken;
//parse right parameter
OperandToken rightSide = parseArithExpression(SINGLE);
//get left parameter from operandStack (e.g. a or [a,b,c] =...)
OperandToken leftSide = (OperandToken)operandStack.pop();
/* create new expression */
Expression tree = null;
if (currentToken instanceof AssignmentOperatorToken)
{
// e.g. a=8
tree = new Expression(operator, leftSide, rightSide);
}
else if (currentToken instanceof AddSubOperatorToken)
{
// e.g. a+=8 -> a=a+8
// e.g. a-=7 -> a=a-7
ErrorLogger.debugLine("Parser: += or -=");
tree = new Expression(operator, leftSide, rightSide);
tree = new Expression(new AssignmentOperatorToken(), leftSide, tree);
}
else if (currentToken instanceof MulDivOperatorToken)
{
// e.g. a*=8 -> a=a*8
// e.g. a/=9 -> a=a/9
ErrorLogger.debugLine("Parser: *= or /=");
tree = new Expression(operator, leftSide, rightSide);
tree = new Expression(new AssignmentOperatorToken(), leftSide, tree);
}
return tree;
} // end parseAssignmentOperator
/***********************************************************************************/
/** parse <operand>:<operand> (e.g. 2:7 -> [2,3,4,5,6,7]) */
/** parse <operand>:<operand>:<operand> (e.g. 2:3:8 -> [2,5,8] */
/* @param */
/* @param */
/* @return */
private OperandToken parseColonOperator(Token nextToken, Stack operandStack)
{
OperandToken leftSide = null;
//get left parameter from operandStack
if(!operandStack.isEmpty())
leftSide =(OperandToken)operandStack.pop();
//parse right parameter
//be careful about e.g. a(:), a(1,:)
OperandToken rightSide = null;
if (!isExpectedDelimiter(peekNextToken(), ')') &&
!isExpectedDelimiter(peekNextToken(), ',') &&
!isExpectedDelimiter(peekNextToken(), ';') )
rightSide = parseArithExpression(SINGLE);
else
rightSide = null;
// also possible is something like a(1:end) or a(2:4:end)
if (isExpectedDelimiter(peekNextToken(), "end"))
rightSide = (OperandToken)getNextToken();
// Check is left Side is empty
if ((leftSide==null) ||
(leftSide instanceof DelimiterToken) )
{
// something like: a(:)
ErrorLogger.debugLine("Parser: colon: (:)");
operandStack.push(leftSide); // push left side back on stack
return new Expression((OperatorToken)nextToken);
}
else
{
// e.g. 1:8
if (rightSide instanceof Expression)
{
Expression rightExpr = (Expression)rightSide;
if (rightExpr.getData() instanceof ColonOperatorToken)
{
// e.g. 2:<4:5>
ErrorLogger.debugLine("Parser: colon: "+leftSide.toString()+":"
+rightExpr.getChild(0).toString()+":"
+rightExpr.getChild(1).toString() );
OperandToken[] opToken = { leftSide,
rightExpr.getChild(0),
rightExpr.getChild(1) };
return new Expression((OperatorToken)nextToken, opToken, 3);
}
else
{
// e.g. 2:<6+7> (just one colon, but expression)
ErrorLogger.debugLine("Parser: colon: "+leftSide.toString()+":"+rightSide.toString());
return new Expression((OperatorToken)nextToken,
leftSide,
rightSide);
}
}
else
{
// e.g.: 2:6
ErrorLogger.debugLine("Parser: colon: "+leftSide.toString()+":"+rightSide.toString());
return new Expression((OperatorToken)nextToken, leftSide, rightSide);
}
}
} // end parseColonOperator
/***********************************************************************************/
/** parse <operand><operator><operand> (e.g. 3+4, 3*4, 3/4, 1+2*3+4*5) */
/* @param */
/* @param */
/* @return */
private OperandToken parseBinaryOperator(Token nextToken, Stack operandStack)
{
// operator for this operation
OperatorToken operator = (OperatorToken)nextToken;
//get left parameter from operandStack
//(exception: if parsing "-a" left operand will be null)
OperandToken leftSide = null;
if (!operandStack.isEmpty())
leftSide = (OperandToken)operandStack.pop();
//parse right parameter
OperandToken rightSide = parseSingle(operandStack, SINGLE);
// create new expression
Expression tree = new Expression(operator, leftSide, rightSide);
// Check if priority is correct. e.g.: 2*3+4 => (2*3)+4
// (left side and right side might be changed
// if the operators (+-*^!') have different priorities)
if (!(leftSide instanceof Expression))
return tree;
Expression leftExpr = (Expression)leftSide;
OperatorToken leftBinary = (OperatorToken)leftExpr.getData();
if (leftBinary == null)
return tree;
if (!(leftBinary instanceof BinaryOperatorToken))
return tree;
/* only priority swapping for binary operators + - * / ^ < > ... */
// 1+2*3+4*5 should be parsed into ((1+(2*3))+(4*5))
// 1/2-1+9 should be parsed into (((1 / 2) - 1) + 9)
ErrorLogger.debugLine("priority ("+ leftBinary.getPriority() +
"," + operator.getPriority() +
") <" + leftSide.toString() +
"> " + operator.toString() +
" <" + rightSide.toString() + ">");
if (leftBinary.getPriority() < operator.getPriority())
{
// something like 2+3*4 : <2+3> * <4>
// change to <2> + <3*4>
// left: +
// <2> <3>
ErrorLogger.debugLine("swapping priorities");
OperandToken newLeft = leftExpr.getRight();
//already parsed right side is first operand of new right
//operandStack.push(rightSide);
//parse right
//OperandToken newRight = (OperandToken)operandStack.pop();
OperandToken newRight = new Expression((OperatorToken)operator,
leftExpr.getRight(),
rightSide);
// Check next token if it is a binary operator and call a parse() method
// until priority of next operator is lower/equals as the calling operator
// (e.g. 1+2 * 3 <+> .... priority of <+> is lower than "*")
if (peekNextToken() instanceof BinaryOperatorToken)
{
BinaryOperatorToken nextBinary = (BinaryOperatorToken)peekNextToken();
if (operator.getPriority() <= nextBinary.getPriority())
{
// the current arithmetic expression is not terminated yet
// parse next operands
ErrorLogger.debugLine("Parser: BinaryOperator: recursive parsing");
operandStack.push(newRight);
newRight = parseSingle(operandStack, SINGLE);
}
}
// create tree again
tree = new Expression((OperatorToken)leftBinary,
leftExpr.getLeft(),
newRight);
}
return tree;
} // end parseBinaryOperator
/***********************************************************************************/
/** parse <operand><operator> (e.g. 3! or !(a<3)) */
/* @param */
/* @param */
/* @return */
private OperandToken parseUnaryOperator(Token nextToken, Stack operandStack)
{
// if parsing !(a<3) or !3 operand stack is empty
if (operandStack.isEmpty())
{
ErrorLogger.debugLine("Parser: Unary !3 or ~3");
UnaryOperatorToken tok = (UnaryOperatorToken)nextToken;
if (! ((tok.getValue()=='!') || (tok.getValue()=='~')))
Errors.throwParserException(" Unary operator by empty stack");
OperandToken operand = parseArithExpression(SINGLE);
FunctionToken func = new FunctionToken("not");
func.setOperand(operand);
return func;
}
// e.g. 3!
//get left parameter from operandStack
OperandToken leftSide = (OperandToken)operandStack.pop();
Expression tree = null;
/* if ((leftSide instanceof DoubleNumberToken) ||
(leftSide instanceof MatrixToken) ||
(leftSide instanceof VariableToken) ||
(leftSide instanceof FunctionToken) )
{*/
// (e.g. 3! a! a++ a--)
tree = new Expression((UnaryOperatorToken)nextToken, leftSide);
/*}
else if (leftSide instanceof Expression)
{
Expression leftExpr = (Expression)leftSide;
Expression newRightOperand = new Expression((UnaryOperatorToken)nextToken,
leftExpr.getRight());
tree = new Expression(leftExpr.getData(),
leftExpr.getLeft(),
newRightOperand);
}
else
Errors.throwParserException(" Unary operator");
*/
return tree;
} // end parseBinaryOperator
/***********************************************************************************/
/** parse expressions of the form value.function() */
/* @param operand stack */
/* @param type of delimiters (including whitespaces or not) */
/* @return parsed expression or variable token */
private OperandToken parseDotOperator(Stack operandStack, int deliTyp)
{
ErrorLogger.debugLine("Parser: DotOperator");
// result of parsing dot operator
OperandToken result;
// the left operand has been parsed already
OperandToken leftSide = (OperandToken)operandStack.pop();
// right side
OperandToken rightSide = null; //parseSingle(operandStack, SINGLE);
// check type of right side operand (e.g. a.bbbb or a.someFunction() )
if (peekNextToken(deliTyp) instanceof VariableToken)
{
// (e.g. a.B or bar.foo)
rightSide = (VariableToken)getNextToken(deliTyp);
}
else if (peekNextToken(deliTyp) instanceof FunctionToken)
{
// (e.g. a.sin() or a.getColor() )
rightSide = parseFunctionAndParameters((FunctionToken)getNextToken(deliTyp), null);
}
else
Errors.throwParserException("DotOperator: unknown right side");
// create extended variable token or expression of dot-operator
if ((leftSide instanceof VariableToken) &&
(rightSide instanceof VariableToken) )
{
// (e.g. a.length or system.A or a.bbb)
String left = ((VariableToken)leftSide).getName();
String right = ((VariableToken)rightSide).getName();
ErrorLogger.debugLine("Parser: " + left + "." + right);
result = new VariableToken(left, right);
}
else
{
// (e.g. a.sin() or a.getColor()
ErrorLogger.debugLine("Parser: foo.some_func()");
result = new Expression(new DotOperatorToken(), leftSide, rightSide);
}
// check if the dot-expression is followed by another dot operator
// (e.g. aaa.getGraphics().getSize().getValue() )
if (peekNextToken(deliTyp) instanceof DotOperatorToken)
{
// push already parsed expression on stack
operandStack.push(result);
// remove "." from scanner
getNextToken(deliTyp);
// parse next dot-expression
result = parseDotOperator(operandStack, deliTyp);
}
return result;
}
/***********************************************************************************/
/** parse <function>(<operand>,<operand>,....) (e.g. min(3,4) ) */
/* @param FunctionToken */
/* @param first parameter */
/* @return parsed function (e.g. sin(3) or min(2,3) ) */
private OperandToken parseFunctionAndParameters(OperandToken nextToken, OperandToken firstParam)
{
// create new expression
FunctionToken func = (FunctionToken)nextToken;
// check if it is a special function e.g. "global a b c"
if ( func.getName().equals("global") || func.getName().equals("isglobal"))
{
ErrorLogger.debugLine("Parser: found global");
// do not evaluate operands
func.evaluationLockB=true;
Token next = null ;
while(true)
{
next = peekNextToken();
if (next==null)
break;
ErrorLogger.debugLine("Parser: global "+next.toString());
if (next instanceof DelimiterToken)
{
break;
}
else if (next instanceof VariableToken)
{
ErrorLogger.debugLine("Parser: global variable "+next.toString());
getNextToken();
func.setOperands(new OperandToken[] {(OperandToken)next});
}
else
Errors.throwMathLibException("Parser: global");
}
// !!!! needs stack for multiple "global a b c e"
//func.setOperands(new OperandToken[] {(OperandToken)next}); //parameters);
return func;
}
// if next token is a "(" then ignore it
Token next = peekNextToken();
// indicator if a cell array acess is parsed
// e.g. a{4,6}='66'
boolean cellB = false;
if (isExpectedDelimiter( next, '(' ))
{
getNextToken();
}
else if (isExpectedDelimiter( next, '{' ))
{
getNextToken();
cellB = true;
}
else if(next instanceof DotOperatorToken)
{
return func;
}
Stack parameterStack = new Stack();
// if a first parameter is supplied, put it on the stack
if(firstParam != null)
{
firstParam.setDisplayResult(false);
parameterStack.push(firstParam);
func.setOperand(firstParam);
}
int i=0;
while (true)
{
i++;
ErrorLogger.debugLine("Parser: function parse Parameter "+i);
//parse next parameter
OperandToken operand = parseArithExpression(SINGLE);
// check if a parameter is returned (e.g. who() returns no parameter)
if (operand == null)
{
// who() returns no parameter, but still need to remove ")" from scanner
if (isExpectedDelimiter(peekNextToken(), ')') && !cellB)
getNextToken();
if (isExpectedDelimiter(peekNextToken(), '}') && cellB)
getNextToken();
break;
}
//values of parameters are not displayed at the prompt
operand.setDisplayResult(false);
//add parameter to expression tree
parameterStack.push(operand);
// get current token to see if more parameters expected or if closing ')'
Token current = peekNextToken();
if (current != null)
ErrorLogger.debugLine("Parser: function parse Parameter current "+current.toString());
if (isExpectedDelimiter(peekNextToken(), ',' ))
{
getNextToken();
}
else if (isExpectedDelimiter(peekNextToken(), ')' ) && !cellB)
{
getNextToken();
break;
}
else if (isExpectedDelimiter(peekNextToken(), '}' ) && cellB)
{
getNextToken();
break;
}
//else if (isExpectedDelimiter(peekNextToken(), ';' ))
//{
// getNextToken();
// break;
//}
else
Errors.throwParserException(" error parsing parameter");
}
// copy parameters from stack into operands array
int parSize = parameterStack.size();
OperandToken[] parameters = new OperandToken[parSize];
// reverse order, because stack is last in first out
for( int p=parSize-1; p>=0; p--)
{
parameters[p] = ((OperandToken)parameterStack.pop());
}
// e.g. foo{888}=...
if (cellB)
{
return new VariableToken(func.getName(),parameters, "cell");
}
func.setOperands(parameters); // = ( (OperatorToken)nextToken , parameters, parSize);
return func;
} // end parseFunctionParameters
/***********************************************************************************/
/** parse <if>(<relation>){<expression>} else {<expression>} */
/* parse <if>(<relation>) <expression> else <expression> endif
/* @param */
/* @param */
/* @return */
private OperandToken parseIf()
{
// parse releation (e.g. if (3<5) ...)
// next Token must be a "("
if (!isExpectedDelimiter(getNextToken(), '('))
Errors.throwParserException(" if missing (");
// get argument inside (...)
OperandToken ifRelation = parseArithExpression(SINGLE);
// check if argument is terminated by ")"
if (!isExpectedDelimiter(peekNextToken(), ')' ))
Errors.throwParserException("If: missing )");
else
getNextToken();
ErrorLogger.debugLine("Parser: if after relation: "+ifRelation.toString());
// parse commands (e.g. if(3<5) {some_commands} or
// if(3<5) some_commands endif
ErrorLogger.debugLine("Parser: if-command");
OperandToken ifCode = parseCommandList();
ErrorLogger.debugLine("Parser: if command: "+ifCode.toString());
// If(..) {...}
IfThenOperatorToken ifToken = new IfThenOperatorToken(ifRelation, ifCode);
// start parsing elseif, ... , else
while(true)
{
Token nextToken = peekNextToken();
ErrorLogger.debugLine("Parser: if "+nextToken);
if(isExpectedDelimiter(peekNextToken(), "elseif"))
{
// this is at least some if-elseif-else
getNextToken(); // remove "elseif"-token
// elseif(..) {...}
ErrorLogger.debugLine("Parser: if: found elseif");
if (!isExpectedDelimiter(getNextToken(), '(' ))
Errors.throwParserException(" if missing (");
// get argument inside (...)
OperandToken elseIfRelation = parseArithExpression(SINGLE);
// check if argument is terminated by ")"
if (!isExpectedDelimiter(peekNextToken(), ')' ) )
Errors.throwParserException("If: missing )");
else
getNextToken();
ErrorLogger.debugLine("Parser: elseIf after relation: "+elseIfRelation.toString());
// parse commands (e.g. elseif(3<5) {some_commands} or
// elseif(3<5) some_commands endif
OperandToken elseIfCode = parseCommandList();
ErrorLogger.debugLine("Parser: elseIf code: "+elseIfCode.toString());
ifToken.addCondition(elseIfRelation, elseIfCode);
}
else if (isExpectedDelimiter(peekNextToken(), "else") )
{
getNextToken(); // remove "else"-token
// If(..) {...} else {...}
ErrorLogger.debugLine("Parser: if: found else");
// get commands inside {...}
OperandToken elseCode = parseCommandList();
ErrorLogger.debugLine("Parser: else code: "+elseCode.toString());
ifToken.addCondition(null, elseCode);
}
else if (isExpectedDelimiter(peekNextToken(), "endif") ||
isExpectedDelimiter(peekNextToken(), "end") )
{
getNextToken(); // remove endif token
break;
}
else
Errors.throwParserException("If: some error");
} // end while
ErrorLogger.debugLine("Parser: if: end of parsing");
return ifToken;
} // end parseIf
/***********************************************************************************/
/** parse switch(<variable>) */
/* { */
/* case(<number>): { <expression> } */
/* ... */
/* case(<number>): { <expression> } */
/* default: { <expression> } */
/* } */
/* @param */
/* @param */
/* @return */
private OperandToken parseSwitch()
{
Token nextToken = null;
// next Token must be a "("
if (!isExpectedDelimiter(getNextToken(), '(' ))
ErrorLogger.debugLine("Parser: switch missing (");
// get argument inside (...)
OperandToken switchRelation = parseArithExpression(SINGLE);
if (!isExpectedDelimiter(peekNextToken(), ')' ))
Errors.throwParserException("Switch: missing )");
else
getNextToken();
if (!isExpectedDelimiter(peekNextToken(), '\n') )
Errors.throwParserException("switch: missing \\n");
else
getNextToken();
ErrorLogger.debugLine("Parser: switch after relation");
//parse switch statement
Vector cases = new Vector(10);
// if the next Token is a "{" then remove it
//if(isExpectedDelimiter(peekNextToken(), '{' ))
// nextToken = getNextToken();
// parse case,default,otherwise commands
while(peekNextToken() != null)
{
if(isExpectedDelimiter(peekNextToken(), "case"))
{
getNextToken();
ErrorLogger.debugLine("Parser: switch: case *****");
cases.addElement(parseCase());
ErrorLogger.debugLine("Parser: switch: case end *****");
}
else if(isExpectedDelimiter(peekNextToken(), "default") ||
isExpectedDelimiter(peekNextToken(), "otherwise") )
{
getNextToken();
ErrorLogger.debugLine("Parser: switch: default");
cases.addElement(parseDefault());
}
else if(isExpectedDelimiter(peekNextToken(), "end") ||
isExpectedDelimiter(peekNextToken(), "endswitch") )
{
getNextToken();
ErrorLogger.debugLine("Parser: switch: end");
break;
}
else
{
Errors.throwParserException(" switch error");
}
} // end while
ErrorLogger.debugLine("Parser: switch returning");
return new SwitchToken(switchRelation, cases);
}
/**
* parsing of "case" commands
* @return
*/
private OperandToken parseCase()
{
if (!isExpectedDelimiter(getNextToken(), '(' ))
ErrorLogger.debugLine("Parser: case missing (");
// get argument inside (...)
ErrorLogger.debugLine("Parser: switch: case relation *****");
OperandToken caseRelation = parseArithExpression(SINGLE);
if (!isExpectedDelimiter(peekNextToken(), ')' ))
Errors.throwParserException("Switch case: missing )");
else
getNextToken();
ErrorLogger.debugLine("Parser: switch: case relation end *****");
// get commands
ErrorLogger.debugLine("Parser: switch: case code *****");
OperandToken caseCode = parseCommandList();
ErrorLogger.debugLine("Parser: switch: case code end *****");
return new CaseToken(caseRelation, caseCode);
}
/**
* parse "default" or "otherwise" command of switch
* @return
*/
private OperandToken parseDefault()
{
ErrorLogger.debugLine("Parser: switch default");
// get default commands
OperandToken defaultCode = parseCommandList();
return new CaseToken(null, defaultCode);
}
/***********************************************************************************/
/** parse while(something) { do something } */
/* @param */
/* @param */
/* @return */
private OperandToken parseWhile()
{
// check for "(" (e.g. while(..... )
if(!isExpectedDelimiter(peekNextToken(), '(') )
Errors.throwParserException("while: ERROR missing (");
else
getNextToken();
// get argument inside (...)
OperandToken whileRelation = parseArithExpression(SINGLE);
if(!isExpectedDelimiter(peekNextToken(), ')') )
Errors.throwParserException("While: ERROR missing )");
else
getNextToken();
ErrorLogger.debugLine("Parser: while after relation");
// get commands inside {...}
OperandToken whileCode = parseCommandList();
//if (isExpectedDelimiter(peekNextToken(), ',' ) ||
// isExpectedDelimiter(peekNextToken(), ';' ) )
// getNextToken();
if(isExpectedDelimiter(peekNextToken(), "end") ||
isExpectedDelimiter(peekNextToken(), "endwhile") )
{
getNextToken();
ErrorLogger.debugLine("Parser: while: end");
}
else
Errors.throwParserException(" while error");
// While(..) {...}
return (OperandToken)( new WhileOperatorToken(whileRelation, whileCode));
}
/***********************************************************************************/
/** this method parses for loops */
/* (e.g. for(z=0;z<10;z=z+1) { disp(z); } endfor */
/* @param */
/* @param */
/* @return */
private OperandToken parseFor()
{
OperandToken forInitialisation = null;
OperandToken forRelation = null;
OperandToken forIncrement = null;
//skip the opening bracket
//Token dummy = peekNextToken();
if(isExpectedDelimiter(peekNextToken(), '(') )
{
//skip the opening bracket
getNextToken();
ErrorLogger.debugLine("Parser: for loop");
// get arguments inside (...;...;...)
forInitialisation = parseArithExpression(SINGLE);
ErrorLogger.debugLine("Parser: for: initialisation = " + forInitialisation.toString());
if (!isExpectedDelimiter(peekNextToken(), ';' ))
Errors.throwParserException("For: missing ;");
else
getNextToken();
forRelation = parseArithExpression(SINGLE);
ErrorLogger.debugLine("Parser: for: relation = " + forRelation.toString());
if (!isExpectedDelimiter(peekNextToken(), ';' ))
Errors.throwParserException("For: missing ;");
else
getNextToken();
forIncrement = parseArithExpression(SINGLE);
ErrorLogger.debugLine("Parser: for: increment = " + forIncrement.toString());
if (!isExpectedDelimiter(peekNextToken(), ')' ))
Errors.throwParserException("For: missing )");
else
getNextToken();
}
else
{
// e.g. for i=1:4
// e.g. for i=x
// e.g. for i=[1,3,5]
ErrorLogger.debugLine("Parser: FOR vector for loop");
// get arguments inside for < >, ... (e.g. for x=[1,2,3], ...)
forInitialisation = parseArithExpression(SINGLE); //MATRIX); //SINGLE);
// get rid of the closing , ; \n
// e.g. for i=2:5,
// e.g. for i=2:5;
// e.g. for i=2:5\n
if (!isExpectedDelimiter(peekNextToken(), ';' ) &&
!isExpectedDelimiter(peekNextToken(), ',' ) &&
!isExpectedDelimiter(peekNextToken(), '\n') )
Errors.throwParserException("For: missing ; , \\n");
else
getNextToken();
ErrorLogger.debugLine("ParserFOR" + peekNextToken());
//if (!isExpectedDelimiter(peekNextToken(), ',' ) ||
// !isExpectedDelimiter(peekNextToken(), '\n' ) )
// Errors.throwParserException("For: missing , or \\n");
//else
// getNextToken();
ErrorLogger.debugLine("Parser: for: initialisation = " + forInitialisation.toString());
}
// get commands inside {...}
OperandToken forCode = parseCommandList();
//if (peekNextToken() instanceof DelimiterToken)
// getNextToken();
if(isExpectedDelimiter(peekNextToken(), "end") ||
isExpectedDelimiter(peekNextToken(), "endfor") )
{
getNextToken();
ErrorLogger.debugLine("Parser: for: end");
}
else
Errors.throwParserException(" for error");
ErrorLogger.debugLine("Parser: for: code = "+forCode.toString());
// For(...;...;...) {...}
return new ForOperatorToken(forInitialisation, forRelation, forIncrement, forCode);
}
/***********************************************************************************/
/** this method parses matrices (e.g. a=[1,2,3;4,5,6] or a=[1 2 3]) */
/* @return parsed matrix */
private OperandToken parseMatrix()
{
boolean endLine = false; //
boolean endMatrix = false; //
int x = 0; // x-size of matrix
int y = 1; // y-size of matrix
Stack elements = new Stack(); // stack for elements
Stack rowLength = new Stack(); //
boolean numberB = true; //
boolean singleB = true; //
boolean numberIndicatorB = false; //
boolean singleIndicatorB = false; //
boolean imagIndicatorB = false; //
// remove spaces between "[" and first element (e.g. [ 2,3] -> [2,3]
while (isExpectedDelimiter(peekNextToken(MATRIX), ' '))
getNextToken();
// parse code of matrices (e.g. [1,2,3;4,5,6] or [1 sin(2) 3; 4 5+1 a]
while(!endMatrix)
{
// get next parameter (whitespaces are treated as delimiter, too)
OperandToken nextParameter = parseArithExpression(MATRIX);
numberIndicatorB = false;
singleIndicatorB = false;
// check type of each parameter: some operands need special attention
if (nextParameter instanceof Expression)
{
Expression expr = (Expression)nextParameter;
if (expr.getData() == null)
{
if (expr.getNumberOfChildren() == 1)
{
// there is only one parameter
singleIndicatorB = true;
}
}
}
else if (nextParameter instanceof DoubleNumberToken)
{
// this parameter is a number token
DoubleNumberToken numberT = (DoubleNumberToken)nextParameter;
// check if matrix has imaginary values
if (numberT.getValuesIm() != null)
imagIndicatorB = true;
// Check if this number token is a scalar. Otherwise deal with
// it like a general matrix
if((numberT.getSizeX()==1) && (numberT.getSizeY()==1))
numberIndicatorB = true;
}
if (numberIndicatorB == false)
{
// at least one element of the matrix is NOT a number
numberB = false;
}
if (singleIndicatorB == false)
{
// at least one element is not a single operand
singleB = false;
}
ErrorLogger.debugLine("Parser: para" + nextParameter);
// push parameter onto element stack
if (nextParameter != null)
elements.push(nextParameter);
DelimiterToken t = (DelimiterToken)peekNextToken(MATRIX);
if((t.value == ',') ||
(t.value == ' ') )
{
//this marks the end of a matrix element
ErrorLogger.debugLine("Parser: Matrix ,");
getNextToken(MATRIX);
x++;
}
else if((t.value == ';') ||
(t.value == '\n') ||
(t.value == '\r') )
{
//this marks the end of a row
getNextToken(MATRIX);
x++;
ErrorLogger.debugLine("Parser: Matrix ; length "+x);
rowLength.push(new Integer(x)); // save row length
x=0;
y++; // increment row counter
}
else if(t.value == ']')
{
//this marks the end of the matrix
getNextToken(MATRIX);
x++;
rowLength.push(new Integer(x)); // save row length
ErrorLogger.debugLine("Parser: Matrix y="+y+" x="+x);
endMatrix = true;
}
else
{
Errors.throwParserException(" matrix error");
}
} // end while
// create matrix of correct size
if (numberB)
{
// the parsed matrix is a pure number array
ErrorLogger.debugLine("Parser: matrix pure numbers");
// length of rows must be equal
for (int yy=y-1; yy>=0; yy--)
{
if ( ((Integer)rowLength.pop()).intValue() != x)
Errors.throwParserException(" Matrix: all rows must have the same length");
}
double values[][] = new double[y][x];
double valuesImag[][] = new double[1][1];
if (imagIndicatorB)
valuesImag = new double[y][x];
// fill array with double values from element stack
for (int yy=y-1; yy>=0; yy--)
{
for (int xx=x-1; xx>=0; xx--)
{
DoubleNumberToken n = (DoubleNumberToken)elements.pop();
values[yy][xx] = n.getValueRe();
if (imagIndicatorB)
{
valuesImag[yy][xx] = n.getValueIm();
}
}
}
if (!imagIndicatorB)
return (OperandToken)(new DoubleNumberToken(values));
else
return (OperandToken)(new DoubleNumberToken(values, valuesImag));
}
else if (singleB)
{
// pure operands (e.g. variables..., [a,b,c])
ErrorLogger.debugLine("Parser: matrix pure operands");
OperandToken values[][] = new OperandToken[y][x];
// fill array with operands from element stack
for (int yy=y-1; yy>=0; yy--)
{
// row length may vary, e.g. a=[b;c,d]
x = ((Integer)rowLength.pop()).intValue();
values[yy] = new OperandToken[x];
for (int xx=x-1; xx>=0; xx--)
{
Expression expr = (Expression)elements.pop();
values[yy][xx] = (OperandToken)expr.getChild(0);
}
}
return new MatrixToken(values);
}
else if (x==1 && y==1 && elements.empty() )
{
// this is supposed to be an empty array
ErrorLogger.debugLine("Parser: matrix: empty array");
return new DoubleNumberToken(); // return empty DoubleNumberToken
}
else
{
// mixed numbers and expressions
OperandToken values[][] = new OperandToken[y][1];
// fill array with tokens from element stack
for (int yy=y-1; yy>=0; yy--)
{
// row length may vary, e.g. a=[1,2,3;b] with b=[1,2,3]
x = ((Integer)rowLength.pop()).intValue();
values[yy] = new OperandToken[x];
ErrorLogger.debugLine("Parser: matrix: row length: "+x);
for (int xx=x-1; xx>=0; xx--)
{
values[yy][xx] = (OperandToken)(elements.pop());
}
}
return (OperandToken)(new MatrixToken(values));
}
} // end parseMatrix
/***********************************************************************************/
/** this method parses cell arrays (e.g. a={1, "barfoo", rand(3)} ) */
/* @return parsed cell array */
private OperandToken parseCellArray()
{
boolean endMatrix = false; //
int x = 0; // x-size of matrix
int y = 1; // y-size of matrix
Stack elements = new Stack(); // stack for elements
int rowLength = 0; //
// remove spaces between "{" and first element (e.g. { 2,3} -> {2,3}
while (isExpectedDelimiter(peekNextToken(MATRIX), ' '))
getNextToken();
// parse code of cell array (e.g. {1, rand(3); "hello", 4+5}
while(!endMatrix)
{
// get next parameter (whitespaces are treated as delimiter, too)
OperandToken nextParameter = parseArithExpression(MATRIX);
ErrorLogger.debugLine("Parser: cell para" + nextParameter);
// push parameter onto element stack
if (nextParameter != null)
elements.push(nextParameter);
DelimiterToken t = (DelimiterToken)peekNextToken(MATRIX);
if((t.value == ',') ||
(t.value == ' ') )
{
//this marks the end of a matrix element
ErrorLogger.debugLine("Parser: CellArray ,");
getNextToken(MATRIX);
x++;
}
else if((t.value == ';') ||
(t.value == '\n') ||
(t.value == '\r') )
{
//this marks the end of a row
getNextToken(MATRIX);
x++;
ErrorLogger.debugLine("Parser: CellArray ; length "+x);
if ((rowLength>0) && (rowLength!=x))
Errors.throwParserException(" Cell Array: unequal rows");
rowLength = x; // save row length
x = 0; // reset column count
y++; // increment row counter
}
else if(t.value == '}')
{
//this marks the end of the matrix
getNextToken(MATRIX);
x++;
if ((rowLength>0) && (rowLength!=x))
Errors.throwParserException(" Cell Array: unequal rows }");
ErrorLogger.debugLine("Parser: CellArray y="+y+" x="+x);
endMatrix = true;
}
else
Errors.throwParserException(" CellArray error");
} // end while
// check if this is supposed to be an empty array
if (x==1 && y==1 && elements.empty() )
{
ErrorLogger.debugLine("Parser: cell: empty array");
return new CellArrayToken(); // return empty CellToken
}
// created final array of operands
OperandToken values[][] = new OperandToken[y][x];
// fill array with tokens from element stack
for (int yy=y-1; yy>=0; yy--)
{
for (int xx=x-1; xx>=0; xx--)
{
values[yy][xx] = (OperandToken)(elements.pop());
}
}
return (OperandToken)(new CellArrayToken(values));
} // end parseCellArray
/***************************************************************************************/
/******** additional/helper methods ***********/
/***************************************************************************************/
/***********************************************************************************/
/** return false if an expression is terminated by "," */
/** return true if an expression is terminated by something else ", EOF" */
private boolean isDisplayResultToken(Token token)
{
// if expression is terminated be nothing it should be displayed
if (token == null)
return true;
if(token instanceof DelimiterToken)
{
if ( ((DelimiterToken)token).value == ';')
{
// expression is terminated by ";" don't display result
//ErrorLogger.debugLine("Parser: setDisplayResult(false)");
return false;
}
// expression is terminated by delimiter unequal ";"
return true;
}
// expression is not terminated by a delimiter
return false;
}
/***********************************************************************************/
/** return false if the token is no delimiter OR not the specified char */
/** return true if the token is a delimiter and is the specified char, e.g. ,;(){}*/
private boolean isExpectedDelimiter(Token token, char c)
{
// check type of token
if(!(token instanceof DelimiterToken))
return false;
// check if value of delimiter token is as expected
if( ((DelimiterToken)token).value != c)
return false;
// token IS a delimiter token AND the value is as expected
return true;
}
private boolean isExpectedDelimiter(Token token, String c)
{
// check type of token
if(!(token instanceof DelimiterToken))
return false;
// check if value of delimiter token is as expected
if( ! ( ((DelimiterToken)token).getWordValue().equals(c) ) )
return false;
// token IS a delimiter token AND the value is as expected
return true;
}
} // end class