All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.vesalainen.grammar.math.MathExpressionParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 Timo Vesalainen
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.vesalainen.grammar.math;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.vesalainen.grammar.math.MathExpressionParserFactory.MathExpressionParserClass;
import static org.vesalainen.parser.ParserFeature.SingleThread;
import org.vesalainen.parser.annotation.GenClassname;
import org.vesalainen.parser.annotation.Terminal;
import org.vesalainen.parser.annotation.GrammarDef;
import org.vesalainen.parser.annotation.MathExpression;
import org.vesalainen.parser.annotation.ParseMethod;
import org.vesalainen.parser.annotation.ParserContext;
import org.vesalainen.parser.annotation.Rule;
import org.vesalainen.regex.Regex;

/**
 * MathExpressionParser parses math expression written in java style with some 
 * exceptions. Expressions are number or boolean valued. Most java.lang.Math
 * methods can be used in expression.
 * 

Example: * 1.2 * cos(x1) *

Variable names follow java identifier ruling. Variables starting with '$' * are reserved. *

Boolean valued example: * x > y && sin(z) > 0 * @author tkv * @param Type type * @param Method type * @param Field type * @param

Parameter type */ @GenClassname(MathExpressionParserClass) @GrammarDef() @Terminal(left="SQUARE", expression="[\u00b2\u2072]") @Terminal(left="CUBE", expression="[\u00b3\u2073]") @Terminal(left="PI", expression="\u03c0") @Terminal(left="SQRT", expression="\u221a") @Terminal(left="CBRT", expression="\u2218") @Terminal(left="PLUS", expression="\\+") @Terminal(left="MINUS", expression="\\-") @Terminal(left="STAR", expression="\\*") @Terminal(left="SLASH", expression="/") @Terminal(left="PERCENT", expression="%") @Terminal(left="EXP", expression="\\^") @Terminal(left="COMMA", expression="\\,") @Terminal(left="PIPE", expression="\\|") @Terminal(left="EXCL", expression="!") @Terminal(left="LBRACKET", expression="\\[") @Terminal(left="RBRACKET", expression="\\]") @Terminal(left="LPAREN", expression="\\(") @Terminal(left="RPAREN", expression="\\)") @Terminal(left="AND", expression="&&") @Terminal(left="OR", expression="\\|\\|") @Terminal(left="NOT", expression="!") @Terminal(left="EQ", expression="==?") @Terminal(left="NE", expression="!=") @Terminal(left="LT", expression="<") @Terminal(left="LE", expression="<=") @Terminal(left="GT", expression=">") @Terminal(left="GE", expression=">=") public abstract class MathExpressionParser implements MathExpressionParserIntf { /** * Parse and execute MathExpression * @param me * @param handler */ @Override public void parse(MathExpression me, ExpressionHandler handler) { Set variables = new HashSet<>(); DEH expression = doParse(me.value(), me.degrees(), handler, variables); try { expression.execute(handler); } catch (Throwable ex) { throw new RuntimeException(ex); } } /** * Parse and return expression. * @param expression * @param degrees * @param handler * @return * @throws Exception */ @Override public DEH parse(String expression, boolean degrees, ExpressionHandler handler) throws Exception { Set variables = new HashSet<>(); DEH deh = doParse(expression, degrees, handler, variables); deh.setVariables(variables); return deh; } @Override public DEH parseBoolean(String expression, boolean degrees, ExpressionHandler handler) throws Exception { Set variables = new HashSet<>(); DEH deh = doParseBoolean(expression, degrees, handler, variables); deh.setVariables(variables); return deh; } @ParseMethod(start="expression", whiteSpace={"whiteSpace", "doubleSlashComment", "hashComment", "cComment"}, features={SingleThread}) protected abstract DEH doParse( String expression, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler, @ParserContext("variables") Set variables ); @ParseMethod(start="conditionalExpression", whiteSpace={"whiteSpace", "doubleSlashComment", "hashComment", "cComment"}, features={SingleThread}) protected abstract DEH doParseBoolean( String expression, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler, @ParserContext("variables") Set variables ); @Rule("term") protected DEH expression(DEH term) { return term; } @Rule("factor") protected DEH term(DEH factor) { return factor; } @Rule("atom") protected DEH factor(DEH atom) { return atom; } @Rule({"LPAREN", "expression", "RPAREN"}) protected DEH atom(DEH expression) { return expression; } @Rule protected List expressionList() { return new ArrayList<>(); } @Rule("expression") protected List expressionList(DEH expression) { ArrayList list = new ArrayList<>(); list.add(expression); return list; } @Rule({"expressionList", "COMMA", "expression"}) protected List expressionList(List list, DEH expression) { list.add(expression); return list; } @Rule(left="expression", value={"expression", "PLUS", "term"}) protected DEH add(DEH expression, DEH term) throws Exception { expression.append(term); expression.getProxy().add(); return expression; } @Rule(left="expression", value={"expression", "MINUS", "term"}) protected DEH subtract(DEH expression, DEH term) throws Exception { expression.append(term); expression.getProxy().subtract(); return expression; } @Rule(left="term", value={"term", "STAR", "factor"}) protected DEH mul(DEH term, DEH factor) throws Exception { term.append(factor); term.getProxy().mul(); return term; } @Rule(left="term", value={"term", "SLASH", "factor"}) protected DEH div(DEH term, DEH factor) throws Exception { term.append(factor); term.getProxy().div(); return term; } @Rule(left="term", value={"term", "PERCENT", "factor"}) protected DEH mod(DEH term, DEH factor) throws Exception { term.append(factor); term.getProxy().mod(); return term; } @Rule(left="atom", value={"number"}) protected DEH num(String number) throws Exception { DEH atom = new DEH(); atom.getProxy().number(number); return atom; } @Rule(left="atom", value={"PIPE", "expression", "PIPE"}) protected DEH abs( DEH expression, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler ) throws Exception { List args = new ArrayList<>(); args.add(expression); return func("abs", args, degrees, handler); } @Rule(left="factor", value={"atom", "EXP", "factor"}) protected DEH power( DEH atom, DEH factor, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler ) throws Exception { List args = new ArrayList<>(); args.add(atom); args.add(factor); return func("pow", args, degrees, handler); } @Rule(left="atom", value={"atom", "EXCL"}) protected DEH factorial( DEH atom, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler ) throws Exception { List args = new ArrayList<>(); args.add(atom); return func("factorial", args, degrees, handler); } @Rule(left="atom", value={"atom", "SQUARE"}) protected DEH square(DEH atom) throws Exception { atom.getProxy().pow(2); return atom; } @Rule(left="atom", value={"atom", "CUBE"}) protected DEH cube(DEH atom) throws Exception { atom.getProxy().pow(3); return atom; } @Rule(left="factor", value={"SQRT", "atom"}) protected DEH sqrt( DEH atom, @ParserContext("handler") ExpressionHandler handler ) throws Exception { List args = new ArrayList<>(); args.add(atom); return func("sqrt", args, false, handler); } @Rule(left="factor", value={"CBRT", "atom"}) protected DEH cbrt( DEH atom, @ParserContext("handler") ExpressionHandler handler ) throws Exception { List args = new ArrayList<>(); args.add(atom); return func("cbrt", args, false, handler); } @Rule(left="atom", value={"PI"}) protected DEH pi(@ParserContext("handler") ExpressionHandler handler) throws Exception { DEH atom = new DEH(); atom.getProxy().loadField(handler.getField(Math.class, "PI")); return atom; } @Rule(left="neg") protected boolean none() { return false; } @Rule(left="neg", value="MINUS") protected boolean minus() { return true; } @Rule protected List indexList() throws Exception { return new ArrayList<>(); } @Rule({"indexList", "LBRACKET", "expression", "RBRACKET"}) protected List indexList(List list, DEH expression) throws Exception { list.add(expression); return list; } @Rule(left="atom", value={"neg", "identifier", "indexList"}) protected DEH variable(boolean neg, String identifier, List indexList, @ParserContext("variables") Set variables) throws Exception { variables.add(identifier); DEH atom = new DEH(); ExpressionHandler proxy = atom.getProxy(); proxy.loadVariable(identifier); if (indexList != null && !indexList.isEmpty()) { Iterator iterator = indexList.iterator(); while (iterator.hasNext()) { DEH expr = iterator.next(); proxy.setIndex(true); atom.append(expr); proxy.setIndex(false); if (iterator.hasNext()) { proxy.loadArray(); } else { proxy.loadArrayItem(); } } } if (neg) { proxy.neg(); } return atom; } @Rule(left="atom", value={"identifier", "LPAREN", "expressionList", "RPAREN"}) protected DEH func( String identifier, List funcArgs, @ParserContext("degrees") boolean degrees, @ParserContext("handler") ExpressionHandler handler ) throws Exception { DEH atom = new DEH(); ExpressionHandler proxy = atom.getProxy(); M method = handler.findMethod(identifier, funcArgs.size()); List parameters = handler.getParameters(method); assert funcArgs.size() == parameters.size(); int index = 0; for (DEH expr : funcArgs) { atom.append(expr); proxy.convertTo(handler.asType(parameters.get(index++))); if (degrees && handler.isRadianArgs(method)) { proxy.invoke(handler.getMethod(Math.class, "toRadians", double.class)); } } proxy.invoke(method); proxy.convertFrom(handler.getReturnType(method)); if (degrees && handler.isRadianReturn(method)) { proxy.invoke(handler.getMethod(Math.class, "toDegrees", double.class)); } return atom; } // Conditional @Rule("andExpression") protected DEH conditionalExpression(DEH andExpression) { return andExpression; } @Rule(value={"conditionalExpression", "OR", "andExpression"}) protected DEH conditionalExpression(DEH conditionalExpression, DEH andExpression) throws Exception { conditionalExpression.getProxy().checkOr(); conditionalExpression.append(andExpression); conditionalExpression.getProxy().or(); return conditionalExpression; } @Rule("orExpression") protected DEH andExpression(DEH orExpression) { return orExpression; } @Rule(value={"andExpression", "AND", "orExpression"}) protected DEH andExpression(DEH andExpression, DEH orExpression) throws Exception { andExpression.getProxy().checkAnd(); andExpression.append(orExpression); andExpression.getProxy().and(); return andExpression; } @Rule("conditionalAtom") protected DEH orExpression(DEH conditionalAtom) { return conditionalAtom; } @Rule(left="conditionalAtom", value={"LPAREN", "conditionalExpression", "RPAREN"}) protected DEH parenConditional(DEH conditionalExpression) { return conditionalExpression; } @Rule(left="conditionalAtom", value={"NOT", "conditionalAtom"}) protected DEH notConditional(DEH conditionalExpression) throws Exception { conditionalExpression.getProxy().not(); return conditionalExpression; } @Rule(left="conditionalAtom", value={"expression", "EQ", "expression"}) protected DEH eqConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().eq(); return exp1; } @Rule(left="conditionalAtom", value={"expression", "NE", "expression"}) protected DEH neConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().ne(); return exp1; } @Rule(left="conditionalAtom", value={"expression", "LT", "expression"}) protected DEH ltConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().lt(); return exp1; } @Rule(left="conditionalAtom", value={"expression", "LE", "expression"}) protected DEH leConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().le(); return exp1; } @Rule(left="conditionalAtom", value={"expression", "GT", "expression"}) protected DEH gtConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().gt(); return exp1; } @Rule(left="conditionalAtom", value={"expression", "GE", "expression"}) protected DEH geConditional(DEH exp1, DEH exp2) throws Exception { exp1.append(exp2); exp1.getProxy().ge(); return exp1; } // ------------------- @Terminal(expression="[a-zA-Z\\$_][a-zA-Z0-9\\$_]*") protected abstract String identifier(String value); @Terminal(expression="(0x|0b)?[\\+\\-]?[0-9]+") protected abstract String integer(String value); @Terminal(expression="(0x|0b)?[\\+\\-]?[0-9]+(\\.[0-9]+)?([eE][\\+\\-]?[0-9]+)?") protected abstract String number(String value); @Terminal(expression="[ \t\r\n]+") protected abstract void whiteSpace(); @Terminal(expression = "\\-\\-[^\n]*\n") protected abstract void doubleSlashComment(); @Terminal(expression = "#[^\n]*\n") protected abstract void hashComment(); @Terminal(expression = "/\\*.*\\*/", options = {Regex.Option.FIXED_ENDER}) protected abstract void cComment(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy