Verified Commit 337459e4 authored by Emily Rowlands's avatar Emily Rowlands
Browse files

Added and modified a lot.

parent 638df9d7
package jrr1g18.bb;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jrr1g18.bb.Token.TokenType;
/**
* Interpreter for BareBones
* @author jrr1g18
*
*/
public class Interpreter {
// The code to be interpreted
private String m_code;
// The index of the current position in the code
private int m_idx;
// Variable dictionary
private Map<String, Integer> m_variables;
/**
* Get the value of a variable
* @param var The variable to get
* @return The value of the variable
*/
public Map<String, Integer> getVariables(String var) {
return m_variables;
}
/**
* Checks if a character is an integer
* @param character
* @return
*/
public static boolean isInt(String character) {
return character.matches("\\d+");
}
public Interpreter(String code) {
m_code = new String(code);
m_idx = 0;
m_variables = new HashMap<String, Integer>();
}
public String variablesToString() {
return m_variables.toString();
}
public Token getNextToken() {
Matcher whitespaceMatcher = Pattern.compile("\\s*").matcher(m_code);
whitespaceMatcher.find(m_idx);
m_idx+=whitespaceMatcher.group().length();
if(m_idx >= m_code.length()) {
return new Token(TokenType.EOF);
}
String nextChar = "" + m_code.charAt(m_idx);
Token token;
if(nextChar.equals(";")) {
// Semicolon
token = new Token(TokenType.SEMICOLON);
++m_idx;
} else if(isInt(nextChar)) {
// Integer
Matcher m = Pattern.compile("\\d+").matcher(m_code);
m.find(m_idx);
token = new ValueToken(TokenType.INTEGER, "" + nextChar);
m_idx+=m.group().length();
} else {
// Variable or instruction
Matcher m = Pattern.compile("[A-Za-z][A-Za-z\\d]*").matcher(m_code);
m.find(m_idx);
String name = m.group();
switch (name) {
case "incr":
token = new Token(TokenType.INCR);
break;
case "decr":
token = new Token(TokenType.DECR);
break;
case "clear":
token = new Token(TokenType.CLEAR);
break;
default:
token = new ValueToken(TokenType.IDENTIFIER, name);
break;
}
m_idx+=m.group().length();
}
return token;
}
public void exec() throws Exception {
ArrayList<Token> tokenHistory = new ArrayList<Token>();
Token lookahead;
int stmt_begin = 0;
int stmt_end = 0;
while(true){
// Find next statement
do{
++stmt_end;
lookahead = getNextToken();
if(lookahead.getType()==TokenType.EOF) {
return;
}
tokenHistory.add(lookahead);
} while(lookahead.getType()!=TokenType.SEMICOLON);
// Run statement
int stmt_len = stmt_end-stmt_begin;
Token currentToken = tokenHistory.get(stmt_begin);
int setVarTo;
switch (currentToken.getType()) {
case CLEAR:
case INCR:
case DECR:
if(stmt_len==3 && tokenHistory.get(stmt_begin+1).getType()==TokenType.IDENTIFIER){
ValueToken token = (ValueToken) tokenHistory.get(stmt_begin+1);
switch (currentToken.getType()) {
case CLEAR:
setVarTo=0;
break;
case INCR:
setVarTo=m_variables.get(token.getValue())+1;
break;
case DECR:
setVarTo=m_variables.get(token.getValue())-1;
default:
throw new Exception("How did you even get here?");
}
if(m_variables.containsKey(token.getValue())) {
m_variables.replace(token.getValue(), 0);
} else {
m_variables.put(token.getValue(), 0);
}
} else {
throw new Exception("Nonsense statement.");
}
break;
default:
throw new IllegalStateException("Illegal token type: "
+ Token.tokenTypeToString(currentToken.getType()));
}
stmt_begin = stmt_end;
}
}
}
package jrr1g18.bb;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Token {
public enum TokenType {
EOF, INTEGER, SEMICOLON, IDENTIFIER, INCR, DECR, CLEAR,
}
private static final Map<TokenType, String> TOKEN_MAP;
static {
HashMap<TokenType, String> tempMap = new HashMap<TokenType, String>();
tempMap.put(TokenType.EOF, "EOF");
tempMap.put(TokenType.INTEGER, "INTEGER");
tempMap.put(TokenType.SEMICOLON, "SEMICOLON");
tempMap.put(TokenType.IDENTIFIER, "IDENTIFIER");
tempMap.put(TokenType.INCR, "INCR");
tempMap.put(TokenType.DECR, "DECR");
tempMap.put(TokenType.CLEAR, "CLEAR");
TOKEN_MAP = Collections.unmodifiableMap(tempMap);
}
public static String tokenTypeToString(final TokenType tt) {
return TOKEN_MAP.get(tt);
}
private final TokenType m_type;
public Token(TokenType type) {
m_type = type;
}
public TokenType getType() {
return m_type;
}
public String toString() {
return "Token(" + tokenTypeToString(m_type)+")";
}
}
\ No newline at end of file
package jrr1g18.bb;
public class ValueToken extends Token {
String m_value;
public ValueToken(TokenType type, String value) {
super(type);
m_value = value;
}
public ValueToken(TokenType type) {
super(type);
m_value="NULL";
}
@Override
public String toString() {
return "ValueToken("+tokenTypeToString(getType())+", " + getValue()+")";
}
public String getValue() {
return m_value;
}
public void setValue(ValueToken value) {
m_value = value.getValue();
}
public void setValue(String value) {
m_value = value;
}
}
package jrr1g18.boring;
import jrr1g18.boring.Token.TokenType;
import jrr1g18.boring.exceptions.IllegalCharacterException;
import jrr1g18.boring.exceptions.IllegalTokenException;
/**
* Interpreter for Boring
*
* @author jrr1g18
*
*/
public class Interpreter {
private Lexer m_lexer;
private Token m_currentToken;
public Interpreter(Lexer lexer) {
m_lexer = lexer;
try {
m_currentToken = m_lexer.getNextToken();
} catch(IllegalCharacterException e) {
e.printStackTrace();
}
}
/**
* Compare current token with tt. If they match, then advance the Lexer.
*
* @param tt The expected TokenType
* @throws IllegalTokenException When the token types do not match
*/
public void eat(TokenType tt) throws IllegalTokenException {
if(m_currentToken.getType() == tt) {
try {
m_currentToken = m_lexer.getNextToken();
} catch(IllegalCharacterException e) {
e.printStackTrace();
}
} else {
throw new IllegalTokenException(
"Expected: " + Lib.tokenTypeToString(tt) + " got: "
+ Lib.tokenTypeToString(m_currentToken.getType()));
}
}
/**
* number : INTEGER
*
* @return An integer token value.
* @throws IllegalTokenException
*/
public int number() throws IllegalTokenException {
Integer value = ((ValueToken) m_currentToken).getValue();
eat(TokenType.INTEGER);
return value;
}
/**
* mulDiv : number ((MUL|DIV) number)*
*
* @return The expression result.
* @throws IllegalTokenException When an illegal token is enountered.
*/
public int mulDiv() throws IllegalTokenException {
int result = number();
while(m_currentToken.getType() == TokenType.MUL
|| m_currentToken.getType() == TokenType.DIV) {
ValueToken token = (ValueToken) m_currentToken;
switch (token.getType()) {
case MUL:
eat(TokenType.MUL);
result *= number();
break;
case DIV:
eat(TokenType.DIV);
result /= number();
break;
default:
break;
}
}
return result;
}
/**
* addSub : number ((ADD|SUB) number)*
*
* @return The expression result.
* @throws IllegalTokenException When an illegal token is enountered.
*/
public int addSub() throws IllegalTokenException {
int result = number();
while(m_currentToken.getType() == TokenType.ADD
|| m_currentToken.getType() == TokenType.SUB) {
ValueToken token = (ValueToken) m_currentToken;
switch (token.getType()) {
case ADD:
eat(TokenType.ADD);
result += number();
break;
case SUB:
eat(TokenType.SUB);
result -= number();
break;
default:
break;
}
}
return result;
}
}
package jrr1g18.boring;
import jrr1g18.boring.Token.TokenType;
import jrr1g18.boring.exceptions.IllegalCharacterException;
public class Lexer {
private String m_text;
private int m_pos;
private String m_currentChar;
public Lexer(String text) {
m_text = text;
}
/**
* Advance m_pos and set m_currentChar
*/
private void nextChar() {
m_pos += 1;
if(m_pos > m_text.length() - 1) {
m_currentChar = null;
} else {
m_currentChar = "" + m_text.charAt(m_pos);
}
}
/**
* Advance until EOF or end of whitespace
*/
public void skipWhitespace() {
while(m_currentChar != null && Lib.isWhitespace(m_currentChar)) {
nextChar();
}
}
/**
* @return A multidigit integer generated from input
*/
public int integer() {
String ret = "";
while(m_currentChar != null && Lib.isInt(m_currentChar)) {
ret += m_currentChar;
nextChar();
}
return Integer.parseInt(ret);
}
/**
* Tokeniser
*
* @return The next token
* @throws IllegalCharacterException When an unknown character is found
*/
public Token getNextToken() throws IllegalCharacterException {
while(m_currentChar != null) {
if(Lib.isWhitespace(m_currentChar)) {
skipWhitespace();
continue;
}
if(Lib.isInt(m_currentChar)) {
return new ValueToken(TokenType.INTEGER, integer());
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.ADD))) {
nextChar();
return new NamedToken(TokenType.ADD,
Lib.tokenTypeToString(TokenType.ADD));
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.SUB))) {
nextChar();
return new NamedToken(TokenType.SUB,
Lib.tokenTypeToString(TokenType.SUB));
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.MUL))) {
nextChar();
return new NamedToken(TokenType.MUL,
Lib.tokenTypeToString(TokenType.MUL));
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.DIV))) {
nextChar();
return new NamedToken(TokenType.DIV,
Lib.tokenTypeToString(TokenType.DIV));
} else {
throw new IllegalCharacterException(
"Unrecognised thing: " + m_currentChar);
}
}
return new Token(TokenType.EOF);
}
}
package jrr1g18.boring;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import jrr1g18.boring.Token.TokenType;
public abstract class Lib {
/**
* Checks if a string is an integer
*
* @param string String to check
* @return True if an integer, false otherwise
*/
public static boolean isInt(String string) {
return string.matches("\\d+");
}
/**
* Checks if a string is only whitespace
*
* @param string String to check
* @return True if an integer, false otherwise
*/
public static boolean isWhitespace(String string) {
return string.matches("\\s+");
}
private static final Map<TokenType, String> TOKEN_MAP;
static {
HashMap<TokenType, String> tempMap = new HashMap<TokenType, String>();
tempMap.put(TokenType.EOF, "EOF");
tempMap.put(TokenType.INTEGER, "INTEGER");
tempMap.put(TokenType.SEMICOLON, "SEMICOLON");
tempMap.put(TokenType.DIV, "/");
tempMap.put(TokenType.SUB, "-");
tempMap.put(TokenType.ADD, "+");
tempMap.put(TokenType.MUL, "*");
TOKEN_MAP = Collections.unmodifiableMap(tempMap);
}
public static String tokenTypeToString(final TokenType tt) {
return TOKEN_MAP.get(tt);
}
}
package jrr1g18.bb;
package jrr1g18.boring;
public class Main {
public static void main(String[] args) throws Exception {
Interpreter interpreter = new Interpreter("clear x;\nincr x;");
interpreter.exec();
System.out.println(interpreter.variablesToString());
Lexer lexer = new Lexer("1+2");
Interpreter interpreter = new Interpreter(lexer);
System.out.println(interpreter.addSub());
}
}
package jrr1g18.boring;
public class NamedToken extends Token {
private String m_name;
public NamedToken(TokenType type, String value) {
super(type);
m_name = new String(value);
}
public NamedToken(TokenType type) {
super(type);
m_name = null;
}
@Override
public String toString() {
return "ValueToken(" + Lib.tokenTypeToString(getType()) + ", "
+ getName() + ")";
}
public String getName() {
return m_name;
}
public void setName(final NamedToken value) {
m_name = new String(value.getName());
}
public void setName(final String value) {
m_name = new String(value);
}
}
package jrr1g18.boring;
public class Token {
public enum TokenType {
EOF, INTEGER, SEMICOLON, ADD, SUB, MUL, DIV,
}
private final TokenType m_type;
public Token(TokenType type) {
m_type = type;
}
public TokenType getType() {
return m_type;
}
public String toString() {
return "Token(" + Lib.tokenTypeToString(m_type) + ")";
}
}
\ No newline at end of file
package jrr1g18.boring;
public class ValueToken extends Token {
private Integer m_value;
public ValueToken(TokenType type, final Integer name) {
super(type);
m_value = new Integer(name);
}
public ValueToken(TokenType type, final int name) {
super(type);
m_value = new Integer(name);
}
public ValueToken(TokenType type) {
super(type);
m_value = null;
}
@Override
public String toString() {
return "ValueToken(" + Lib.tokenTypeToString(getType()) + ", "
+ getValue() + ")";
}
public Integer getValue() {
return m_value;
}
public void setValue(ValueToken value) {
m_value = value.getValue();
}
public void setValue(final Integer value) {
m_value = new Integer(value);
}
}
package jrr1g18.boring.exceptions;
public class BoringException extends Exception {
public BoringException(String message) {
super(message);
}