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.

Verified Commit 2cdedb47 authored by Emily Rowlands's avatar Emily Rowlands
Browse files

Added unary operators

parent c03d9cff
INTEGER = (0|1|2|3|4|5|6|7|8|9)*
SEMICOLON = ;
ADD = +
SUB = -
PLUS = +
MINUS = -
MUL = *
DIV = /
LPAREN = (
RPAREN = )
factor ::= INTEGER | LPAREN expr RPAREN
factor ::= (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN
term ::= factor ((MUL|DIV) factor)*
expr ::= term ((ADD|SUB) term)*
\ No newline at end of file
expr ::= term ((PLUS|MINUS) term)*
\ No newline at end of file
......@@ -77,13 +77,13 @@ public class Lexer {
if(Lib.isInt(m_currentChar)) {
return new ValueToken(TokenType.INTEGER, integer());
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.ADD))) {
.equals(Lib.tokenTypeToString(TokenType.PLUS))) {
nextChar();
return new BasicToken(TokenType.ADD);
return new BasicToken(TokenType.PLUS);
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.SUB))) {
.equals(Lib.tokenTypeToString(TokenType.MINUS))) {
nextChar();
return new BasicToken(TokenType.SUB);
return new BasicToken(TokenType.MINUS);
} else if(m_currentChar
.equals(Lib.tokenTypeToString(TokenType.MUL))) {
nextChar();
......
......@@ -62,8 +62,8 @@ public abstract class Lib {
tempMap.put(TokenType.RPAREN, ")");
tempMap.put(TokenType.DIV, "/");
tempMap.put(TokenType.SUB, "-");
tempMap.put(TokenType.ADD, "+");
tempMap.put(TokenType.MINUS, "-");
tempMap.put(TokenType.PLUS, "+");
tempMap.put(TokenType.MUL, "*");
TOKEN_MAP = Collections.unmodifiableMap(tempMap);
}
......
package jrr1g18.boring;
import jrr1g18.boring.exceptions.IllegalTokenException;
import jrr1g18.boring.nodevisitors.Interpreter;
import jrr1g18.boring.nodevisitors.NodeVisitor;
public class Main {
public static void main(String[] args) throws Exception {
// inputLoop();
Lexer lexer = new Lexer("3*(2+1)");
System.out.println(lexer.getText());
Lexer lexer = new Lexer("-3*(2++1)");
Parser parser = new Parser(lexer);
System.out.println(parser.expr());
NodeVisitor<?> interpreter = new Interpreter(parser);
System.out.println(interpreter.travserse());
}
public static void inputLoop() {
......@@ -22,11 +22,8 @@ public class Main {
}
Lexer lexer = new Lexer(input);
Parser parser = new Parser(lexer);
try {
System.out.println(parser.expr());
} catch(IllegalTokenException e) {
e.printStackTrace();
}
NodeVisitor<?> interpreter = new Interpreter(parser);
System.out.println(interpreter.travserse());
}
}
......
......@@ -2,6 +2,11 @@ package jrr1g18.boring;
import jrr1g18.boring.exceptions.IllegalCharacterException;
import jrr1g18.boring.exceptions.IllegalTokenException;
import jrr1g18.boring.nodes.ASTNode;
import jrr1g18.boring.nodes.ASTNode.NodeType;
import jrr1g18.boring.nodes.BinaryOperationNode;
import jrr1g18.boring.nodes.UnaryOperationNode;
import jrr1g18.boring.nodes.ValueNode;
import jrr1g18.boring.tokens.Token;
import jrr1g18.boring.tokens.Token.TokenType;
import jrr1g18.boring.tokens.ValueToken;
......@@ -25,6 +30,15 @@ public class Parser {
}
}
public ASTNode parse() {
try {
return expr();
} catch(IllegalTokenException e) {
e.printStackTrace();
}
return new ValueNode(NodeType.INTEGER, 0);
}
private static void err(TokenType expected, TokenType actual)
throws IllegalTokenException {
throw new IllegalTokenException(
......@@ -57,50 +71,61 @@ public class Parser {
}
/**
* factor ::= INTEGER | LPAREN expr RPAREN
* factor ::= (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN
*
* @return An integer token value.
* @return The expression as a {@link ASTNode}.
* @throws IllegalTokenException
*/
public int factor() throws IllegalTokenException {
public ASTNode factor() throws IllegalTokenException {
TokenType tt = m_currentToken.getType();
Integer value = null;
ASTNode ret = null;
switch (tt) {
case PLUS:
eat(TokenType.PLUS);
ret = new UnaryOperationNode(NodeType.UNARYPLUS, factor());
break;
case MINUS:
eat(TokenType.MINUS);
ret = new UnaryOperationNode(NodeType.UNARYMINUS, factor());
break;
case INTEGER:
value = ((ValueToken) m_currentToken).getValue();
ret = new ValueNode(NodeType.INTEGER,
((ValueToken) m_currentToken).getValue());
eat(TokenType.INTEGER);
break;
case LPAREN:
eat(TokenType.LPAREN);
value = expr();
ret = expr();
eat(TokenType.RPAREN);
break;
default:
err(tt);
break;
}
return value;
return ret;
}
/**
* term : factor ((MUL|DIV) factor)*
*
* @return The expression result.
* @return The expression as a {@link ASTNode}.
* @throws IllegalTokenException
*/
public int term() throws IllegalTokenException {
int result = factor();
public ASTNode term() throws IllegalTokenException {
ASTNode result = factor();
while(m_currentToken.getType() == TokenType.MUL
|| m_currentToken.getType() == TokenType.DIV) {
TokenType operation = m_currentToken.getType();
switch (operation) {
case MUL:
eat(TokenType.MUL);
result *= factor();
result = new BinaryOperationNode(result, NodeType.MUL,
factor());
break;
case DIV:
eat(TokenType.DIV);
result /= factor();
result = new BinaryOperationNode(result, NodeType.DIV,
factor());
break;
default:
err(operation);
......@@ -111,24 +136,25 @@ public class Parser {
}
/**
* expr : term ((ADD|SUB) term)*
* expr : term ((PLUS|MINUS) term)*
*
* @return The expression result.
* @return The expression as a {@link ASTNode}.
* @throws IllegalTokenException
*/
public int expr() throws IllegalTokenException {
int result = term();
while(m_currentToken.getType() == TokenType.ADD
|| m_currentToken.getType() == TokenType.SUB) {
public ASTNode expr() throws IllegalTokenException {
ASTNode result = term();
while(m_currentToken.getType() == TokenType.PLUS
|| m_currentToken.getType() == TokenType.MINUS) {
TokenType operation = m_currentToken.getType();
switch (operation) {
case ADD:
eat(TokenType.ADD);
result += term();
case PLUS:
eat(TokenType.PLUS);
result = new BinaryOperationNode(result, NodeType.ADD, term());
break;
case SUB:
eat(TokenType.SUB);
result -= term();
case MINUS:
eat(TokenType.MINUS);
result = new BinaryOperationNode(result, NodeType.ADD, term());
break;
default:
break;
......
......@@ -2,27 +2,16 @@ package jrr1g18.boring.nodes;
public abstract class ASTNode {
public enum NodeType {
INTEGER, ADD, SUB, MUL, DIV,
INTEGER, ADD, SUB, MUL, DIV, UNARYPLUS, UNARYMINUS,
}
private final NodeType m_type;
private ASTNode m_parent;
public ASTNode(NodeType type, ASTNode parent) {
m_type = type;
m_parent = parent;
}
public ASTNode(NodeType type) {
m_type = type;
m_parent = null;
}
public NodeType getType() {
return m_type;
}
public ASTNode getParent() {
return m_parent;
}
}
package jrr1g18.boring.nodes;
import jrr1g18.boring.tokens.Token.TokenType;
public class BinaryOperationNode extends ASTNode {
private ASTNode m_lhs;
private ASTNode m_rhs;
TokenType m_operation;
public BinaryOperationNode(ASTNode lhs, NodeType type, ASTNode rhs) {
super(type);
m_lhs = lhs;
m_rhs = rhs;
}
public BinaryOperationNode(NodeType type, TokenType operatorType,
ASTNode parent) {
super(type, parent);
m_operation = operatorType;
public ASTNode getLHS() {
return m_lhs;
}
public BinaryOperationNode(NodeType type, TokenType operatorType) {
super(type);
m_operation = operatorType;
public ASTNode getRHS() {
return m_rhs;
}
}
package jrr1g18.boring.nodes;
public class UnaryOperationNode extends ASTNode {
private ASTNode m_operand;
public UnaryOperationNode(NodeType type, ASTNode operand) {
super(type);
m_operand = operand;
}
public ASTNode getOperand() {
return m_operand;
}
}
......@@ -4,17 +4,12 @@ public class ValueNode extends ASTNode {
private int m_value;
public ValueNode(NodeType type, ASTNode parent, int value) {
super(type, parent);
m_value = value;
}
public ValueNode(NodeType type, int value) {
super(type);
m_value = value;
}
public int getValue() {
public Integer getValue() {
return m_value;
}
}
package jrr1g18.boring.nodevisitors;
import jrr1g18.boring.Parser;
import jrr1g18.boring.nodes.ASTNode;
import jrr1g18.boring.nodes.BinaryOperationNode;
import jrr1g18.boring.nodes.UnaryOperationNode;
import jrr1g18.boring.nodes.ValueNode;
public class Interpreter extends NodeVisitor<Integer> {
public Interpreter(Parser parser) {
super(parser);
}
@Override
protected Integer visit_ValueNode(ASTNode node) {
return ((ValueNode) node).getValue();
}
@Override
protected Integer visit_UnaryOperationNode(ASTNode node) {
ASTNode operand = ((UnaryOperationNode) node).getOperand();
switch (node.getType()) {
case UNARYPLUS:
return visit(operand);
case UNARYMINUS:
return -visit(operand);
default:
return null;
}
}
@Override
protected Integer visit_BinaryOperationNode(ASTNode node) {
ASTNode lhs = ((BinaryOperationNode) node).getLHS();
ASTNode rhs = ((BinaryOperationNode) node).getRHS();
switch (node.getType()) {
case ADD:
return visit(lhs) + visit(rhs);
case DIV:
return visit(lhs) - visit(rhs);
case MUL:
return visit(lhs) * visit(rhs);
case SUB:
return visit(lhs) / visit(rhs);
default:
return null;
}
}
}
package jrr1g18.boring.nodevisitors;
import jrr1g18.boring.Parser;
import jrr1g18.boring.nodes.ASTNode;
import jrr1g18.boring.nodes.BinaryOperationNode;
import jrr1g18.boring.nodes.UnaryOperationNode;
import jrr1g18.boring.nodes.ValueNode;
public class LISPTranslator extends NodeVisitor<String> {
public LISPTranslator(Parser parser) {
super(parser);
}
@Override
protected String visit_ValueNode(ASTNode node) {
return ((ValueNode) node).getValue().toString();
}
@Override
protected String visit_UnaryOperationNode(ASTNode node) {
ASTNode operand = ((UnaryOperationNode) node).getOperand();
switch (node.getType()) {
case UNARYPLUS:
return "u+ (" + visit(operand) + ")";
case UNARYMINUS:
return "u- (" + visit(operand) + ")";
default:
return null;
}
}
@Override
protected String visit_BinaryOperationNode(ASTNode node) {
ASTNode lhs = ((BinaryOperationNode) node).getLHS();
ASTNode rhs = ((BinaryOperationNode) node).getRHS();
switch (node.getType()) {
case ADD:
return "+ (" + visit(lhs) + " " + visit(rhs) + ")";
case SUB:
return "- (" + visit(lhs) + " " + visit(rhs) + ")";
case MUL:
return "* (" + visit(lhs) + " " + visit(rhs) + ")";
case DIV:
return "/ (" + visit(lhs) + " " + visit(rhs) + ")";
default:
return null;
}
}
}
package jrr1g18.boring.nodevisitors;
import jrr1g18.boring.Parser;
import jrr1g18.boring.nodes.ASTNode;
import jrr1g18.boring.nodes.BinaryOperationNode;
import jrr1g18.boring.nodes.UnaryOperationNode;
import jrr1g18.boring.nodes.ValueNode;
public abstract class NodeVisitor<T> {
protected Parser m_parser;
public NodeVisitor(Parser parser) {
m_parser = parser;
}
public T travserse() {
return visit(m_parser.parse());
}
protected T visit(ASTNode node) {
if(node instanceof ValueNode) {
return visit_ValueNode(node);
} else if(node instanceof BinaryOperationNode) {
return visit_BinaryOperationNode(node);
} else if(node instanceof UnaryOperationNode) {
return visit_UnaryOperationNode(node);
}
System.err.print("Unknown node type");
return null;
}
protected abstract T visit_ValueNode(ASTNode node);
protected abstract T visit_UnaryOperationNode(ASTNode node);
protected abstract T visit_BinaryOperationNode(ASTNode node);
}
\ No newline at end of file
package jrr1g18.boring.nodevisitors;
import jrr1g18.boring.Parser;
import jrr1g18.boring.nodes.ASTNode;
import jrr1g18.boring.nodes.BinaryOperationNode;
import jrr1g18.boring.nodes.UnaryOperationNode;
import jrr1g18.boring.nodes.ValueNode;
public class RPNTranslator extends NodeVisitor<String> {
public RPNTranslator(Parser parser) {
super(parser);
}
@Override
protected String visit_ValueNode(ASTNode node) {
return ((ValueNode) node).getValue().toString();
}
@Override
protected String visit_UnaryOperationNode(ASTNode node) {
ASTNode operand = ((UnaryOperationNode) node).getOperand();
switch (node.getType()) {
case UNARYPLUS:
return "u+ (" + visit(operand) + ")";
case UNARYMINUS:
return "u- (" + visit(operand) + ")";
default:
return null;
}
}
@Override
protected String visit_BinaryOperationNode(ASTNode node) {
ASTNode lhs = ((BinaryOperationNode) node).getLHS();
ASTNode rhs = ((BinaryOperationNode) node).getRHS();
switch (node.getType()) {
case ADD:
return visit(lhs) + " " + visit(rhs) + " +";
case SUB:
return visit(lhs) + " " + visit(rhs) + " -";
case MUL:
return visit(lhs) + " " + visit(rhs) + " *";
case DIV:
return visit(lhs) + " " + visit(rhs) + " /";
default:
return null;
}
}
}
......@@ -3,7 +3,7 @@ package jrr1g18.boring.tokens;
public abstract class Token {
public enum TokenType {
EOF, INTEGER, SEMICOLON, ADD, SUB, MUL, DIV, LPAREN, RPAREN
EOF, INTEGER, SEMICOLON, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN
}
private final TokenType m_type;
......
......@@ -76,7 +76,7 @@ class LexerTest {
Lexer lexer = new Lexer("2+3");
List<Token> expected = new ArrayList<Token>();
expected.add(new ValueToken(TokenType.INTEGER, 2));
expected.add(new BasicToken(TokenType.ADD));
expected.add(new BasicToken(TokenType.PLUS));
expected.add(new ValueToken(TokenType.INTEGER, 3));
expected.add(new BasicToken(TokenType.EOF));
......@@ -96,7 +96,7 @@ class LexerTest {
Lexer lexer = new Lexer("2-3");
List<Token> expected = new ArrayList<Token>();
expected.add(new ValueToken(TokenType.INTEGER, 2));
expected.add(new BasicToken(TokenType.SUB));
expected.add(new BasicToken(TokenType.MINUS));
expected.add(new ValueToken(TokenType.INTEGER, 3));
expected.add(new BasicToken(TokenType.EOF));
......@@ -157,7 +157,7 @@ class LexerTest {
List<Token> expected = new ArrayList<Token>();
expected.add(new BasicToken(TokenType.LPAREN));
expected.add(new ValueToken(TokenType.INTEGER, 2));
expected.add(new BasicToken(TokenType.ADD));
expected.add(new BasicToken(TokenType.PLUS));
expected.add(new ValueToken(TokenType.INTEGER, 3));
expected.add(new BasicToken(TokenType.RPAREN));
expected.add(new BasicToken(TokenType.EOF));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment