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
* @author Jonathan Bernard (jdbernard@gmail.com)
*/
public class FunctionEntry {
public class FunctionEntry implements FormEntry {
protected final Symbol[] parameters;
protected final SExp body;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Symbol> parameters;
ArrayList<Symbol> parameters = new ArrayList<Symbol>();
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<Symbol>();
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);
}
}

View File

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

View File

@ -11,7 +11,7 @@ public class Symbol implements SExp {
}
/** {@inheritdoc}*/
public SymbolTable eval(SymbolTable table) {
public SExp eval(SymbolTable table) {
// TODO
return null;
}

View File

@ -9,7 +9,7 @@ import java.util.Map;
*/
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 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;