/* * This file is part or JMathLib * * Check it out at http://www.jmathlib.de * * Author: * (c) 2005-2009 */ package jmathlib.core.functions; import jmathlib.core.interpreter.*; import jmathlib.core.tokens.*; import jmathlib.core.constants.*; import java.util.ArrayList; /**A class for parsing user functions. M-files contain either functions or they are script files. Script files are just a couple of commands which are typed into a text file*/ public class FunctionParser extends RootObject implements TokenConstants, ErrorCodes { /**default constructor - creates the FunctionParser object with an empty expression string*/ public FunctionParser() { } /**Parse a user function @param expression the function as a string @return the UserFunction object created*/ public UserFunction parseFunction(String expr) { boolean foundMFunction = false; ErrorLogger.debugLine("FunctionParser: parseFunction"); // create a new instance of a user function //this creates a new context and pushes it on the stack UserFunction function = new UserFunction(); // create an instance of a parser Parser p = new Parser(); p.setExpression(expr); // check if the m-file starts with the keyword "function" or not // e.g. // function y=some_name(x) // y = sin(x)+3; // Token t = p.peekNextToken(); if (t instanceof VariableToken) { if (((VariableToken)t).getName().toLowerCase().equals("function")) { // the m-file is a function file ErrorLogger.debugLine("FunctionParser: found m-function"); t = p.getNextToken(); foundMFunction = true; } } // parse m-function- of m-script-file if (foundMFunction) { // parse m-function file // Possible syntax of function headers are: // (e.g. a = foo(b) ) // (e.g. [a,b] = foo(c) ) // (e.g. [a,b] = foo(c,d) ) // (e.g. foo(a) ) // (e.g. a = foo() ) // check for left hand side arguments // (e.g. [a,b,c]=foo(x) ) // (e.g.: a =foo(x) ) //ArrayList names = new ArrayList(); ArrayList returnVariables = new ArrayList(); ArrayList parameterVariables = new ArrayList(); t = p.peekNextToken(); if (t instanceof VariableToken) { //single return argument t = p.getNextToken(); String retVariable = ((VariableToken)t).getName(); //function.getLocalVariables().createVariable(retVariable); //returnCount = 1; ErrorLogger.debugLine("FunctionParser: function: 1 return value: "+retVariable); returnVariables.add(retVariable); //names.add(retVariable); } else if (t instanceof DelimiterToken) { if ( ((DelimiterToken)t).value != '[' ) Errors.throwMathLibException("FunctionParser: missing ["); t = p.getNextToken(); // parse return variables while(true) { t = p.getNextToken(); if (t instanceof VariableToken) { // variable token is a return value of the function String parameter = ((VariableToken)t).getName(); // check if return name is unique if (returnVariables.contains(parameter)) Errors.throwMathLibException("FunctionParser: return parameter "+parameter+" not unique"); // add parameter to list of parameters returnVariables.add(parameter); } else if (t instanceof DelimiterToken) { if ( ((DelimiterToken)t).value == ']' ) { // closing ']' bracket break; } else if ( ((DelimiterToken)t).value == ',' ) { // delimiter between arguments //check for alternating variable token and delimiter } else Errors.throwMathLibException("FunctionParser: wrong delimiter"); } else Errors.throwMathLibException("FunctionParser: wrong return"); } // end while } else { // no return value ErrorLogger.debugLine("FunctionParser: no return value"); } // check for assignment operator (e.g. y=sin(x)) t = p.peekNextToken(); if (t instanceof AssignmentOperatorToken) { //found a "=" token t = p.getNextToken(); ErrorLogger.debugLine("FunctionParser: found = token"); } // check for the name of this function t = p.peekNextToken(); if (t instanceof FunctionToken) { //found the name of this function t = p.getNextToken(); String functionName = ((FunctionToken)t).getName(); ErrorLogger.debugLine("FunctionParser: function name: "+functionName); //set the name of the parsed function function.setName(functionName); } else if (t instanceof VariableToken) { // e.g. y = hallo(x) //found the name of this function t = p.getNextToken(); String functionName = ((VariableToken)t).getName(); ErrorLogger.debugLine("FunctionParser: function name: "+functionName); //set the name of the parsed function function.setName(functionName); } else { // did not find a function name. Since there was the keyword "function" there // must be a name Errors.throwMathLibException("FunctionParser: no function name, but"+t.toString()); } // get "(" (e.g. a=foo"("b) ) t = p.getNextToken(); if (!(t instanceof DelimiterToken)) { // throw exception Errors.throwMathLibException("FunctionParser: not ( , but "+t.toString()); } // check for right hand side arguments (e.g. a=foo("x,y,z") ) ErrorLogger.debugLine("FunctionParser: reading right hand side arguments"); while (true) { t = p.getNextToken(); if (t instanceof VariableToken) { // variable token is a parameter of the function String parameter = ((VariableToken)t).getName(); ErrorLogger.debugLine("FunctionParser: parameter: "+parameter); // check if parameter name is unique if (parameterVariables.contains(parameter)) Errors.throwMathLibException("FunctionParser: calling parameter "+parameter+" not unique"); // add parameter to list of parameters parameterVariables.add(parameter); } else if (t instanceof DelimiterToken) { if ( ((DelimiterToken)t).value == ')' ) { // closing ')' bracket break; } else if ( ((DelimiterToken)t).value == ',' ) { // delimiter between arguments //check for alternating variable token and delimiter } else Errors.throwMathLibException("FunctionParser: wrong delimiter"); } else Errors.throwMathLibException("FunctionParser: wrong argument"); } // end parameters // set return values function.setReturnVariables( returnVariables ); // set parameters function.setParameterVariables( parameterVariables ); // parse the body of the function and store the parsed code OperandToken code = p.parseRemainingExpression(); function.setCode(code); } else { // the current function is a m-script file // parse m-script file ErrorLogger.debugLine("FuntionParser: m-script file"); // set function name to "_scriptFile" so that it is not stored as a function function.setScript(true); // parse the body of the m-script OperandToken code = p.parseRemainingExpression(); function.setCode(code); } return function; } // end parseFunction }