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
