Skip to content

Commit 09b0756

Browse files
committed
initial commit
1 parent 9a619b6 commit 09b0756

File tree

7 files changed

+317
-0
lines changed

7 files changed

+317
-0
lines changed

.gitignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
*.*~
2+
target
3+
src/main/java/META-INF/MANIFEST.MF
4+
.DS_Store
5+
*.class
6+
7+
# Package Files #
8+
*.jar
9+
*.war
10+
*.ear
11+
12+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
13+
hs_err_pid*
14+
/.settings/

.project

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>lems-expr-parser</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
<buildCommand>
14+
<name>org.eclipse.jdt.core.javabuilder</name>
15+
<arguments>
16+
</arguments>
17+
</buildCommand>
18+
<buildCommand>
19+
<name>org.eclipse.m2e.core.maven2Builder</name>
20+
<arguments>
21+
</arguments>
22+
</buildCommand>
23+
</buildSpec>
24+
<natures>
25+
<nature>org.eclipse.jdt.core.javanature</nature>
26+
<nature>org.eclipse.m2e.core.maven2Nature</nature>
27+
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
28+
</natures>
29+
</projectDescription>

pom.xml

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
3+
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>org.lemsml.model</groupId>
7+
<artifactId>lems-expr-parser</artifactId>
8+
<version>0.0-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<dependencies>
12+
<dependency>
13+
<groupId>org.antlr</groupId>
14+
<artifactId>antlr4-maven-plugin</artifactId>
15+
<version>4.3</version>
16+
</dependency>
17+
<dependency>
18+
<groupId>junit</groupId>
19+
<artifactId>junit</artifactId>
20+
<version>4.11</version>
21+
<scope>test</scope>
22+
<type>jar</type>
23+
</dependency>
24+
</dependencies>
25+
26+
<properties>
27+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
28+
</properties>
29+
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>org.eclipse.m2e</groupId>
34+
<artifactId>lifecycle-mapping</artifactId>
35+
<version>1.0.0</version>
36+
<configuration>
37+
<lifecycleMappingMetadata>
38+
<pluginExecutions>
39+
<pluginExecution>
40+
<pluginExecutionFilter>
41+
<groupId>org.antlr</groupId>
42+
<artifactId>antlr4-maven-plugin</artifactId>
43+
<versionRange>[4.1,)</versionRange>
44+
<goals>
45+
<goal>antlr4</goal>
46+
</goals>
47+
</pluginExecutionFilter>
48+
<action>
49+
<execute>
50+
<runOnIncremental>true</runOnIncremental>
51+
</execute>
52+
</action>
53+
</pluginExecution>
54+
</pluginExecutions>
55+
</lifecycleMappingMetadata>
56+
</configuration>
57+
</plugin>
58+
<plugin>
59+
<groupId>org.apache.maven.plugins</groupId>
60+
<artifactId>maven-compiler-plugin</artifactId>
61+
<version>3.1</version>
62+
<configuration>
63+
<source>1.7</source>
64+
<target>1.7</target>
65+
</configuration>
66+
</plugin>
67+
<plugin>
68+
<groupId>org.codehaus.mojo</groupId>
69+
<artifactId>exec-maven-plugin</artifactId>
70+
<version>1.2.1</version>
71+
<executions>
72+
<execution>
73+
<goals>
74+
<goal>java</goal>
75+
</goals>
76+
</execution>
77+
</executions>
78+
<configuration>
79+
<mainClass>Run</mainClass>
80+
</configuration>
81+
</plugin>
82+
<plugin>
83+
<groupId>org.antlr</groupId>
84+
<artifactId>antlr4-maven-plugin</artifactId>
85+
<version>4.1</version>
86+
<configuration>
87+
<listener>false</listener>
88+
<visitor>true</visitor>
89+
</configuration>
90+
<executions>
91+
<execution>
92+
<goals>
93+
<goal>antlr4</goal>
94+
</goals>
95+
</execution>
96+
</executions>
97+
</plugin>
98+
</plugins>
99+
</build>
100+
</project>
101+

src/main/antlr4/CommonLexerRules.g4

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
lexer grammar CommonLexerRules;
2+
3+
NEWLINE: '\r' ? '\n' ; // return newlines to parser (end-statement signal)
4+
ID : [a-zA-Z]+ ; // match identifiers
5+
WS : [ \t]+ -> skip ; // toss out whitespace
6+
7+
MUL : '*' ;
8+
DIV : '/' ;
9+
ADD : '+' ;
10+
SUB : '-' ;
11+
POW : '^' ;
12+
13+
FLOAT: DIGIT+ '.' DIGIT* EXP? [Ll]?
14+
| DIGIT+ EXP? [Ll]?
15+
| '.' DIGIT+ EXP? [Ll]?
16+
;
17+
fragment
18+
DIGIT: '0'..'9' ;
19+
fragment
20+
EXP : ('E' | 'e') ('+' | '-')? DIGIT+ ;
21+

src/main/antlr4/LEMSExpression.g4

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
grammar LEMSExpression;
2+
import CommonLexerRules;
3+
4+
base: expr
5+
;
6+
7+
expr: '(' expr ')' # parens
8+
| BuiltinFuncs '(' expr? ')' # funcCall
9+
| '-' expr # Negate
10+
| expr op=POW expr # Pow
11+
| expr op=(MUL | DIV) expr # MulDiv
12+
| expr op=(ADD | SUB) expr # AddSub
13+
| FLOAT # float
14+
| ID # id
15+
;
16+
17+
BuiltinFuncs: 'sin'
18+
| 'cos'
19+
| 'tan'
20+
;

