Function lookup and calling implemented. Some SpecialForms implemented.
Special forms:
    DEFUN
    SETQ
    +
    -
    *
    /
			
			
This commit is contained in:
		
							
								
								
									
										9
									
								
								src/edu/utexas/cs345/jdblisp/FormEntry.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/edu/utexas/cs345/jdblisp/FormEntry.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||||
|  | } | ||||||
| @@ -4,7 +4,7 @@ package edu.utexas.cs345.jdblisp; | |||||||
|  * FunctionEntry |  * FunctionEntry | ||||||
|  * @author Jonathan Bernard (jdbernard@gmail.com) |  * @author Jonathan Bernard (jdbernard@gmail.com) | ||||||
|  */ |  */ | ||||||
| public class FunctionEntry { | public class FunctionEntry implements FormEntry { | ||||||
|  |  | ||||||
|     protected final Symbol[] parameters; |     protected final Symbol[] parameters; | ||||||
|     protected final SExp body; |     protected final SExp body; | ||||||
|   | |||||||
| @@ -68,7 +68,12 @@ public class Lisp { | |||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             try { | ||||||
|                 out.println(sexp.display("  ")); |                 out.println(sexp.display("  ")); | ||||||
|  |                 out.println(sexp.eval(globalSymbolTable)); | ||||||
|  |             } catch (LispException le) { | ||||||
|  |                 out.println(le.getLocalizedMessage()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // print prompt if applicable |             // print prompt if applicable | ||||||
|             if (interactive) { |             if (interactive) { | ||||||
| @@ -77,6 +82,9 @@ public class Lisp { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         out.println("\nLeaving JDB-LISP"); | ||||||
|  |         out.flush(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ public class List implements SExp { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** {@inheritdoc}*/ |     /** {@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 the car of the sequence is a symbol,  | ||||||
|         if (seq.car instanceof Symbol) { |         if (seq.car instanceof Symbol) { | ||||||
|             // then that symbol is the name of an operator |             // then that symbol is the name of an operator | ||||||
| @@ -24,10 +24,10 @@ public class List implements SExp { | |||||||
|             // a function form |             // a function form | ||||||
|  |  | ||||||
|             // look up in the symbol table |             // look up in the symbol table | ||||||
|             FunctionEntry functionEntry = table.lookupFunction((Symbol) seq.car); |             FormEntry functionEntry = table.lookupFunction((Symbol) seq.car); | ||||||
|  |  | ||||||
|             // call function |             // call function | ||||||
|             return functionEntry.call(table); |             return functionEntry.call(table, seq.cdr); | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,10 +8,10 @@ import java.math.BigInteger; | |||||||
|  */ |  */ | ||||||
| public class Num implements SExp { | public class Num implements SExp { | ||||||
|  |  | ||||||
|     private Number n; |     private BigDecimal n; | ||||||
|  |  | ||||||
|     public Num(String string) { |     public Num(String string) { | ||||||
|         try { n = Short.parseShort(string); return; } |         /*try { n = Short.parseShort(string); return; } | ||||||
|         catch (NumberFormatException nfe) {} |         catch (NumberFormatException nfe) {} | ||||||
|  |  | ||||||
|         try { n = Integer.parseInt(string); return; } |         try { n = Integer.parseInt(string); return; } | ||||||
| @@ -28,20 +28,18 @@ public class Num implements SExp { | |||||||
|  |  | ||||||
|         try { n = Double.parseDouble(string); return; } |         try { n = Double.parseDouble(string); return; } | ||||||
|         catch (NumberFormatException nfe) {} |         catch (NumberFormatException nfe) {} | ||||||
|  | */ | ||||||
|         try { n = new BigDecimal(string); return; } |         try { n = new BigDecimal(string); return; } | ||||||
|         catch (NumberFormatException nfe) { |         catch (NumberFormatException nfe) { | ||||||
|             throw new LispException("Cannot parse number: " + string); |             assert(false); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public Num(BigDecimal n) { this.n = n; } | ||||||
|  |  | ||||||
|     /** {@inheritdoc} */ |     /** {@inheritdoc} */ | ||||||
|     public SExp eval(SymbolTable table) { |     public SExp eval(SymbolTable table) { | ||||||
|         return new SymbolTable( |         return this; | ||||||
|             new TableEntry( |  | ||||||
|                 new Symbol("RETURN-VAL"), |  | ||||||
|                 null, |  | ||||||
|                 this)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public String display(String offset) { |     public String display(String offset) { | ||||||
| @@ -52,4 +50,28 @@ public class Num implements SExp { | |||||||
|     public String toString() { |     public String toString() { | ||||||
|         return n.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()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ public interface SExp { | |||||||
|      * @param table The SymbolTable context for this scope. |      * @param table The SymbolTable context for this scope. | ||||||
|      * @return A SymbolTable containing the reutrn value. |      * @return A SymbolTable containing the reutrn value. | ||||||
|      */ |      */ | ||||||
|     SymbolTable eval(SymbolTable table) throws LispException; |     SExp eval(SymbolTable table) throws LispException; | ||||||
|  |  | ||||||
|     String display(String offset); |     String display(String offset); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ public class Seq implements SExp { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** {@inheritdoc}*/ |     /** {@inheritdoc}*/ | ||||||
|     public SymbolTable eval(SymbolTable table) { |     public SExp eval(SymbolTable table) { | ||||||
|         assert(false) : "Attempted to eval() a Seq."; |         assert(false) : "Attempted to eval() a Seq."; | ||||||
|         throw new UnsupportedOperationException("Attempted to eval a Seq."); |         throw new UnsupportedOperationException("Attempted to eval a Seq."); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import java.util.ArrayList; | |||||||
|  * SpecialFormEntry |  * SpecialFormEntry | ||||||
|  * @author Jonathan Bernard (jdbernard@gmail.com) |  * @author Jonathan Bernard (jdbernard@gmail.com) | ||||||
|  */ |  */ | ||||||
| public abstract class SpecialFormEntry extends FunctionEntry { | public abstract class SpecialFormEntry implements FormEntry { | ||||||
|  |  | ||||||
|     protected Lisp environment; |     protected Lisp environment; | ||||||
|  |  | ||||||
| @@ -21,7 +21,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { | |||||||
|             public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException { |             public SExp call(SymbolTable symbolTable, Seq arguments) throws LispException { | ||||||
|  |  | ||||||
|                 Symbol functionName; |                 Symbol functionName; | ||||||
|                 ArrayList<Symbol> parameters; |                 ArrayList<Symbol> parameters = new ArrayList<Symbol>(); | ||||||
|                 SExp body; |                 SExp body; | ||||||
|  |  | ||||||
|                 // TODO: check to see if a function for this symbol exists |                 // TODO: check to see if a function for this symbol exists | ||||||
| @@ -40,18 +40,17 @@ public abstract class SpecialFormEntry extends FunctionEntry { | |||||||
|                 arguments = arguments.cdr; |                 arguments = arguments.cdr; | ||||||
|                 assert (arguments != null); |                 assert (arguments != null); | ||||||
|                  |                  | ||||||
|                 if (!(arguments.car instanceof List)) |                 //if (!(arguments.car instanceof List)) | ||||||
|                     // TODO: error, need parameter list |                     // TODO: error, need parameter list | ||||||
|  |  | ||||||
|                 // read parameters |                 // read parameters | ||||||
|                 parameters = new ArrayList<Symbol>(); |  | ||||||
|                 Seq paramSeq = ((List) arguments.car).seq; |                 Seq paramSeq = ((List) arguments.car).seq; | ||||||
|                 while (seq != null) { |                 while (paramSeq != null) { | ||||||
|                     if (!(seq.car instanceof Symbol)) |                     if (!(paramSeq.car instanceof Symbol)) | ||||||
|                         throw new TypeException(seq.car, Symbol.class); |                         throw new TypeException(paramSeq.car, Symbol.class); | ||||||
|  |  | ||||||
|                     parameters.add((Symbol) seq.car); |                     parameters.add((Symbol) paramSeq.car); | ||||||
|                     seq = seq.cdr; |                     paramSeq = paramSeq.cdr; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // third argument: function body |                 // third argument: function body | ||||||
| @@ -62,7 +61,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { | |||||||
|                  |                  | ||||||
|                 body = arguments.car; |                 body = arguments.car; | ||||||
|  |  | ||||||
|                 environment.globalSymbolTable.define(functionName, |                 environment.globalSymbolTable.bind(functionName, | ||||||
|                     new FunctionEntry(parameters.toArray(new Symbol[]{}), body)); |                     new FunctionEntry(parameters.toArray(new Symbol[]{}), body)); | ||||||
|  |  | ||||||
|                 return functionName; |                 return functionName; | ||||||
| @@ -82,7 +81,7 @@ public abstract class SpecialFormEntry extends FunctionEntry { | |||||||
|                         arguments.length()); |                         arguments.length()); | ||||||
|  |  | ||||||
|                 // first argument: Symbol for variable name |                 // first argument: Symbol for variable name | ||||||
|                 if (!(arguments.car instanceof Symbol)) |                 //if (!(arguments.car instanceof Symbol)) | ||||||
|                     // TODO: error: expected symbol |                     // TODO: error: expected symbol | ||||||
|  |  | ||||||
|                 variableName = (Symbol) arguments.car; |                 variableName = (Symbol) arguments.car; | ||||||
| @@ -92,10 +91,134 @@ public abstract class SpecialFormEntry extends FunctionEntry { | |||||||
|                 assert (arguments != null); |                 assert (arguments != null); | ||||||
|  |  | ||||||
|                 variableValue = arguments.car; |                 variableValue = arguments.car; | ||||||
|  |  | ||||||
|  |                 environment.globalSymbolTable.bind(variableName, | ||||||
|  |                     new VariableEntry(variableValue)); | ||||||
|  |  | ||||||
|  |                 return variableValue; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         environment.globalSymbolTable.defin(new Symbol("DEFUN"), DEFUN); |         SpecialFormEntry SUM = new SpecialFormEntry(environment) { | ||||||
|         environment.globalSymbolTable.defin(new Symbol("SETQ"), SETQ); |             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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,13 +12,7 @@ public class Str implements SExp { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** {@inheritdoc}*/ |     /** {@inheritdoc}*/ | ||||||
|     public SymbolTable eval(SymbolTable table) { |     public SExp eval(SymbolTable table) { return this; } | ||||||
|         return new SymbolTable( |  | ||||||
|             new TableEntry( |  | ||||||
|                 "RETURN-VAL", |  | ||||||
|                 null, |  | ||||||
|                 this)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public String display(String offset) { |     public String display(String offset) { | ||||||
|         return offset + "Str: " + value + "\n"; |         return offset + "Str: " + value + "\n"; | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ public class Symbol implements SExp { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** {@inheritdoc}*/ |     /** {@inheritdoc}*/ | ||||||
|     public SymbolTable eval(SymbolTable table) { |     public SExp eval(SymbolTable table) { | ||||||
|         // TODO |         // TODO | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import java.util.Map; | |||||||
|  */ |  */ | ||||||
| public class SymbolTable { | public class SymbolTable { | ||||||
|  |  | ||||||
|     private Map<Symbol, FunctionEntry> functions = new HashMap<Symbol, FunctionEntry>(); |     private Map<Symbol, FormEntry> functions = new HashMap<Symbol, FormEntry>(); | ||||||
|     private Map<Symbol, VariableEntry> variables = new HashMap<Symbol, VariableEntry>(); |     private Map<Symbol, VariableEntry> variables = new HashMap<Symbol, VariableEntry>(); | ||||||
|     private SymbolTable enclosingTable; |     private SymbolTable enclosingTable; | ||||||
|     private boolean locked = false; |     private boolean locked = false; | ||||||
| @@ -23,7 +23,7 @@ public class SymbolTable { | |||||||
|         this.locked = locked; |         this.locked = locked; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public Symbol bind(Symbol s, FunctionEntry f) { |     public Symbol bind(Symbol s, FormEntry f) { | ||||||
|         if (functions.get(s) != null) { |         if (functions.get(s) != null) { | ||||||
|             // TODO: warning: function redefinition |             // TODO: warning: function redefinition | ||||||
|             // Also, check access permissions |             // Also, check access permissions | ||||||
| @@ -42,8 +42,8 @@ public class SymbolTable { | |||||||
|         return s; |         return s; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public FunctionEntry lookupFunction(Symbol s) throws LispException { |     public FormEntry lookupFunction(Symbol s) throws LispException { | ||||||
|         FunctionEntry fe = functions.get(s); |         FormEntry fe = functions.get(s); | ||||||
|  |  | ||||||
|         // found function definition |         // found function definition | ||||||
|         if (fe != null) return fe; |         if (fe != null) return fe; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user