Friday, 15 February 2013

java - Antlr4: Evaluate math functions f(x) -



java - Antlr4: Evaluate math functions f(x) -

last days working on grammar able calculate normal expressions like: 2+2*5; 2^2 or set variables y=5+5; etc.

now want parse functions f(a,b)=2*a*b; , phone call them later f(5,7); im having troubles that.

so lets seek parse function-declaration this:

function:name=var'(' varnames=(multvar|var) ')' '=' (var|number) (operator=('*'|'/'|'+'|'-') (var|number))* semi;

so (kind of) works, think kinda "dirty" or whatever. im working listener , when im in "exitfunction" dont know how handle function best, can evaluate things f(5,7); easy.

im having java-class called "function.java" method "public double eval(double... args)"

so right im having attributes string arguments; string expression; string name; , need spend lot of time in listener , seek find right arguments etc in string. lot of substring(), , indexof() etc trying find name, arguments , expression. save function in hashmap then.

in parser functions phone call looks like:

functioncall: name=vart '('para=(multiplenumbers) ')' semi;

multiplenumbers be:

multiplenumber: number(',' number)+;

in lexer. seek arguments out of string, , replace them in function. have normal look programm can solve again.

since seems hard me , impossible right "substrings" etc think there must improve way implement things this. when wanna things like:

f(a,b)=2*a+b; a=5; f(a,5)

its getting harder, because cant rly mix numbers , variables. there way implement "function evaluator". maybe can save whole tree in hashmap , alter variables within tree , parse or? think grammar pretty much horrible aswell task.

since didnt work antlr in past, appreciate every help. hope can help me. , sorry bad english, hope you're able understand me.

kind regards

felrpi

one way parsing concrete syntax tree abstract syntax tree. function object stores ast , parse when called, lot simpler. considering example, f(a, b) = 2 * * b, parsed similar concrete syntax tree:

of course of study can understand well, isn't easy parse! look 2 * * b written pretty much string, don't quite know operator precedence looking @ tree (does 2 + * b means 2 + (a * b) or (2 + a) * b?) , take time traverse in right order.

however, can parse 1 time build more reliable, easier machine understand:

oh yes, easy parse: called params.length parameters, set them in hashmap or whatever representing scope, phone call "function" * parameters 2 , look *(a,b), function, phone call passing a , b "function" *. of course of study extensible user-defined functions.

considering function abs (value) = max(value, -value), build ast similar to:

parsing ast easy, ok. building it? not hard either, if consider operators functions (most of type (num, num) -> num, (unary) of type (num) -> num). have stable definition node in tree:

interface astnode { double eval(scope scope); // can @ scope hashmap<string, double> } class terminalnode : astnode { string varname; double constantvalue; public terminalnode(string varname) { this.varname = varname; } public terminalnode(double constantvalue) { this.constantvalue = constantvalue; this.varname = null; } public double eval(scope scope) { if (varname == null) homecoming constantvalue; homecoming scope.get(varname); } } class callnode : astnode { function target; string[] parameters; astnode[] children; public callnode(function target, string[] parameters, astnode[] children) { this.target = target; this.parameters = parameters; this.children = children; } public double eval(scope scope) { double[] subexpressions = new double[children.length]; scope innerscope = new scope(scope); // creates re-create (int = 0; < children.length; i++) { // i'm using re-create here because of edge-case: f(x) = g(x) + x; g(x) = x * 2; // in case, x variable overriden in innerscope when resolve g(x) // "stored" previous x value in "outerscope" can add together later subexpressions[i] = children[i].eval(scope); innerscope.set(target.getparamname(i), subexpressions[i]); } // usually, target.getnode().eval(innerscope) // however, limit target function user-defined functions // leave way can override function's eval method built-in homecoming target.eval(innerscope); } }

this may over-simplification, starting point. notice, callnode have other astnode children, bit of infinite recursion, broken when every children terminalnode (variable or constant). commented in code, build operators members of function class, either instantiating or extension of class. of course, depends on function implementation. way build astnode class, builtinnode (or nodes plusnode, dividenode, etc) solve phone call using primitives.

adding reply comment, "how create utilize of built ast". suppose have function object called g, stores ast expressions f(x, y) = 2 * * b. how accomplish value of f(4, 2)?

to this, utilize scope object (or hashmap<string, double> matters). create scope function parameters have been determined, phone call using ast, utilize scope inner levels.

the code can like:

scope scope = new scope(); scope.set("x", 4); scope.set("y", 2); // remember stored function f on object g, create distinction // also, note equivalent g.getnode().eval(scope), because function stored in g not built-in! system.out.println(g.eval(scope));

to solve eval query, ast have scope {x: 4, y: 2} beforehand (we created it), , phone call function *(a, b), a=2 , b=x*y. solve first * function phone call need solve both arguments (a , b). solve a easy, because terminal node (the eval homecoming terminal immediatly). solve b, need phone call eval of inner function, generating new scope {x: 4, y: 2, a: x, b: y}, a , b arguments of sec * function. both a , b solved terminal nodes, sec phone call * can calculate value (by built-in function, calculates 4*2=8) , homecoming caller, b first * function.

now having scope {x: 4, y: 2, a: 2, b: 8}, x , y parameters of f , a , b arguments * function. arguments set, can phone call * built-in function, yielding 16, result of function!

images generated http://ironcreek.net/phpsyntaxtree

java eclipse parsing antlr evaluate

No comments:

Post a Comment