src/main/java/EvalVisitor.java

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
public class EvalVisitor extends LEMSExpressionBaseVisitor<Float> {
2+
3+
/** expr */
4+
@Override
5+
public Float visitBase(LEMSExpressionParser.BaseContext ctx) {
6+
Float result = visit(ctx.expr());
7+
System.out.println(ctx.expr().getText() + " = " + result);
8+
return result;
9+
}
10+
11+
/** '-' expr */
12+
@Override
13+
public Float visitNegate(LEMSExpressionParser.NegateContext ctx) {
14+
return -visit(ctx.expr());
15+
}
16+
17+
/** expr op=POW expr */
18+
@Override
19+
public Float visitPow(LEMSExpressionParser.PowContext ctx) {
20+
Float left = visit(ctx.expr(0)); // get value of left subexpression
21+
Float right = visit(ctx.expr(1)); // get value of right subexpression
22+
return new Float(Math.pow(left, right));
23+
}
24+
25+
/** FLOAT */
26+
@Override
27+
public Float visitFloat(LEMSExpressionParser.FloatContext ctx) {
28+
return Float.valueOf(ctx.FLOAT().getText());
29+
}
30+
31+
/** expr op=('*'|'/') expr */
32+
@Override
33+
public Float visitMulDiv(LEMSExpressionParser.MulDivContext ctx) {
34+
Float left = visit(ctx.expr(0)); // get value of left subexpression
35+
Float right = visit(ctx.expr(1)); // get value of right subexpression
36+
if (ctx.op.getType() == LEMSExpressionParser.MUL)
37+
return left * right;
38+
return left / right; // must be DIV
39+
}
40+
41+
/** expr op=('+'|'-') expr */
42+
@Override
43+
public Float visitAddSub(LEMSExpressionParser.AddSubContext ctx) {
44+
Float left = visit(ctx.expr(0)); // get value of left subexpression
45+
Float right = visit(ctx.expr(1)); // get value of right subexpression
46+
if (ctx.op.getType() == LEMSExpressionParser.ADD)
47+
return left + right;
48+
return left - right; // must be SUB
49+
}
50+
51+
/** '(' expr ')' */
52+
@Override
53+
public Float visitParens(LEMSExpressionParser.ParensContext ctx) {
54+
return visit(ctx.expr()); // return child expr's value
55+
}
56+
57+
/** BuiltinFuncs '(' expr ')' */
58+
@Override
59+
public Float visitFuncCall(LEMSExpressionParser.FuncCallContext ctx) {
60+
Float ret = null;
61+
switch (ctx.BuiltinFuncs().getText()) {
62+
case "sin":
63+
ret = new Float(Math.sin(visit(ctx.expr())));
64+
break;
65+
case "cos":
66+
ret = new Float(Math.cos(visit(ctx.expr())));
67+
break;
68+
case "tan":
69+
ret = new Float(Math.tan(visit(ctx.expr())));
70+
break;
71+
}
72+
73+
return ret;
74+
}
75+
76+
}

src/test/java/EvalVisitorTest.java

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import static org.junit.Assert.assertEquals;
2+
3+
import org.antlr.v4.runtime.ANTLRInputStream;
4+
import org.antlr.v4.runtime.CommonTokenStream;
5+
import org.antlr.v4.runtime.tree.ParseTree;
6+
import org.junit.Test;
7+
8+
public class EvalVisitorTest {
9+
private static final double EPSILON = 0.0000000001d;
10+
11+
@Test
12+
public void testAddSub() {
13+
assertEquals(2.0d, getResult("1.5 + 0.5"), EPSILON);
14+
assertEquals(1.0d, getResult("1.5 - 0.5"), EPSILON);
15+
}
16+
17+
@Test
18+
public void testMultDiv() {
19+
assertEquals(-6.0d, getResult("-0.2e1 * 3"), EPSILON);
20+
assertEquals(3.0d, getResult("9 / 3"), EPSILON);
21+
}
22+
23+
@Test
24+
public void testParenthesis() {
25+
assertEquals(4.5d, getResult("3 * (1 + .5)"), EPSILON);
26+
}
27+
28+
@Test
29+
public void testNegate() {
30+
assertEquals(1.5d, getResult("3 * (1 + -.5)"), EPSILON);
31+
}
32+
33+
@Test
34+
public void testTwoParenthesis() {
35+
assertEquals(4.5d, getResult("3 * ((9.0 - 7) / 2 + .5)"), EPSILON);
36+
}
37+
38+
@Test
39+
public void testTrig() {
40+
assertEquals(0.0d, getResult("sin(0)"), EPSILON);
41+
assertEquals(1.0d, getResult("sin(0.5*3.14159265359)"), EPSILON);
42+
assertEquals(1.0d, getResult("sin(1/2)^2 + cos(1/2)^2"), EPSILON);
43+
}
44+
45+
46+
private Float getResult(String expression) {
47+
ANTLRInputStream input = new ANTLRInputStream(expression);
48+
LEMSExpressionLexer lexer = new LEMSExpressionLexer(input);
49+
CommonTokenStream tokens = new CommonTokenStream(lexer);
50+
LEMSExpressionParser parser = new LEMSExpressionParser(tokens);
51+
ParseTree tree = parser.base();
52+
53+
EvalVisitor eval = new EvalVisitor();
54+
return eval.visit(tree);
55+
}
56+
}

0 commit comments

Comments
 (0)