From 1642e5a51aaa03d588ddaab8212e35609897b315 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 20 Nov 2009 10:26:21 -0600 Subject: [PATCH] Function lookup and calling implemented. Some SpecialForms implemented. Special forms: DEFUN SETQ + - * / --- src/edu/utexas/cs345/jdblisp/FormEntry.java | 9 ++ .../utexas/cs345/jdblisp/FunctionEntry.java | 2 +- src/edu/utexas/cs345/jdblisp/Lisp.java | 10 +- src/edu/utexas/cs345/jdblisp/List.java | 6 +- src/edu/utexas/cs345/jdblisp/Num.java | 40 +++-- src/edu/utexas/cs345/jdblisp/SExp.java | 2 +- src/edu/utexas/cs345/jdblisp/Seq.java | 2 +- .../cs345/jdblisp/SpecialFormEntry.java | 149 ++++++++++++++++-- src/edu/utexas/cs345/jdblisp/Str.java | 8 +- src/edu/utexas/cs345/jdblisp/Symbol.java | 2 +- src/edu/utexas/cs345/jdblisp/SymbolTable.java | 8 +- 11 files changed, 197 insertions(+), 41 deletions(-) create mode 100644 src/edu/utexas/cs345/jdblisp/FormEntry.java diff --git a/src/edu/utexas/cs345/jdblisp/FormEntry.java b/src/edu/utexas/cs345/jdblisp/FormEntry.java new file mode 100644 index 0000000..5006d3b --- /dev/null +++ b/src/edu/utexas/cs345/jdblisp/FormEntry.java @@ -0,0 +1,9 @@ +package edu.utexas.cs345.jdblisp; + +/** + * FormEntry + * @author Jonathan Bernard(jdbernard@gmail.com) + */ +public interface FormEntry { + SExp call(SymbolTable table, Seq arguments) throws LispException; +} diff --git a/src/edu/utexas/cs345/jdblisp/FunctionEntry.java b/src/edu/utexas/cs345/jdblisp/FunctionEntry.java index 60af07c..c65df30 100755 --- a/src/edu/utexas/cs345/jdblisp/FunctionEntry.java +++ b/src/edu/utexas/cs345/jdblisp/FunctionEntry.java @@ -4,7 +4,7 @@ package edu.utexas.cs345.jdblisp; * FunctionEntry * @author Jonathan Bernard (jdbernard@gmail.com) */ -public class FunctionEntry { +public class FunctionEntry implements FormEntry { protected final Symbol[] parameters; protected final SExp body; diff --git a/src/edu/utexas/cs345/jdblisp/Lisp.java b/src/edu/utexas/cs345/jdblisp/Lisp.java index 1b9a042..503560b 100755 --- a/src/edu/utexas/cs345/jdblisp/Lisp.java +++ b/src/edu/utexas/cs345/jdblisp/Lisp.java @@ -68,7 +68,12 @@ public class Lisp { continue; } - out.println(sexp.display(" ")); + try { + out.println(sexp.display(" ")); + out.println(sexp.eval(globalSymbolTable)); + } catch (LispException le) { + out.println(le.getLocalizedMessage()); + } // print prompt if applicable if (interactive) { @@ -77,6 +82,9 @@ public class Lisp { } } + + out.println("\nLeaving JDB-LISP"); + out.flush(); } } diff --git a/src/edu/utexas/cs345/jdblisp/List.java b/src/edu/utexas/cs345/jdblisp/List.java index 840316c..11aa688 100755 --- a/src/edu/utexas/cs345/jdblisp/List.java +++ b/src/edu/utexas/cs345/jdblisp/List.java @@ -12,7 +12,7 @@ public class List implements SExp { } /** {@inheritdoc}*/ - public SymbolTable eval(SymbolTable table) throws LispException { + public SExp eval(SymbolTable table) throws LispException { // if the car of the sequence is a symbol, if (seq.car instanceof Symbol) { // then that symbol is the name of an operator @@ -24,10 +24,10 @@ public class List implements SExp { // a function form // look up in the symbol table - FunctionEntry functionEntry = table.lookupFunction((Symbol) seq.car); + FormEntry functionEntry = table.lookupFunction((Symbol) seq.car); // call function - return functionEntry.call(table); + return functionEntry.call(table, seq.cdr); } diff --git a/src/edu/utexas/cs345/jdblisp/Num.java b/src/edu/utexas/cs345/jdblisp/Num.java index d32f00d..d0e21ad 100755 --- a/src/edu/utexas/cs345/jdblisp/Num.java +++ b/src/edu/utexas/cs345/jdblisp/Num.java @@ -8,10 +8,10 @@ import java.math.BigInteger; */ public class Num implements SExp { - private Number n; + private BigDecimal n; public Num(String string) { - try { n = Short.parseShort(string); return; } + /*try { n = Short.parseShort(string); return; } catch (NumberFormatException nfe) {} try { n = Integer.parseInt(string); return; } @@ -28,20 +28,18 @@ public class Num implements SExp { try { n = Double.parseDouble(string); return; } catch (NumberFormatException nfe) {} - +*/ try { n = new BigDecimal(string); return; } catch (NumberFormatException nfe) { - throw new LispException("Cannot parse number: " + string); + assert(false); } } + public Num(BigDecimal n) { this.n = n; } + /** {@inheritdoc} */ public SExp eval(SymbolTable table) { - return new SymbolTable( - new TableEntry( - new Symbol("RETURN-VAL"), - null, - this)); + return this; } public String display(String offset) { @@ -52,4 +50,28 @@ public class Num implements SExp { public String toString() { return n.toString(); } + + public Num add(Num addend) { + return new Num(n.add(addend.n)); + } + + public Num subtract(Num subtrahend) { + return new Num(n.subtract(subtrahend.n)); + } + + public Num multiply(Num multiplicand) { + return new Num(n.multiply(multiplicand.n)); + } + + public Num divideBy(Num divisor) { + return new Num(n.divide(divisor.n)); + } + + public Num negate() { + return new Num(n.negate()); + } + + public Num abs() { + return new Num(n.abs()); + } } diff --git a/src/edu/utexas/cs345/jdblisp/SExp.java b/src/edu/utexas/cs345/jdblisp/SExp.java index 9fba198..f93db52 100755 --- a/src/edu/utexas/cs345/jdblisp/SExp.java +++ b/src/edu/utexas/cs345/jdblisp/SExp.java @@ -11,7 +11,7 @@ public interface SExp { * @param table The SymbolTable context for this scope. * @return A SymbolTable containing the reutrn value. */ - SymbolTable eval(SymbolTable table) throws LispException; + SExp eval(SymbolTable table) throws LispException; String display(String offset); diff --git a/src/edu/utexas/cs345/jdblisp/Seq.java b/src/edu/utexas/cs345/jdblisp/Seq.java index 51372b6..b46af21 100755 --- a/src/edu/utexas/cs345/jdblisp/Seq.java +++ b/src/edu/utexas/cs345/jdblisp/Seq.java @@ -25,7 +25,7 @@ public class Seq implements SExp { } /** {@inheritdoc}*/ - public SymbolTable eval(SymbolTable table) { + public SExp eval(SymbolTable table) { assert(false) : "Attempted to eval() a Seq."; throw new UnsupportedOperationException("Attempted to eval a Seq."); } diff --git a/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java b/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java index 759cd94..2439b4b 100755 --- a/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java +++ b/src/edu/utexas/cs345/jdblisp/SpecialFormEntry.java @@ -6,7 +6,7 @@ import java.util.ArrayList; * SpecialFormEntry * @author Jonathan Bernard (jdbernard@gmail.com) */ -public abstract class SpecialFormEntry extends FunctionEntry { +public abstract class SpecialFormEntry implements FormEntry { protected Lisp environment; @@ -21,7 +21,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException { Symbol functionName; - ArrayList parameters; + ArrayList parameters = new ArrayList(); SExp body; // TODO: check to see if a function for this symbol exists @@ -40,18 +40,17 @@ public abstract class SpecialFormEntry extends FunctionEntry { arguments = arguments.cdr; assert (arguments != null); - if (!(arguments.car instanceof List)) + //if (!(arguments.car instanceof List)) // TODO: error, need parameter list // read parameters - parameters = new ArrayList(); Seq paramSeq = ((List) arguments.car).seq; - while (seq != null) { - if (!(seq.car instanceof Symbol)) - throw new TypeException(seq.car, Symbol.class); + while (paramSeq != null) { + if (!(paramSeq.car instanceof Symbol)) + throw new TypeException(paramSeq.car, Symbol.class); - parameters.add((Symbol) seq.car); - seq = seq.cdr; + parameters.add((Symbol) paramSeq.car); + paramSeq = paramSeq.cdr; } // third argument: function body @@ -62,7 +61,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { body = arguments.car; - environment.globalSymbolTable.define(functionName, + environment.globalSymbolTable.bind(functionName, new FunctionEntry(parameters.toArray(new Symbol[]{}), body)); return functionName; @@ -82,7 +81,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { arguments.length()); // first argument: Symbol for variable name - if (!(arguments.car instanceof Symbol)) + //if (!(arguments.car instanceof Symbol)) // TODO: error: expected symbol variableName = (Symbol) arguments.car; @@ -92,10 +91,134 @@ public abstract class SpecialFormEntry extends FunctionEntry { assert (arguments != null); variableValue = arguments.car; + + environment.globalSymbolTable.bind(variableName, + new VariableEntry(variableValue)); + + return variableValue; } }; - environment.globalSymbolTable.defin(new Symbol("DEFUN"), DEFUN); - environment.globalSymbolTable.defin(new Symbol("SETQ"), SETQ); + SpecialFormEntry SUM = new SpecialFormEntry(environment) { + public SExp call(SymbolTable symbolTable, Seq arguments) + throws LispException { + + Num sum = new Num("0"); + + // variable number of arguments [0..inf) + while (arguments != null) { + try { + sum = sum.add((Num) arguments.car.eval(symbolTable)); + } catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + } + + return sum; + } + }; + + SpecialFormEntry DIF = new SpecialFormEntry(environment) { + public SExp call(SymbolTable symbolTable, Seq arguments) + throws LispException { + + Num difference = new Num("0"); + + // need at least one argument + if (arguments == null) + throw new InvalidArgumentQuantityException(1, 0); + + // case: only one argument: 0 - arg + try { + difference = difference.subtract( + (Num) arguments.car.eval(symbolTable)); + } catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + + arguments = arguments.cdr; + if (arguments == null) return difference; + + // case: (- x y1 ... yn) + difference = difference.negate(); + + // variable number of arguments [0..inf) + while (arguments != null) { + try { + difference = difference.subtract( + (Num) arguments.car.eval(symbolTable)); + } catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + } + + return difference; + } + }; + + SpecialFormEntry MUL = new SpecialFormEntry(environment) { + public SExp call(SymbolTable symbolTable, Seq arguments) + throws LispException { + + Num product = new Num("1"); + + // variable number of arguments [0..inf) + while (arguments != null) { + try { + product = product.multiply( + (Num) arguments.car.eval(symbolTable)); + } catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + } + + return product; + } + }; + + SpecialFormEntry DIV = new SpecialFormEntry(environment) { + public SExp call(SymbolTable symbolTable, Seq arguments) + throws LispException { + + Num dividend = new Num("1"); + Num firstArg; + + if (arguments == null) + throw new InvalidArgumentQuantityException(1, 0); + + // case: only one argument: 1 / arg + try { firstArg = (Num) arguments.car.eval(symbolTable); } + catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + + dividend = dividend.divideBy(firstArg); + + arguments = arguments.cdr; + if (arguments == null) return dividend; + + // case: (/ x y1 ... yn) + dividend = firstArg; + + // variable number of arguments [0..inf) + while (arguments != null) { + try { + dividend = dividend.divideBy( + (Num) arguments.car.eval(symbolTable)); + } catch (ClassCastException cce) { + throw new TypeException(arguments.car, Num.class); + } + } + + return dividend; + } + }; + + environment.globalSymbolTable.bind(new Symbol("DEFUN"), DEFUN); + environment.globalSymbolTable.bind(new Symbol("SETQ"), SETQ); + environment.globalSymbolTable.bind(new Symbol("+"), SUM); + environment.globalSymbolTable.bind(new Symbol("-"), DIF); + environment.globalSymbolTable.bind(new Symbol("*"), MUL); + environment.globalSymbolTable.bind(new Symbol("/"), DIV); } } diff --git a/src/edu/utexas/cs345/jdblisp/Str.java b/src/edu/utexas/cs345/jdblisp/Str.java index 59c8234..496670a 100755 --- a/src/edu/utexas/cs345/jdblisp/Str.java +++ b/src/edu/utexas/cs345/jdblisp/Str.java @@ -12,13 +12,7 @@ public class Str implements SExp { } /** {@inheritdoc}*/ - public SymbolTable eval(SymbolTable table) { - return new SymbolTable( - new TableEntry( - "RETURN-VAL", - null, - this)); - } + public SExp eval(SymbolTable table) { return this; } public String display(String offset) { return offset + "Str: " + value + "\n"; diff --git a/src/edu/utexas/cs345/jdblisp/Symbol.java b/src/edu/utexas/cs345/jdblisp/Symbol.java index 45f0e2a..db0cad8 100755 --- a/src/edu/utexas/cs345/jdblisp/Symbol.java +++ b/src/edu/utexas/cs345/jdblisp/Symbol.java @@ -11,7 +11,7 @@ public class Symbol implements SExp { } /** {@inheritdoc}*/ - public SymbolTable eval(SymbolTable table) { + public SExp eval(SymbolTable table) { // TODO return null; } diff --git a/src/edu/utexas/cs345/jdblisp/SymbolTable.java b/src/edu/utexas/cs345/jdblisp/SymbolTable.java index 2645a53..b837dbf 100755 --- a/src/edu/utexas/cs345/jdblisp/SymbolTable.java +++ b/src/edu/utexas/cs345/jdblisp/SymbolTable.java @@ -9,7 +9,7 @@ import java.util.Map; */ public class SymbolTable { - private Map functions = new HashMap(); + private Map functions = new HashMap(); private Map variables = new HashMap(); private SymbolTable enclosingTable; private boolean locked = false; @@ -23,7 +23,7 @@ public class SymbolTable { this.locked = locked; } - public Symbol bind(Symbol s, FunctionEntry f) { + public Symbol bind(Symbol s, FormEntry f) { if (functions.get(s) != null) { // TODO: warning: function redefinition // Also, check access permissions @@ -42,8 +42,8 @@ public class SymbolTable { return s; } - public FunctionEntry lookupFunction(Symbol s) throws LispException { - FunctionEntry fe = functions.get(s); + public FormEntry lookupFunction(Symbol s) throws LispException { + FormEntry fe = functions.get(s); // found function definition if (fe != null) return fe;