Skip to content

Commit

Permalink
Simple interpreter
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanbeschi committed Dec 15, 2013
1 parent 626f364 commit 6d950cf
Show file tree
Hide file tree
Showing 27 changed files with 910 additions and 420 deletions.
14 changes: 14 additions & 0 deletions 03_projects/bytecode/01_src/main/pjb/partnine/postfix.pjb
@@ -0,0 +1,14 @@
.class org/isk/jvmhardcore/bytecode/partnine/Postfix
.method compute()I
iconst_2
bipush 7
iconst_5
isub
imul
bipush 8
iconst_5
isub
imul
ireturn
.methodend
.classend
@@ -0,0 +1,12 @@
package org.isk.jvmhardcore.bytecode.partnine;

import org.junit.Assert;
import org.junit.Test;

public class BytecodeTest {
@Test
public void compute() {
final int result = Postfix.compute();
Assert.assertEquals(12, result);
}
}
@@ -1,10 +1,7 @@
package org.isk.jvmhardcore.mathparser;
package org.isk.jvmhardcore.math;

public class MathException extends RuntimeException {

/**
*
*/
private static final long serialVersionUID = 2413076920261396393L;

public MathException() {
Expand Down
@@ -0,0 +1,5 @@
package org.isk.jvmhardcore.math.common;

public enum Operator {
PLUS, MINUS, TIMES, DIVIDE;
}
@@ -1,4 +1,4 @@
package org.isk.jvmhardcore.mathparser;
package org.isk.jvmhardcore.math.parser;

public enum EventType {
EOF,
Expand Down
@@ -0,0 +1,157 @@
package org.isk.jvmhardcore.math.parser;

import java.io.InputStream;
import java.util.LinkedList;
import java.util.Stack;

import org.isk.jvmhardcore.math.MathException;
import org.isk.jvmhardcore.math.common.Operator;
import org.isk.jvmhardcore.math.parser.core.InputStreamReader;
import org.isk.jvmhardcore.math.parser.core.Parser;
import org.isk.jvmhardcore.math.parser.core.util.Ascii;

public class MathParser extends Parser<LinkedList<Object>, EventType, MathTokenizer> {

final private LinkedList<Object> postfixExpression;
final private Stack<ParsingOperator> operatorStack;

public MathParser(final InputStream inputStream) {
super(inputStream, Symbols.number());

this.postfixExpression = new LinkedList<>();
this.operatorStack = new Stack<>();
}

@Override
public LinkedList<Object> parse() {
EventType eventType = null;

boolean done = false;
while (!done) {
eventType = this.getNextEvent();

switch (eventType) {
case FLOAT:
this.postfixExpression.add(this.tokenizer.getFloat());
break;
case INTEGER:
this.postfixExpression.add(this.tokenizer.getInteger());
break;
case OPERATOR:
this.processOperator(this.tokenizer.getOperator());
break;
case LEFT_PARENTHESIS:
this.operatorStack.push(this.tokenizer.getParenthesis());
break;
case RIGHT_PARENTHESIS:
this.processRightParenthesis(this.tokenizer.getParenthesis());
break;
case EOF:
this.tokenizer.checkEndOfFile();
this.processEndOfFile();
done = true;
break;
default:
System.err.println("Unexpected event.");
break;
}
}

return this.postfixExpression;
}

@Override
protected MathTokenizer newTokenizer(final String filename, final InputStream inputStream) {
return new MathTokenizer(filename, new InputStreamReader(inputStream));
}

@Override
protected void initProductionTable() {
this.table[Symbols.STREAM] = new Productions.Stream();
this.table[Symbols.EOF] = new Productions.EndOfFile();
this.table[Symbols.EXPRESSION] = new Productions.Expression();
this.table[Symbols.OR_RIGHT_EXPRESSION] = new Productions.OrRightExpression();
this.table[Symbols.OR_LEFT_PARENTHESIS] = new Productions.OrLeftParenthesis();
this.table[Symbols.OR_RIGHT_PARENTHESIS] = new Productions.OrRightParenthesis();
this.table[Symbols.LEFT_PARENTHESIS] = new Productions.LeftParenthesis();
this.table[Symbols.RIGHT_PARENTHESIS] = new Productions.RightParenthesis();
this.table[Symbols.NUMBER] = new Productions.Number();
this.table[Symbols.OPERATOR] = new Productions.Operator();
this.table[Symbols.WS] = new Productions.Whitespaces();
}

private void processOperator(ParsingOperator parsingOperator) {
// The current operator is of less priority than the previous one
if (!this.operatorStack.isEmpty() && parsingOperator.le(this.operatorStack.peek())) {
this.postfixExpression.add(ParsingOperator.getClean(this.operatorStack.pop()));
}

this.operatorStack.push(parsingOperator);
}

private void processRightParenthesis(ParsingOperator rightParenthsesis) {
// A closing parenthesis has been reached
// We add all operators until the opening parenthesis
while (!this.operatorStack.isEmpty() && this.operatorStack.peek() != ParsingOperator.LEFT_PARENTHESIS) {
this.postfixExpression.add(ParsingOperator.getClean(this.operatorStack.pop()));
}

if (this.operatorStack.isEmpty() || this.operatorStack.pop() != ParsingOperator.LEFT_PARENTHESIS) {
throw new MathException("Missing left parenthesis.");
}
}

private void processEndOfFile() {
while (!this.operatorStack.isEmpty()) {
this.postfixExpression.add(ParsingOperator.getClean(this.operatorStack.pop()));
}
}
}

enum ParsingOperator {
PLUS(0), MINUS(0), TIMES(1), DIVIDE(1), LEFT_PARENTHESIS(100), RIGHT_PARENTHESIS(100);

private int value;

private ParsingOperator(int value) {
this.value = value;
}

public boolean le(ParsingOperator po) {
return po.value != 100 && this.value <= po.value;
}

public static ParsingOperator get(int operator) {
switch (operator) {
case Ascii.PLUS_SIGN:
return PLUS;
case Ascii.HYPHEN:
return MINUS;
case Ascii.ASTERISK:
return TIMES;
case Ascii.SLASH:
return DIVIDE;
case Ascii.LEFT_PARENTHESIS:
return LEFT_PARENTHESIS;
case Ascii.RIGHT_PARENTHESIS:
return RIGHT_PARENTHESIS;
default:
throw new MathException("Unexpected operator: " + String.valueOf(Character.toChars(operator)));
}
}

public static Operator getClean(ParsingOperator operator) {
switch (operator) {
case PLUS:
return Operator.PLUS;
case MINUS:
return Operator.MINUS;
case TIMES:
return Operator.TIMES;
case DIVIDE:
return Operator.DIVIDE;
default:
throw new MathException("Unexpected operator: " + operator);
}
}
}
@@ -1,32 +1,32 @@
package org.isk.jvmhardcore.mathparser;
package org.isk.jvmhardcore.math.parser;

import org.isk.jvmhardcore.mathparser.core.Reader;
import org.isk.jvmhardcore.mathparser.core.Tokenizer;
import org.isk.jvmhardcore.mathparser.core.util.Ascii;
import org.isk.jvmhardcore.mathparser.core.util.StringGenerator;
import org.isk.jvmhardcore.math.parser.core.Reader;
import org.isk.jvmhardcore.math.parser.core.Tokenizer;
import org.isk.jvmhardcore.math.parser.core.util.Ascii;
import org.isk.jvmhardcore.math.parser.core.util.StringGenerator;

public class MathTokenizer extends Tokenizer {

final private StringGenerator generator;

public MathTokenizer(String filename, Reader reader) {
super(filename, reader);

this.generator = new StringGenerator();
}

public String getInteger() {
public Integer getInteger() {
this.fillWithDigits();

if (!generator.isEmpty()) {
this.rewind();
return generator.toString();
return Integer.valueOf(generator.toString());
} else {
throw new ParserException("Expected: At least one Digit [0-9].");
}
}

public String getFloat() {
public Double getFloat() {
int character = this.fillWithDigits();

// getFloat() is called after isFloat()
Expand All @@ -38,7 +38,7 @@ public String getFloat() {
}

this.rewind();
return generator.toString();
return Double.valueOf(generator.toString());
}

private int fillWithDigits() {
Expand All @@ -51,28 +51,29 @@ private int fillWithDigits() {
} else {
this.rewind();
}

while (isDigit(character = this.next())) {
generator.appendChar(character);
}

return character;
}

public int getOperator() {
public ParsingOperator getOperator() {
int character = this.next();

if (this.isOperator(character)) {
return character;
return ParsingOperator.get(character);
} else {
throw new ParserException("Expected: '+' or '-' or '*' or '/'.");
}
}

public int getNext() {
return this.next();

public ParsingOperator getParenthesis() {
int character = this.next();
return ParsingOperator.get(character);
}

public boolean isFloat() {
this.mark();

Expand Down Expand Up @@ -122,18 +123,18 @@ public boolean isFloat() {
}

public boolean isOperator(int character) {
return character == Ascii.PLUS_SIGN
|| character == Ascii.HYPHEN
|| character == Ascii.ASTERIX
|| character == Ascii.SLASH;
return character == Ascii.PLUS_SIGN
|| character == Ascii.HYPHEN
|| character == Ascii.ASTERISK
|| character == Ascii.SLASH;
}

public boolean isOperator() {
final int character = this.next();
this.rewind();
return isOperator(character);
}

public boolean isLeftParenthesis() {
final int character = this.next();
this.rewind();
Expand Down
@@ -1,11 +1,11 @@
package org.isk.jvmhardcore.mathparser;
package org.isk.jvmhardcore.math.parser;

import java.util.Stack;

import org.isk.jvmhardcore.mathparser.core.Production;
import org.isk.jvmhardcore.math.parser.core.Production;

public class Productions {

// stream = expression eof
public static class Stream implements Production<EventType, MathTokenizer> {
public EventType produce(MathTokenizer tokenizer,
Expand All @@ -32,7 +32,7 @@ public EventType produce(MathTokenizer tokenizer,
return null;
}
}

// orRightExpression = {ws operator orLeftParenthesis number orRightParenthesis ws}
public static class OrRightExpression implements Production<EventType, MathTokenizer> {
public EventType produce(MathTokenizer tokenizer,
Expand All @@ -52,7 +52,7 @@ public EventType produce(MathTokenizer tokenizer,
return null;
}
}

// number = integer | float
// integer = repeatingDigit
// float = oRepeatingDigit [dot] oRepeatingDigit
Expand Down Expand Up @@ -132,19 +132,19 @@ public EventType produce(MathTokenizer tokenizer,
}
}

// ws = ? whitespaces ?
// ws = ? caractères d'espacement ?
public static class Whitespaces implements Production<EventType, MathTokenizer> {
public EventType produce(MathTokenizer tokenizer,
public EventType produce(MathTokenizer tokenizer,
Production<EventType, MathTokenizer>[] table,
Stack<Production<EventType, MathTokenizer>> productionStack) {
tokenizer.consumeUnprintables();
return null;
}
}

// eof = ? end of stream ?
// eof = ? fin du flux ?
public static class EndOfFile implements Production<EventType, MathTokenizer> {
public EventType produce(MathTokenizer tokenizer,
public EventType produce(MathTokenizer tokenizer,
Production<EventType, MathTokenizer>[] table,
Stack<Production<EventType, MathTokenizer>> productionStack) {
return EventType.EOF;
Expand Down

0 comments on commit 6d950cf

Please sign in to comment.