if (xtype == FUNC || xtype == COMMA)
break;
if (xtype == LPAREN)
throw error("')' expected", xop);
ops.remove(0);
new Operator(expr, xop.getValue(), xop.getLine());
}
ops.add(0, new Op(COMMA, token.getLine()));
opExpected = false;
continue;
}
if (opExpected && (token instanceof Id || token instanceof Other)) {
putback(token);
token = new Op(CONCAT, token.getLine());
}
if (token instanceof Op) {
final Op op = (Op)token;
if (!opExpected) {
switch (op.getValue()) {
case LPAREN:
ops.add(0, op);
continue; //next
case SUBTRACT:
op.setValue(NEGATE);
break;
case ADD:
continue; //ignore
default:
throw error("an operand expected, not "+op, op);
}
} else if (op.getValue() == RPAREN) {
int argc = 1; //zero argument has been processed when Id is found
l_pop:
while (!ops.isEmpty()) {
final Op xop = ops.remove(0);
switch (xop.getValue()) {
case FUNC:
new FunctionValue(expr, xop.getData(), argc, xop.getLine());
//fall thru
case LPAREN:
break l_pop; //done
case COMMA:
++argc;
break;
default:
new Operator(expr, xop.getValue(), xop.getLine());
}
}
if (endcc == EOPAREN && ops.isEmpty())
break; //done
continue; //next token
} else if (op.getValue() == LPAREN)
throw error("unexpected '('", op);
//push an operator
while (!ops.isEmpty()) {
final Op xop = ops.get(0);
final Operator.Type xtype = xop.getValue();
if (xtype.getPrecedence() > op.getValue().getPrecedence())
break;
//move ops[0] to expression since the precedence is GE
ops.remove(0);
new Operator(expr, xop.getValue(), xop.getLine());
}
ops.add(0, op);
opExpected = false;
} else {
if (opExpected)
throw error("an operator expected, not "+token, token);
if (token instanceof Id) {
final String nm = ((Id)token).getValue();
Token t = next(ctx);
if (!(t instanceof Op) || ((Op)t).getValue() != LPAREN) {
putback(t);
new FunctionValue(expr, nm, token.getLine()); //no parenthesis
} else { //function invocation
t = next(ctx);
if (t instanceof Op && ((Op)t).getValue() == RPAREN) {
//handle no arg invocation special, since it is not easy
//to tell the difference between f(a) vs. f()
new FunctionValue(expr, nm, 0, token.getLine()); //empty parenthesis
if (endcc == EOPAREN && ops.isEmpty())
break; //done
} else {
putback(t);
ops.add(0, new Op(FUNC, nm, token.getLine())); //pass name as op's data
continue; //opExpected still false
}
}
} else if (token instanceof Other)
new ConstantValue(expr, ((Other)token).getValue(), token.getLine());
else
throw error("unexpected "+token, token);
opExpected = true;
}
}
while (!ops.isEmpty()) {
final Op xop = ops.remove(0);
final Operator.Type xtype = xop.getValue();
if (xtype == COMMA)
throw error("unexpected ','", xop);
if (xtype == LPAREN || xtype == FUNC)
throw error("')' expected", xop);
new Operator(expr, xtype, xop.getLine());
}
if (expr.getChildren().isEmpty())
throw error("an expression expected", expr.getLine());
}