Function lookup and calling implemented. Some SpecialForms implemented.

Special forms:
    DEFUN
    SETQ
    +
    -
    *
    /
This commit is contained in:
Jonathan Bernard 2009-11-20 10:26:21 -06:00
parent f6d3658342
commit 1642e5a51a
11 changed files with 197 additions and 41 deletions

View 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;
}

View File

@ -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;

View File

@ -68,7 +68,12 @@ public class Lisp {
continue; 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 // print prompt if applicable
if (interactive) { if (interactive) {
@ -77,6 +82,9 @@ public class Lisp {
} }
} }
out.println("\nLeaving JDB-LISP");
out.flush();
} }
} }

View File

@ -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);
} }

View File

@ -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());
}
} }

View File

@ -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);

View File

@ -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.");
} }

View File

@ -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);
} }
} }

View File

@ -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";

View File

@ -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;
} }

View File

@ -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;