Administrator approval is now required for registering new accounts. If you are registering a new account, and are external to the University, please ask the repository owner to contact ServiceLine to request your account be approved. Repository owners must include the newly registered email address, and specific repository in the request for approval.

Commit 647e6148 authored by mutantoe's avatar mutantoe
Browse files
parents f7cc44ba 337459e4
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);
}