Last active
June 9, 2016 12:09
-
-
Save hirthwork/b96b4167e769229a58ec7dd0e833d9ca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.StringReader; | |
import java.util.ArrayDeque; | |
import java.util.Deque; | |
public class Calc { | |
private final Deque<TokenType> tokens = new ArrayDeque<>(); | |
private final Lexer lexer; | |
private int parDepth = 0; | |
private TokenType token = null; | |
public Calc(final Lexer lexer) { | |
this.lexer = lexer; | |
} | |
private TokenType token() throws IOException { | |
token = tokens.poll(); | |
if (token == null) { | |
token = lexer.nextToken(); | |
} | |
return token; | |
} | |
private double value() { | |
return Double.parseDouble(lexer.yytext()); | |
} | |
private IllegalArgumentException exc() { | |
return new IllegalArgumentException( | |
"Unexpected token " + token + "(\"" + lexer.yytext() | |
+ "\") at pos: " + lexer.yychar()); | |
} | |
private double eof(final double value) { | |
if (parDepth == 0) { | |
return value; | |
} else { | |
throw exc(); | |
} | |
} | |
private double parsePrimary() throws IOException { | |
switch (token()) { | |
case NUMBER: | |
return value(); | |
case MINUS: | |
return -parsePrimary(); | |
case LPAR: | |
++parDepth; | |
return parse(); | |
default: | |
throw exc(); | |
} | |
} | |
private double parseExp() throws IOException { | |
double value = parsePrimary(); | |
while (true) { | |
TokenType token = token(); | |
switch (token) { | |
case POWER: | |
value = Math.pow(value, parseExp()); | |
break; | |
default: | |
tokens.push(token); | |
return value; | |
} | |
} | |
} | |
private double parseTerm() throws IOException { | |
double value = parseExp(); | |
while (true) { | |
TokenType token = token(); | |
switch (token) { | |
case MUL: | |
value *= parseExp(); | |
break; | |
case DIV: | |
value /= parseExp(); | |
break; | |
default: | |
tokens.push(token); | |
return value; | |
} | |
} | |
} | |
public double parse() throws IOException { | |
double value = parseTerm(); | |
while (true) { | |
switch (token()) { | |
case PLUS: | |
value += parseTerm(); | |
break; | |
case MINUS: | |
value -= parseTerm(); | |
break; | |
case RPAR: | |
--parDepth; | |
return value; | |
case EOF: | |
return eof(value); | |
default: | |
throw exc(); | |
} | |
} | |
} | |
public static void main(final String... args) throws Exception { | |
for (String expr: args) { | |
System.out.print(expr + " = "); | |
System.out.println( | |
new Calc(new Lexer(new StringReader(expr))).parse()); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% | |
%class Lexer | |
%int | |
%char | |
%type TokenType | |
%function nextToken | |
%{ | |
public int yychar() { | |
return yychar; | |
} | |
%} | |
Number = [0-9]+[.][0-9]* | [.]?[0-9]+ | |
%eofval{ | |
return TokenType.EOF; | |
%eofval} | |
%% | |
<YYINITIAL> { | |
{Number} {return TokenType.NUMBER;} | |
[+] {return TokenType.PLUS;} | |
[-] {return TokenType.MINUS;} | |
[*] {return TokenType.MUL;} | |
[/] {return TokenType.DIV;} | |
\^ {return TokenType.POWER;} | |
[(] {return TokenType.LPAR;} | |
[)] {return TokenType.RPAR;} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum TokenType { | |
NUMBER, | |
PLUS, | |
MINUS, | |
MUL, | |
DIV, | |
LPAR, | |
RPAR, | |
POWER, | |
EOF | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment