split("A|B|C|D", "|")[2]
The solution would depend on which version for Jep your using. In Jep
2.4 you would need to modify the javacc grammar in
org/nfunk/jep/Parser.jjt. In Jep 3.4 you could modify the grammar
using the ConfigurableParser
http://www.singularsys.com/jep/doc/html/confparser.html
You would need to add a new
com.singularsys.jep.configurableparser.matchers.GrammarMatcher
which would match the syntax you needed.
Rich
In Jep 3.4 you can
> --
> You received this message because you are subscribed to the Google Groups
> "Jep Java Users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/jep-users/-/3xr5M07Jrk8J.
> 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.
>
public class ArrayFunctionGrammarMatcher 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; // = ","; private final Token arrayOpen; private final Token arrayClose; private transient NodeFactory nf; private transient OperatorTableI ot;
/** * Create a FunctionGrammarMatcher * @param open token representing an opening bracket * @param close token representing a closing bracket * @param comma token representing a list item separator */
public ArrayFunctionGrammarMatcher(Token open, Token close, Token comma,Token aopen, Token aclose) { this.open = open; this.close = close; this.comma = comma; this.arrayOpen = aopen; this.arrayClose = aclose; }
@Override public void init(Jep j) { nf = j.getNodeFactory(); ot = j.getOperatorTable(); }
/** * 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) { t2 = new TerminatorToken("Function Grammar Matcher"); } return t2; } /** * Attempt to match a function, calls the GrammarParser.parseSubExpression() * to match function arguments. */ @Override public Node match(Lookahead2Iterator<Token> it, GrammarParser parser) throws ParseException { Token t = it.peekNext(); if(t==null) return null; if(!t.isFunction()) return null; String name = t.getSource(); PostfixMathCommandI pfmc = ((FunctionToken) t).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( "Function "+pfmc.getName() + " Requires "+ req + " arguments. Found "+ 0, errorToken(it)); throw new GrammarException( "Function "+pfmc.getName()+"Illegal Number Of Arguments"+0,errorToken(it)); //$NON-NLS-1$ } it.consume(); return nf.buildFunctionNode(name, pfmc,new Node[0]); } List<Node> seq=new ArrayList<>(); 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( "Function"+pfmc.getName()+" requre "+close,errorToken(it)); //$NON-NLS-1$ } it.consume(); if(!pfmc.checkNumberOfParameters(seq.size())) { int req = pfmc.getNumberOfParameters(); if(req>=0) throw new GrammarException( "Function "+pfmc.getName() + " Requires "+ req + " arguments. Found "+ 0, errorToken(it)); throw new GrammarException( "Function "+pfmc.getName()+"Illegal Number Of Arguments"+0,errorToken(it)); //$NON-NLS-1$ } Node functionNode = nf.buildFunctionNode(name, pfmc,seq.toArray(new Node[seq.size()]));
// Parsed full function, now check if array subscript if(!arrayOpen.equals(it.peekNext())) { return functionNode; }
// now has a array subscript List<Node> contents = new ArrayList<>(4); contents.add(functionNode);
while(arrayOpen.equals(it.peekNext())) { it.consume(); Node ele = parser.parseSubExpression(); contents.add(ele); if(!arrayClose.equals(it.peekNext())) { Token t2 = it.peekNext(); if(t2==null) { t2 = new TerminatorToken("TerminatorTokenName"); //$NON-NLS-1$ } throw new GrammarException("Array Faunction Grammar Matcher requre "+close,t2); //$NON-NLS-1$ } it.consume(); } Node n = nf.buildOperatorNode( ot.getEle(), contents.toArray(new Node[contents.size()])); return n;
} }
ConfigurableParser cp = new ConfigurableParser(); cp.addHashComments(); cp.addSlashComments(); cp.addDoubleQuoteStrings(); cp.addWhiteSpace(); cp.addTokenMatcher( NumberTokenMatcher.defaultNumberTokenMatcher()); cp.addExponentNumbers(); cp.addTokenMatcher(new OperatorTokenMatcher()); cp.addSymbols("(",")","[","]"); cp.setImplicitMultiplicationSymbols("(","["); cp.addIdentifiers(); cp.addSemiColonTerminator(); cp.addWhiteSpaceCommentFilter(); cp.addBracketMatcher("(",")");
// No longer want the standard function matcher //cp.addFunctionMatcher("(",")",",");
// Add the new matcher
cp.addGrammarMatcher(new ArrayFunctionGrammarMatcher( cp.getSymbolToken("("), cp.getSymbolToken(")"), cp.getSymbolToken(","), cp.getSymbolToken("["), cp.getSymbolToken("]") )); cp.addListMatcher("[","]",","); cp.addArrayAccessMatcher("[","]");
jep = new Jep(); jep.setComponent(cp); jep.reinitializeComponents();
class SeqFun extends UnaryFunction { private static final long serialVersionUID = 1L;
@Override public Object eval(Object arg) throws EvaluationException { Vector<Object> res = new Vector<>(); int n = this.asInt(0, arg); for(int i=1;i<=n;++i) { res.add(Double.valueOf(i)); } return res; } }
@Test public void simpleTest() throws Exception { jep.addFunction("seq",new SeqFun()); Node n2 = jep.parse("seq(3)[2]"); Object o2 = jep.evaluate(n2); assertEquals(2.0, o2); }
/**
* Parsers to allow indexed access to a value list that is a result of an evaluated function, i. e. parses expressions like <tt>function(...)[index]</tt>.
*/
public class IndexedFunctionGrammarMatcher implements GrammarMatcher {
private static final long serialVersionUID = 300L;
private final Token comma = new SymbolToken(",");
private final Token openingBracket = new SymbolToken("(");
private final Token closingBracket = new SymbolToken(")");
private final Token openingSquareBracket = new SymbolToken("[");
private final Token closingSquareBracket = new SymbolToken("]");
private transient Jep jep;
@Override
public Node match(final Lookahead2Iterator<Token> iterator, final GrammarParser parser) throws ParseException {
Token nextToken;
Token token = iterator.peekNext();
if (token == null || !token.isFunction() || !openingBracket.equals(iterator.nextnext())) {
return null;
}
// Get access to function definition and function name.
PostfixMathCommandI function = ((FunctionToken) token).getPfmc();
String functionName = token.getSource();
// Process function token and opening bracket.
iterator.consume();
iterator.consume();
// Check whether any function arguments have been provided. If no arguments have been provided, the function must not expect any arguments, too.
// Otherwise raise a grammar exception.
nextToken = iterator.peekNext();
if (closingBracket.equals(nextToken)) {
if (!function.checkNumberOfParameters(0)) {
throw new GrammarException(String.format("Missing parameter in function '%s'.", functionName), closingBracket);
}
// Process closing bracket.
iterator.consume();
// Create and return the node representing the function.
return jep.getNodeFactory().buildFunctionNode(functionName, function, new Node[0]);
}
// Process function arguments.
List<Node> functionArgs = new ArrayList<>();
while (true) {
nextToken = iterator.peekNext();
functionArgs.add(parser.parseSubExpression());
// After processing of a function argument, either a closing bracket or a comma (as delimiter for further function arguments) is expected.
if (closingBracket.equals(iterator.peekNext())) {
break;
}
if (!comma.equals(iterator.peekNext())) {
throw new GrammarException(String.format("Missing '%s' in function '%s'.", closingBracket.getSource(), functionName), nextToken);
}
// Process comma.
iterator.consume();
}
// Check whether the number of provided function arguments matches the number of expected function arguments.
nextToken = iterator.peekNext();
if (!function.checkNumberOfParameters(functionArgs.size())) {
throw new GrammarException(String.format("Missing parameter in function '%s'.", functionName), nextToken);
}
// Process closing bracket.
iterator.consume();
// Create the node representing the function.
// At this step the function has been fully parsed.
Node functionNode = jep.getNodeFactory().buildFunctionNode(functionName, function, functionArgs.toArray(new Node[functionArgs.size()]));
// Check for opening square bracket (indexed access).
if (!openingSquareBracket.equals(iterator.peekNext())) {
return functionNode;
}
// Process opening square bracket.
iterator.consume();
// Process index and check whether it is a positive integer number.
nextToken = iterator.peekNext();
Node indexNode = parser.parseSubExpression();
if (!Convert.isInteger(indexNode.getValue()) || Convert.toInteger(indexNode.getValue(), 0) < 1) {
throw new GrammarException(String.format("'%s' is not considered to be a valid element index.", nextToken.getSource()), nextToken);
}
// Ensure the closing square bracket comes next.
nextToken = iterator.peekNext();
if (!closingSquareBracket.equals(iterator.peekNext())) {
throw new GrammarException(String.format("Function '%s' expects '%s'.", functionName, closingSquareBracket.getSource()), nextToken);
}
// Process closing square bracket.
iterator.consume();
// Create and return the node representing the function as well as the indexed access.
return jep.getNodeFactory().buildOperatorNode(jep.getOperatorTable().getEle(), new Node[]{ functionNode, indexNode });
}
@Override
public void init(final Jep jep) {
this.jep = jep;
}
}
ConfigurableParser cp = new ConfigurableParser();
cp.addHashComments();
cp.addSlashComments();
cp.addDoubleQuoteStrings();
cp.addSingleQuoteStrings();
cp.addWhiteSpace();
cp.addExponentNumbers();
cp.addOperatorTokenMatcher();
cp.addSymbols("(", ")", "[", "]", ",");
//cp.setImplicitMultiplicationSymbols("(", "[");
cp.addTokenMatcher(IdentifierTokenMatcher.dottedIndetifierMatcher());
cp.addGrammarMatcher(new IndexedFunctionGrammarMatcher());
cp.addSemiColonTerminator();
cp.addWhiteSpaceCommentFilter();
cp.addBracketMatcher("(", ")");
cp.addFunctionMatcher("(", ")", ",");
cp.addListMatcher("[", "]", ",");
cp.addArrayAccessMatcher("[", "]");
/** * Parsers to allow index access to an array[4,5,6][2]. */ public class IndexedArrayGrammarMatcher implements GrammarMatcher {
private static final long serialVersionUID = 300L;
private final Token comma = new SymbolToken(",");
private final Token open = new SymbolToken("["); private final Token close = new SymbolToken("]");
private transient NodeFactory nf; private transient Operator list;
public void init(Jep jep) { nf = jep.getNodeFactory(); list = jep.getOperatorTable().getList();
}
public Node match(Lookahead2Iterator<Token> it, GrammarParser parser) throws ParseException {
if (!open.equals(it.peekNext())) return null; it.consume(); if (close.equals(it.peekNext())) { it.consume(); return nf.buildOperatorNode(list, 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("List", close, it.peekNext()); } it.consume(); Node inner = nf.buildOperatorNode(list, seq.toArray(new Node[seq.size()])); if (!open.equals(it.peekNext())) { return inner; }
List<Node> arguments = new ArrayList<Node>(); arguments.add(inner); while (open.equals(it.peekNext())) {
// Process opening square bracket.
it.consume();
// Process index and check whether it is a positive integer
// number. Token nextToken = it.peekNext();
Node indexNode = parser.parseSubExpression(); if (!Convert.isInteger(indexNode.getValue()) || Convert.toInteger(indexNode.getValue(), 0) < 1) { throw new GrammarException( String.format("'%s' is not considered to be a valid element index.", nextToken.getSource()), nextToken); }
// Ensure the closing square bracket comes next.
nextToken = it.peekNext(); if (!close.equals(it.peekNext())) { throw new GrammarException(String.format("Index array expects '%s'.", close.getSource()), nextToken); } arguments.add(indexNode);
// Process closing square bracket.
it.consume();
}
// Create and return the node representing the function as well
// as the indexed access. inner = jep.getNodeFactory().buildOperatorNode(jep.getOperatorTable().getEle(), arguments.toArray(new Node[arguments.size()]));
return inner; } }
class SeqFun extends UnaryFunction { private static final long serialVersionUID = 1L;
@Override public Object eval(Object arg) throws EvaluationException {
Vector<Object> res = new Vector<Object>();
int n = this.asInt(0, arg); for (int i = 1; i <= n; ++i) { res.add(Double.valueOf(i)); } return res; } }
@Test public void testAnonArrayAccess() throws JepException {
ConfigurableParser cp = new ConfigurableParser(); cp.addHashComments(); cp.addSlashComments(); cp.addDoubleQuoteStrings(); cp.addSingleQuoteStrings(); cp.addWhiteSpace(); cp.addExponentNumbers(); cp.addOperatorTokenMatcher(); cp.addSymbols("(", ")", "[", "]", ",");
// cp.setImplicitMultiplicationSymbols("(", "["); cp.addTokenMatcher(IdentifierTokenMatcher.dottedIndetifierMatcher()); cp.addGrammarMatcher(new IndexedFunctionGrammarMatcher()); cp.addGrammarMatcher(new IndexedArrayGrammarMatcher());
cp.addSemiColonTerminator(); cp.addWhiteSpaceCommentFilter(); cp.addBracketMatcher("(", ")");
// cp.addFunctionMatcher("(", ")", ","); // cp.addListMatcher("[", "]", ","); cp.addArrayAccessMatcher("[", "]");
Jep jep = new Jep(cp); jep.addFunction("seq", new SeqFun());
{ Node n2 = jep.parse("x=[7,8,9]"); Object o2 = jep.evaluate(n2); assertEquals("[7.0, 8.0, 9.0]", o2.toString()); } { Node n2 = jep.parse("x[3]"); Object o2 = jep.evaluate(n2); assertEquals(9.0, o2); }
{
Node n2 = jep.parse("seq(3)[2]"); Object o2 = jep.evaluate(n2); assertEquals(2.0, o2); }
{ Node n2 = jep.parse("[4, 5, 6][2]"); jep.println(n2); (new PrefixTreeDumper()).dump(n2); Object o2 = jep.evaluate(n2); assertEquals(5.0, o2); } { Node n2 = jep.parse("[3, [4, 5], 6][3]"); jep.println(n2); (new PrefixTreeDumper()).dump(n2); Object o2 = jep.evaluate(n2); assertEquals(6.0, o2); } { Node n2 = jep.parse("[[1, 2], [3, 4], [5, 6]][3][1]"); jep.println(n2); (new PrefixTreeDumper()).dump(n2); Object o2 = jep.evaluate(n2); assertEquals(5.0, o2); } }
static class SuffixArrayAccessShuntingYard extends ShuntingYard {
private final Token comma = new SymbolToken(","); private final Token open = new SymbolToken("["); private final Token close = new SymbolToken("]");
public SuffixArrayAccessShuntingYard(Jep jep, List<GrammarMatcher> gm) { super(jep, gm); }
@Override protected void prefixSuffix() throws ParseException { // if(DUMP) dumpState("PS"); prefix(); Token t; while(true) { t = it.peekNext(); if(open.equals(t)) {
List<Node> arguments = new ArrayList<Node>();
Node lhs = nodes.pop(); arguments.add(lhs);
while (open.equals(it.peekNext())) {
// Process opening square bracket. it.consume();
// Process index and check whether it is a positive integer // number. Token nextToken = it.peekNext();
Node indexNode = this.parseSubExpression();
if (!Convert.isInteger(indexNode.getValue()) || Convert.toInteger(indexNode.getValue(), 0) < 1) { throw new GrammarException( String.format("'%s' is not considered to be a valid element index.", nextToken.getSource()), nextToken); }
// Ensure the closing square bracket comes next. nextToken = it.peekNext(); if (!close.equals(it.peekNext())) { throw new GrammarException(String.format("Index array expects '%s'.", close.getSource()), nextToken); } arguments.add(indexNode); // Process closing square bracket. it.consume();
}
// Create and return the node representing the function as well // as the indexed access.
Node inner = jep.getNodeFactory().buildOperatorNode(jep.getOperatorTable().getEle(), arguments.toArray(new Node[arguments.size()]));
nodes.push(inner); } else if(t==null || !t.isSuffix()) { break; } else { pushOp(((OperatorToken)t).getSuffixOp(),t); it.consume(); } } } }
public static class SuffixArrayAccessShuntingYardGrammarParserFactory implements GrammarParserFactory,Serializable { private static final long serialVersionUID = 340L; /** * Create a new ShuntingYard instance. */ public GrammarParser newInstance(ConfigurableParser cp) { return new SuffixArrayAccessShuntingYard(cp.getJep(),cp.getGrammarMatchers()); } }
@Test
@Test
public void testGeneralArrayAccess() throws JepException {
ConfigurableParser cp = new ConfigurableParser();
cp.addHashComments();
cp.addSlashComments();
cp.addDoubleQuoteStrings();
cp.addSingleQuoteStrings();
cp.addWhiteSpace();
cp.addExponentNumbers();
cp.addOperatorTokenMatcher();
cp.addSymbols("(", ")", "[", "]", ",");
// cp.setImplicitMultiplicationSymbols("(", "[");
cp.addTokenMatcher(IdentifierTokenMatcher.dottedIndetifierMatcher());
cp.addSemiColonTerminator();
cp.addWhiteSpaceCommentFilter();
cp.addBracketMatcher("(", ")");
cp.addFunctionMatcher("(", ")", ",");
cp.addListMatcher("[", "]", ",");
cp.setGrammarParserFactory(new SuffixArrayAccessShuntingYardGrammarParserFactory());
// cp.addArrayAccessMatcher("[", "]");
Jep jep = new Jep(cp);
jep.addFunction("seq", new SeqFun());
{
Node n2 = jep.parse("sin(pi)");
Object o2 = jep.evaluate(n2);
assertEquals(0.0, (Double) o2, 1e-9);
}
{
Node n2 = jep.parse("x=[7,8,9]");
Object o2 = jep.evaluate(n2);
assertEquals("[7.0, 8.0, 9.0]", o2.toString());
}
{
Node n2 = jep.parse("x=[7,8,9]");
Object o2 = jep.evaluate(n2);
assertEquals("[7.0, 8.0, 9.0]", o2.toString());
}
{
Node n2 = jep.parse("x[3]");
Object o2 = jep.evaluate(n2);
assertEquals(9.0, o2);
}
{
Node n2 = jep.parse("x[3]+x[2]");
Object o2 = jep.evaluate(n2);
assertEquals(17.0, o2);
}
{
Node n2 = jep.parse("seq(3)[2]");
Object o2 = jep.evaluate(n2);
assertEquals(2.0, o2);
}
{
Node n2 = jep.parse("[4, 5, 6][2]");
jep.println(n2);
(new PrefixTreeDumper()).dump(n2);
Object o2 = jep.evaluate(n2);
assertEquals(5.0, o2);
}
{
Node n2 = jep.parse("[3, [4, 5], 6][3]");
jep.println(n2);
(new PrefixTreeDumper()).dump(n2);
Object o2 = jep.evaluate(n2);
assertEquals(6.0, o2);
}
{
Node n2 = jep.parse("[[1, 2], [3, 4], [5, 6]][3][1]");
jep.println(n2);
(new PrefixTreeDumper()).dump(n2);
Object o2 = jep.evaluate(n2);
assertEquals(5.0, o2);
}
{
Node n2 = jep.parse("(x+[1,2,3])[2]");
jep.println(n2);
(new PrefixTreeDumper()).dump(n2);
Object o2 = jep.evaluate(n2);
assertEquals(10.0, o2);
}
}