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
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user