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