Given an expression with operators, functions, and operands, such as:
2 + sin ( max ( 2, 3 ) / 3 * 3.1415 )
How can I programmatically validate the expression, such that any functions must have the correct number of parameters? For example abs,sin,cos must have exactly 1 parameter, whereas sum,avg,max,min have 2 or more.
Given that each parameter can itself be a very complicated expression, it seems non-trivial to programmatically determine this. I have already written a lexical tokenizer (lexer), and I've managed to convert the expression to postfix/RPN. (Which is: 2 3 max 3 / 3.1415 * sin 2 +). I am still no closer to a solution.
I would appreciate some code or pseudocode that will guide me in writing something from scratch. Java would be great.
Below is my lexer code:
    public static List<Token> shunt(List<Token> tokens) throws Exception {
    List<Token> rpn = new ArrayList<Token>();
    Iterator<Token> it = tokens.iterator();
    Stack<Token> stack = new Stack<Token>();
    while (it.hasNext()) {
        Token token = it.next();
        if (Type.NUMBER.equals(token.type))
            rpn.add(token);
        if (Type.FUNCTION.equals(token.type) || Type.LPAREN.equals(token.type)) 
            stack.push(token);
        if (Type.COMMA.equals(token.type)) {
            while (!stack.isEmpty() && !Type.LPAREN.equals(stack.peek().type))
                rpn.add(stack.pop());
            if (stack.isEmpty()) 
                throw new Exception("Missing left parenthesis!");
        }
        if (Type.OPERATOR.equals(token.type)) {
            while (!stack.isEmpty() && Type.OPERATOR.equals(stack.peek().type))
                rpn.add(stack.pop());
            stack.add(token);
        }
        if (Type.RPAREN.equals(token.type)) {
            while (!stack.isEmpty() && !Type.LPAREN.equals(stack.peek().type))
                rpn.add(stack.pop());
            if (stack.isEmpty()) 
                throw new Exception("Missing left parenthesis!");
            stack.pop();
            if (!stack.isEmpty() && Type.FUNCTION.equals(stack.peek().type))
                rpn.add(stack.pop());
        }
    }
    while (!stack.isEmpty()) {
        if (Type.LPAREN.equals(stack.peek().type) || Type.RPAREN.equals(stack.peek().type))
            throw new Exception("Mismatched parenthesis!");
        rpn.add(stack.pop());
    }
    return rpn;
}
 
     
     
    