Skip to content

Instantly share code, notes, and snippets.

@hirthwork
Last active June 9, 2016 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hirthwork/b96b4167e769229a58ec7dd0e833d9ca to your computer and use it in GitHub Desktop.
Save hirthwork/b96b4167e769229a58ec7dd0e833d9ca to your computer and use it in GitHub Desktop.
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());
}
}
}
%%
%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;}
}
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