Parsington is an infix-to-postfix and infix-to-syntax-tree expression parser for mathematical expressions written in Java. It is simple yet fancy, handling (customizable) operators, functions, variables and constants in a similar way to what the Java language itself supports.
Parsington is part of the SciJava project for scientific computing in Java.
Infix input: (-b + sqrt(b^2 - 4*a*c)) / (2*a)
→ postfix output: b - sqrt b 2 ^ 4 a * c * - (1) <Fn> + (1) 2 a * (1) /
Expression parsers are as old as the hills; what makes this one different?
- No dependencies.
- Available on Maven Central.
- Permissive BSD-2 license. See LICENSE.txt.
- Separation of concerns. Parsington's parser stands alone, giving you a postfix queue or syntax tree from your infix expression, which you can then process or evaluate however you see fit. Parsington also provides an eval subpackage that can evaluate expressions involving objects of common types (
java.lang.Boolean,java.lang.Number,java.lang.String), and which is extensible to your own needs—there is no assumption that your variables will consist of any particular data type, numerical or otherwise. - Extensibility. The default operators, a synthesis of Java and MATLAB syntax, work well. But if you need something else, you can define your own unary and binary operators with whatever symbols, precedence and associativity you desire.
- Clean, well-commented codebase with unit tests. Import the source into your favorite IDE and watch Parsington in action by putting a breakpoint here.
The ImageJ Ops project needed an expression parser so that it could be more awesome. But not one limited to primitive doubles, or one that conflated parsing with evaluation, or one licensed in a restrictive way. Just a simple infix parser: a nice shunting yard implementation, or maybe some lovely recursive descent. Something on GitHub, with no dependencies, available on Maven Central. But surprisingly, there was only tumbleweed. So Parsington was born, and all our problems are now over!
In your POM <dependencies>:
<dependency> <groupId>org.scijava</groupId> <artifactId>parsington</artifactId> <version>3.0.0</version> </dependency>To parse an infix expression to a postfix queue:
LinkedList<Object> queue = newExpressionParser().parsePostfix("a+b*c^f(1,2)'"); // queue = [a, b, c, f, 1, 2, (2), <Fn>, ^, ', *, +]To parse an infix expression to a syntax tree:
SyntaxTreetree = newExpressionParser().parseTree("a+b*c^f(1,2)'"); +-------+ | + | +---+---+ | +------+------+ | | +---+---+ +---+---+ | a | | * | +-------+ +---+---+ | +------+------+ | | +---+---+ +---+---+ | b | | ' | +-------+ +---+---+ | | +---+---+ | ^ | +---+---+ | +------+------+ | | +---+---+ +---+---+ | c | | <Fn> | +-------+ +---+---+ | +------+------+ | | +---+---+ +---+---+ | f | | (2) | +-------+ +---+---+ | +------+------+ | | +---+---+ +---+---+ | 1 | | 2 | +-------+ +-------+ To evaluate an expression involving basic types:
Objectresult = newDefaultTreeEvaluator().evaluate("6.5*7.8^2.3");There is also an interactive console shell you can play with.
Run it easily using jgo:
jgo org.scijava:parsington Or run from source, after cloning this repository:
mvn java -jar target/parsington-*-SNAPSHOT.jarSimple example invocations with the console's default evaluator:
> 6.5*7.8^2.3 732.3706691398969 : java.lang.Double > 2*3,4 ^ Misplaced separator or mismatched groups at index 4 The postfix built-in function lets you introspect a parsed postfix queue:
> postfix('6.5*7.8^2.3') 6.5 : java.lang.Double 7.8 : java.lang.Double 2.3 : java.lang.Double ^ : org.scijava.parsington.Operator * : org.scijava.parsington.Operator > postfix('[1, 2f, 3d, 4., 5L, 123456789987654321, 9987654321234567899]') 1 : java.lang.Integer 2.0 : java.lang.Float 3.0 : java.lang.Double 4.0 : java.lang.Double 5 : java.lang.Long 123456789987654321 : java.lang.Long 9987654321234567899 : java.math.BigInteger [7] : org.scijava.parsington.Group > postfix('f(x, y) = x*y') f : org.scijava.parsington.Variable x : org.scijava.parsington.Variable y : org.scijava.parsington.Variable (2) : org.scijava.parsington.Group <Fn> : org.scijava.parsington.Function x : org.scijava.parsington.Variable y : org.scijava.parsington.Variable * : org.scijava.parsington.Operator = : org.scijava.parsington.Operator > postfix('math.pow(q) = q^q') math : org.scijava.parsington.Variable pow : org.scijava.parsington.Variable . : org.scijava.parsington.Operator q : org.scijava.parsington.Variable (1) : org.scijava.parsington.Group <Fn> : org.scijava.parsington.Function q : org.scijava.parsington.Variable q : org.scijava.parsington.Variable ^ : org.scijava.parsington.Operator = : org.scijava.parsington.Operator The tree function is another way to introspect, in syntax tree form:
> tree('math.pow(q) = q^q') '=' - '<Fn>' -- '.' --- 'math' --- 'pow' -- '(1)' --- 'q' - '^' -- 'q' -- 'q' : org.scijava.parsington.SyntaxTree Parsington supports various kinds of customization, including custom operators, custom separator symbols, and even custom parsing of literals and/or other expression elements. See the TestExamples for illustrations of these sorts of customizations in practice.