package com.singularsys.jep.misc;
import java.util.ArrayList;
import java.util.List;
import com.singularsys.jep.Jep;
import com.singularsys.jep.JepMessages;
import com.singularsys.jep.NodeFactory;
import com.singularsys.jep.Operator;
import com.singularsys.jep.ParseException;
import com.singularsys.jep.PostfixMathCommandI;
import com.singularsys.jep.configurableparser.GrammarParser;
import com.singularsys.jep.configurableparser.Lookahead2Iterator;
import com.singularsys.jep.configurableparser.matchers.GrammarException;
import com.singularsys.jep.configurableparser.matchers.GrammarMatcher;
import com.singularsys.jep.configurableparser.tokens.OperatorToken;
import com.singularsys.jep.configurableparser.tokens.TerminatorToken;
import com.singularsys.jep.configurableparser.tokens.Token;
import com.singularsys.jep.parser.Node;
/**
* A GrammarMatcher which matches functions in the form '+(x,y)' where
+ is an operator.
*/
public class OperatorAsFunctionGrammarMatcher implements GrammarMatcher {
private static final long serialVersionUID = 300L;
/**
* @serial
*/
private final Token open; // = new SymbolToken("(");
/**
* @serial
*/
private final Token close; // = new SymbolToken(")");
/**
* @serial
*/
private final Token comma; // = ",";
/**
* @serial
*/
private List<Operator> operators;
private transient NodeFactory nf;
/**
* Create a OperatorAsFunctionGrammarMatcher
* @param open token representing an opening bracket
* @param close token representing a closing bracket
* @param comma token representing a list item separator
* @param operators list of operators which will be matched
*/
public OperatorAsFunctionGrammarMatcher(Token open, Token close,
Token comma, List<Operator> operators) {
this.open = open;
this.close = close;
this.comma = comma;
this.operators = operators;
}
public void init(Jep jep) {
nf = jep.getNodeFactory();
}
/**
* Generate a token to use in GrammarExecptions
* @param it used to get current position
* @return a TerminatorToken
*/
protected Token errorToken(Lookahead2Iterator<Token> it) {
Token t2 = it.peekNext();
if(t2==null) {
Token t3 = it.prev();
t2 = new TerminatorToken(JepMessages.getString("configurableparser.matchers.FunctionGrammarMatcher.TerminatorTokenName"));
//$NON-NLS-1$
t2.setPosition(t3.getLineNumber(), t3.getColumnNumber());
}
return t2;
}
/**
* Attempt to match a function, calls the
GrammarParser.parseSubExpression()
* to match function arguments.
*/
public Node match(Lookahead2Iterator<Token> it, GrammarParser
parser) throws ParseException {
Token t = it.peekNext();
if(t==null) return null;
if(!t.isOperator()) return null;
OperatorToken ot = (OperatorToken) t;
Operator matchedOp=null;
for(Operator op:operators) {
if(ot.getBinaryOp()==op || ot.getPrefixOp()==op ||
ot.getSuffixOp()==op)
matchedOp=op;
}
if(matchedOp==null) return null;
String name = t.getSource();
PostfixMathCommandI pfmc = matchedOp.getPFMC();
if(!open.equals(it.nextnext())) return null;
it.consume();
it.consume();
if(close.equals(it.peekNext())) {
if(!pfmc.checkNumberOfParameters(0)) {
int req = pfmc.getNumberOfParameters();
if(req>=0)
throw new
GrammarException(String.format(JepMessages.getString(
"FunctionRequiresNArgumentsFoundN"), //$NON-NLS-1$
pfmc.getName(),req,0),errorToken(it));
throw new GrammarException(String.format(JepMessages.getString(
"FunctionIllegalNumberOfArguments"),pfmc.getName(),0),errorToken(it));
//$NON-NLS-1$
}
it.consume();
return nf.buildFunctionNode(name, pfmc,new Node[0]);
}
List<Node> seq=new ArrayList<Node>();
while(true) {
Node contents = parser.parseSubExpression();
seq.add(contents);
if(close.equals(it.peekNext())) // this way round to cope with null
break;
else if(comma.equals(it.peekNext()))
it.consume();
else
throw new
GrammarException(String.format(JepMessages.getString("configurableparser.matchers.FunctionGrammarMatcher.Function"),pfmc.getName()),close,errorToken(it));
//$NON-NLS-1$
}
it.consume();
if(!pfmc.checkNumberOfParameters(seq.size())) {
int req = pfmc.getNumberOfParameters();
if(req>=0)
throw new GrammarException(String.format(JepMessages.getString(
"FunctionRequiresNArgumentsFoundN"), //$NON-NLS-1$
pfmc.getName(),req,seq.size()),errorToken(it));
throw new GrammarException(String.format(JepMessages.getString(
"FunctionIllegalNumberOfArguments"), //$NON-NLS-1$
pfmc.getName(),seq.size()),
it.prev());
}
return nf.buildFunctionNode(name, pfmc,seq.toArray(new
Node[seq.size()]));
}
}
It allows selected operators to be treated as functions, and can be
added to the parse as
cp.addGrammarMatcher(new OperatorAsFunctionGrammarMatcher(
cp.getSymbolToken("("),
cp.getSymbolToken(")"),
cp.getSymbolToken(","),
Arrays.asList(newOr2) // list of operators
));
A full example would be
@Test
public void testOperatorsAsFunctions() throws ParseException, Exception {
ot.addOperator(new EmptyOperatorTable.OperatorKey() {},
newOr1, defaultOr);
Operator newOr2 = new Operator("or", defaultOr.getPFMC(),
defaultOr.getFlags());
ot.addOperator(new EmptyOperatorTable.OperatorKey() {},
newOr2, defaultOr);
cp.addGrammarMatcher(new OperatorAsFunctionGrammarMatcher(
cp.getSymbolToken("("),
cp.getSymbolToken(")"),
cp.getSymbolToken(","),Arrays.asList(newOr2 )));
// Add logical functions as alternatives to the default operators.
//jep.getFunctionTable().addFunction("or", new Or());
// Notify other components of change in operator and function table.
jep.reinitializeComponents();
// Test it
jep.addVariable("x", 2);
List<String> formulas = new ArrayList<String>();
//formulas.add("sin(x)");
formulas.add("x > 1 or x < -1");
formulas.add("or(x > 1, x < -1)");
formulas.add("x > 1 || x < -1");
formulas.add("x > 1 | x < -1");
for (String formula : formulas) {
Node n = jep.parse(formula);
Object result = jep.evaluate(n);
System.out.println(String.format("\"%s\" = \"%s\" =
%s", formula, jep.toString(n), result));
}
}
Richard
> --
> You received this message because you are subscribed to the Google Groups "Jep Java Users" group.
> To post to this group, send email to jep-...@googlegroups.com.
> To unsubscribe from this group, send email to jep-users+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/jep-users?hl=en.
>