Function lookup and calling implemented. Some SpecialForms implemented.
Special forms: DEFUN SETQ + - * /
This commit is contained in:
parent
f6d3658342
commit
1642e5a51a
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
|
||||
* @author Jonathan Bernard (jdbernard@gmail.com)
|
||||
*/
|
||||
public class FunctionEntry {
|
||||
public class FunctionEntry implements FormEntry {
|
||||
|
||||
protected final Symbol[] parameters;
|
||||
protected final SExp body;
|
||||
|
@ -68,7 +68,12 @@ public class Lisp {
|
||||
continue;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -11,7 +11,7 @@ public class Symbol implements SExp {
|
||||
}
|
||||
|
||||
/** {@inheritdoc}*/
|
||||
public SymbolTable eval(SymbolTable table) {
|
||||
public SExp eval(SymbolTable table) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user