diff --git a/build.xml b/build.xml
index f8acc18..a663a7d 100644
--- a/build.xml
+++ b/build.xml
@@ -41,7 +41,9 @@
+ classpathref="javac.path"
+ debug="on"
+ debuglevel="source,vars,lines"/>
diff --git a/src/edu/utexas/cs345/jdblisp/Lisp.java b/src/edu/utexas/cs345/jdblisp/Lisp.java
index 648b6b9..eff9680 100644
--- a/src/edu/utexas/cs345/jdblisp/Lisp.java
+++ b/src/edu/utexas/cs345/jdblisp/Lisp.java
@@ -1,11 +1,81 @@
package edu.utexas.cs345.jdblisp;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Scanner;
+
+import edu.utexas.cs345.jdblisp.parser.Parser;
+import edu.utexas.cs345.jdblisp.parser.ParseException;
+
/**
* @author Jonathan Bernard (jdbernard@gmail.com)
*/
public class Lisp {
- public static void main(String[] args) {
+ private Parser parser;
+ private SymbolTable globalSymbolTable;
+ private boolean interactive = true;
+ public Lisp() {
+ this(true);
+ }
+
+ public Lisp(boolean interactive) {
+ this.interactive = interactive;
+ Parser parser = new Parser(new ByteArrayInputStream(new byte[]{}));
+ }
+
+ public static void main(String[] args) {
+ Lisp lisp = new Lisp();
+ lisp.repl(System.in, System.out);
+ globalSymbolTable = SpecialForms.createSymbolTable();
+ }
+
+ public void repl(InputStream is, OutputStream os) {
+
+ // wrap input and output in more friendly objects
+ Scanner in = new Scanner(is);
+ PrintWriter out = new PrintWriter(os);
+
+ // print prompt if applicable
+ if (interactive) {
+ out.print("> ");
+ out.flush();
+ }
+
+ // read each line of input
+ while(in.hasNextLine()) {
+
+ // get line
+ String line = in.nextLine();
+
+ // stuff it into an input buffer for the parser
+ ByteArrayInputStream bin = new ByteArrayInputStream(line.getBytes());
+
+ // re-init the parser with the new stream
+ parser.ReInit(bin);
+
+ // parse the line
+ SExp sexp;
+ try { sexp = parser.sexp(); }
+ catch (ParseException pe) {
+ // TODO
+ out.println(pe.getLocalizedMessage());
+ continue;
+ }
+
+ out.println(sexp.display(" "));
+ out.println(sexp.eval(globalSymbolTable).car.body);
+
+ // print prompt if applicable
+ if (interactive) {
+ out.print("> ");
+ out.flush();
+ }
+
+ }
}
}
diff --git a/src/edu/utexas/cs345/jdblisp/LispException.java b/src/edu/utexas/cs345/jdblisp/LispException.java
new file mode 100644
index 0000000..1002059
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/LispException.java
@@ -0,0 +1,15 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * LispException
+ */
+public class LispException extends Exception {
+
+ public LispException(String message) {
+ this(message, null);
+ }
+
+ public LispException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/List.java b/src/edu/utexas/cs345/jdblisp/List.java
new file mode 100644
index 0000000..41e7743
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/List.java
@@ -0,0 +1,58 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class List implements SExp {
+ public final Seq seq;
+
+ public List(Seq seq) {
+ this.seq = seq;
+ }
+
+ /** {@inheritdoc}*/
+ public SymbolTable 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
+ // Depending on the funciton binding of the operator in the
+ // current lexical environment the form is either:
+ // a special form
+ // a macro form or
+ // a function form
+
+ // look up in the symbol table
+ TableEntry functionEntry = table.findFunction((Symbol) seq.car);
+
+ // check parameter length
+ if (functionEntry.parameters.length != seq.cdr.length())
+ throw new LispException("Invalid number of parameters: "
+ + seq.cdr.length());
+
+ // create a new SymbolTable and bind arguments to parameters
+ SymbolTable newTable = table;
+ Seq nextArg = seq.cdr;
+ for (Symbol parameter : functionEntry.parameters) {
+ TableEntry newEntry = new TableEntry(parameter, null, nextArg.car);
+ newTable = new SymbolTable(newEntry, newTable);
+ nextArg = nextArg.cdr;
+ }
+
+ // call function
+ return functionEntry.body.eval(newTable);
+
+ }
+
+ return null;
+ }
+
+ public String display(String offset) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(offset);
+ sb.append("List: \n");
+ if (seq == null) sb.append(offset + " NIL\n");
+ else sb.append(seq.display(offset + " "));
+ return sb.toString();
+ }
+
+}
diff --git a/src/edu/utexas/cs345/jdblisp/Num.java b/src/edu/utexas/cs345/jdblisp/Num.java
new file mode 100644
index 0000000..b8251a8
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/Num.java
@@ -0,0 +1,54 @@
+package edu.utexas.cs345.jdblisp;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class Num implements SExp {
+
+ private Number n;
+
+ public Num(String string) {
+ try { n = Short.parseShort(string); return; }
+ catch (NumberFormatException nfe) {}
+
+ try { n = Integer.parseInt(string); return; }
+ catch (NumberFormatException nfe) {}
+
+ try { n = Long.parseLong(string); return; }
+ catch (NumberFormatException nfe) {}
+
+ try { n = new BigInteger(string); return; }
+ catch (NumberFormatException nfe) {}
+
+ try { n = Float.parseFloat(string); return; }
+ catch (NumberFormatException nfe) {}
+
+ 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);
+ }
+ }
+
+ /** {@inheritdoc} */
+ public SymbolTable eval(SymbolTable table) {
+ return new SymbolTable(
+ new TableEntry(
+ new Symbol("RETURN-VAL"),
+ null,
+ this));
+ }
+
+ public String display(String offset) {
+ return offset + "Num: " + n.toString() + "\n";
+ }
+
+ public String toString() {
+ return n.toString();
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/Parser.jj b/src/edu/utexas/cs345/jdblisp/Parser.jj
index 475bbce..5e516f2 100644
--- a/src/edu/utexas/cs345/jdblisp/Parser.jj
+++ b/src/edu/utexas/cs345/jdblisp/Parser.jj
@@ -8,7 +8,7 @@ options {
PARSER_BEGIN(Parser)
package edu.utexas.cs345.jdblisp.parser;
-import edu.utexas.cs345.jdblisp.data.*;
+import edu.utexas.cs345.jdblisp.*;
public class Parser {
}
@@ -44,9 +44,9 @@ TOKEN : /* LITERALS & SYMBOLS */
SExp sexp():
{ SExp s = null; Token t;
}
-{ t = { return new Symbol(t); }
- | t = { return new Str(t); }
- | t = { return new Num(t); }
+{ t = { return new Symbol(t.image.toUpperCase()); }
+ | t = { return new Str(t.image); }
+ | t = { return new Num(t.image); }
| s = list() { return s; }
}
@@ -56,7 +56,7 @@ SExp sexp():
List list():
{ Seq s;
}
-{ s = seq() { return (s == null) ? null : new List(s); }
+{ s = seq() { return new List(s); }
}
/**
diff --git a/src/edu/utexas/cs345/jdblisp/SExp.java b/src/edu/utexas/cs345/jdblisp/SExp.java
new file mode 100644
index 0000000..9fba198
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/SExp.java
@@ -0,0 +1,18 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * SExp
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public interface SExp {
+
+ /**
+ * Evaluate this SExp within the context of the given SymbolTable.
+ * @param table The SymbolTable context for this scope.
+ * @return A SymbolTable containing the reutrn value.
+ */
+ SymbolTable eval(SymbolTable table) throws LispException;
+
+ String display(String offset);
+
+}
diff --git a/src/edu/utexas/cs345/jdblisp/Seq.java b/src/edu/utexas/cs345/jdblisp/Seq.java
new file mode 100644
index 0000000..0014170
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/Seq.java
@@ -0,0 +1,49 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * Seq
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class Seq implements SExp {
+
+ public final SExp car;
+ public final Seq cdr;
+
+ public Seq(SExp car, Seq cdr) {
+ assert (car != null);
+ this.car = car;
+ this.cdr = cdr;
+ }
+
+ public Seq(SExp... elements) {
+ int idx = elements.length;
+ Seq last = null;
+ while (idx > 1) last = new Seq(elements[--idx], last);
+
+ this.car = elements[0];
+ this.cdr = last;
+ }
+
+ /** {@inheritdoc}*/
+ public SymbolTable eval(SymbolTable table) {
+ assert(false) : "Attempted to eval() a Seq.";
+ throw new UnsupportedOperationException("Attempted to eval a Seq.");
+ }
+
+ public int length() {
+ if (cdr == null) return 1;
+ return 1 + cdr.length();
+ }
+
+ public String display(String offset) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(offset);
+ sb.append("Seq: \n");
+
+ sb.append(car.display(offset + " "));
+
+ if (cdr != null) sb.append(cdr.display(offset));
+
+ return sb.toString();
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/Str.java b/src/edu/utexas/cs345/jdblisp/Str.java
new file mode 100644
index 0000000..3fd9841
--- /dev/null
+++ b/src/edu/utexas/cs345/jdblisp/Str.java
@@ -0,0 +1,30 @@
+package edu.utexas.cs345.jdblisp;
+
+/**
+ * @author Jonathan Bernard (jdbernard@gmail.com)
+ */
+public class Str implements SExp {
+
+ public final String value;
+
+ public Str(String value) {
+ this.value = value;
+ }
+
+ /** {@inheritdoc}*/
+ public SymbolTable eval(SymbolTable table) {
+ return new SymbolTable(
+ new TableEntry(
+ "RETURN-VAL",
+ null,
+ this));
+ }
+
+ public String display(String offset) {
+ return offset + "Str: " + value + "\n";
+ }
+
+ public String toString() {
+ return value;
+ }
+}
diff --git a/src/edu/utexas/cs345/jdblisp/data/Symbol.java b/src/edu/utexas/cs345/jdblisp/Symbol.java
similarity index 53%
rename from src/edu/utexas/cs345/jdblisp/data/Symbol.java
rename to src/edu/utexas/cs345/jdblisp/Symbol.java
index e839691..cfcef75 100644
--- a/src/edu/utexas/cs345/jdblisp/data/Symbol.java
+++ b/src/edu/utexas/cs345/jdblisp/Symbol.java
@@ -1,4 +1,5 @@
-package edu.utexas.cs345.jdblisp.data;
+package edu.utexas.cs345.jdblisp;
+
/**
* @author Jonathan Bernard (jdbernard@gmail.com)
*/
@@ -9,8 +10,13 @@ public class Symbol implements SExp {
this.name = name;
}
- public SExp eval(SExp sexp, SymbolTable table) {
+ /** {@inheritdoc}*/
+ public SymbolTable eval(SymbolTable table) {
// TODO
return null;
}
+
+ public String display(String offset) {
+ return offset + "Symbol: " + name + "\n";
+ }
}
diff --git a/src/edu/utexas/cs345/jdblisp/data/List.java b/src/edu/utexas/cs345/jdblisp/data/List.java
deleted file mode 100644
index e67be41..0000000
--- a/src/edu/utexas/cs345/jdblisp/data/List.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package edu.utexas.cs345.jdblisp.data;
-/**
- * @author Jonathan Bernard (jdbernard@gmail.com)
- */
-public class List implements SExp {
- public final Seq seq;
-
- public List(Seq seq) {
- this.seq = seq;
- }
-
- public SExp eval(SExp sexp, SymbolTable table) {
- // TODO
- return null;
- }
-
-}
diff --git a/src/edu/utexas/cs345/jdblisp/data/Num.java b/src/edu/utexas/cs345/jdblisp/data/Num.java
deleted file mode 100644
index dfe3aa3..0000000
--- a/src/edu/utexas/cs345/jdblisp/data/Num.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package edu.utexas.cs345.jdblisp.data;
-/**
- * @author Jonathan Bernard (jdbernard@gmail.com)
- */
-public class Num implements SExp {
-
- public Num(String n) {
- // TODO
- }
-
- public SExp eval(SExp sexp, SymbolTable table) {
- // TODO
- return null;
- }
-
-}
diff --git a/src/edu/utexas/cs345/jdblisp/data/SExp.java b/src/edu/utexas/cs345/jdblisp/data/SExp.java
deleted file mode 100644
index 9354023..0000000
--- a/src/edu/utexas/cs345/jdblisp/data/SExp.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package edu.utexas.cs345.jdblisp.data;
-/**
- * SExp
- * @author Jonathan Bernard (jdbernard@gmail.com)
- */
-public interface SExp {
-
- SymbolTable eval(SExp sexp, SymbolTable table);
-}
diff --git a/src/edu/utexas/cs345/jdblisp/data/Seq.java b/src/edu/utexas/cs345/jdblisp/data/Seq.java
deleted file mode 100644
index 0639cf8..0000000
--- a/src/edu/utexas/cs345/jdblisp/data/Seq.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package edu.utexas.cs345.jdblisp.data;
-/**
- * Seq
- * @author Jonathan Bernard (jdbernard@gmail.com)
- */
-public class Seq implements SExp {
-
- public final T car;
- public final Seq cdr;
-
- public Seq(T car, Seq cdr) {
- this.car = car;
- this.cdr = cdr;
- }
-
- public Seq(T... elements) {
- int idx = elements.length;
- Seq last = null;
- while (idx > 1) last = new Seq(elements[--idx], last);
-
- this.car = elements[0];
- this.cdr = last;
- }
-
- public SExp eval(SExp sexp, SymbolTable table) {
- // TODO
- return null;
- }
-}
diff --git a/src/edu/utexas/cs345/jdblisp/data/Str.java b/src/edu/utexas/cs345/jdblisp/data/Str.java
deleted file mode 100644
index 41009d2..0000000
--- a/src/edu/utexas/cs345/jdblisp/data/Str.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package edu.utexas.cs345.jdblisp.data;
-/**
- * @author Jonathan Bernard (jdbernard@gmail.com)
- */
-public class Str implements SExp {
-
- public SExp eval(SExp sexp, SymbolTable table) {
- // TODO
- return null;
- }
-}
diff --git a/src/edu/utexas/cs345/jdblisp/parser/Parser.java b/src/edu/utexas/cs345/jdblisp/parser/Parser.java
index f77b13a..26f7a6c 100644
--- a/src/edu/utexas/cs345/jdblisp/parser/Parser.java
+++ b/src/edu/utexas/cs345/jdblisp/parser/Parser.java
@@ -1,7 +1,7 @@
/* Generated By:JavaCC: Do not edit this line. Parser.java */
package edu.utexas.cs345.jdblisp.parser;
-import edu.utexas.cs345.jdblisp.data.*;
+import edu.utexas.cs345.jdblisp.*;
public class Parser implements ParserConstants {
/**
@@ -12,15 +12,15 @@ public class Parser implements ParserConstants {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case SYMB:
t = jj_consume_token(SYMB);
- {if (true) return new Symbol(t);}
+ {if (true) return new Symbol(t.image.toUpperCase());}
break;
case STRG:
t = jj_consume_token(STRG);
- {if (true) return new Str(t);}
+ {if (true) return new Str(t.image);}
break;
case NUMB:
t = jj_consume_token(NUMB);
- {if (true) return new Num(t);}
+ {if (true) return new Num(t.image);}
break;
case LPAREN:
s = list();
@@ -42,7 +42,7 @@ public class Parser implements ParserConstants {
jj_consume_token(LPAREN);
s = seq();
jj_consume_token(RPAREN);
- {if (true) return (s == null) ? null : new List(s);}
+ {if (true) return new List(s);}
throw new Error("Missing return statement in function");
}
diff --git a/src/edu/utexas/cs345/jdblisp/parser/ParserTokenManager.java b/src/edu/utexas/cs345/jdblisp/parser/ParserTokenManager.java
index ae61968..548ac2a 100644
--- a/src/edu/utexas/cs345/jdblisp/parser/ParserTokenManager.java
+++ b/src/edu/utexas/cs345/jdblisp/parser/ParserTokenManager.java
@@ -1,6 +1,6 @@
/* Generated By:JavaCC: Do not edit this line. ParserTokenManager.java */
package edu.utexas.cs345.jdblisp.parser;
-import edu.utexas.cs345.jdblisp.data.*;
+import edu.utexas.cs345.jdblisp.*;
/** Token Manager. */
public class ParserTokenManager implements ParserConstants