Added keywords, several new special forms

This commit is contained in:
Jonathan Bernard 2009-11-24 09:22:52 -06:00
parent dfc1234817
commit e6a608ee2b
19 changed files with 997 additions and 448 deletions

View File

@ -47,5 +47,8 @@
</target>
<target name="dist" depends="init,compile"/>
<target name="dist" depends="init,compile">
<mkdir dir="${dist.dir}"/>
</target>
</project>

View File

@ -4,3 +4,4 @@ dist.dir=dist
lib.dir=lib
grammar.file=${src.dir}/edu/utexas/cs345/jdblisp/Parser.jj
grammar.output.dir=${src.dir}/edu/utexas/cs345/jdblisp/parser
project.version=0.1.0

View File

@ -11,4 +11,12 @@ public class InvalidArgumentQuantityException extends LispException {
super ("Invalid number of arguments: " + actual
+ " (expected " + expected + ").");
}
public InvalidArgumentQuantityException(int actual) {
super ("Invalid number of arguments: " + actual);
}
public InvalidArgumentQuantityException(String message) {
super ("Invalid number of arguments: " + message);
}
}

View File

@ -0,0 +1,29 @@
package edu.utexas.cs345.jdblisp;
/**
* Keyword
* @author Jonathan Bernard (jdbernard@gmail.com)
*/
public class Keyword extends Symbol {
public Keyword(String name) { super(name); }
/** {@inheritdoc} */
@Override
public SExp eval(SymbolTable symbolTable) { return this; }
public String display(String offset) {
return offset + "Keyword: " + name + "\n";
}
@Override
public String toString() { return ":" + name; }
@Override
public boolean equals(Object that) {
if (this == that) return true;
if (that == null) return false;
if (!(that instanceof Keyword)) return false;
return this.name.equals(((Keyword) that).name);
}
}

View File

@ -35,9 +35,13 @@ public class LISPRuntime {
public LISPRuntime(boolean interactive) {
this.interactive = interactive;
Parser parser = new Parser(new ByteArrayInputStream(new byte[]{}));
globalSymbolTable = new SymbolTable();
// build global constants
SymbolTable constantsSymbolTable = defineGlobalConstants();
// build global symbol table
globalSymbolTable = new SymbolTable(constantsSymbolTable);
SpecialFormEntry.defineSpecialForms(this);
globalSymbolTable.bind(new Symbol("T"), new VariableEntry(SExp.T));
}
// TODO: is this needed?
@ -114,4 +118,12 @@ public class LISPRuntime {
OutputStream getOutputStream() { return os; }
private static SymbolTable defineGlobalConstants() {
SymbolTable constantsTable = new SymbolTable();
constantsTable.bind(new Symbol("T"), new VariableEntry(SExp.T, true));
constantsTable.bind(new Symbol("NIL"), new VariableEntry(SExp.NIL, true));
return constantsTable;
}
}

View File

@ -1,93 +0,0 @@
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 SymbolTable globalSymbolTable;
private Parser parser;
private boolean interactive = true;
public Lisp() {
this(true);
}
public Lisp(boolean interactive) {
this.interactive = interactive;
Parser parser = new Parser(new ByteArrayInputStream(new byte[]{}));
globalSymbolTable = new SymbolTable();
SpecialFormEntry.defineSpecialForms(this);
}
public static void main(String[] args) {
Lisp lisp = new Lisp();
lisp.repl(System.in, System.out);
}
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;
}
// DEBUG: print abstract syntax TODO: remove
out.println(sexp.display(" "));
out.flush();
try {
out.println(sexp.eval(globalSymbolTable));
} catch (LispException le) {
out.println(le.getLocalizedMessage());
}
// print prompt if applicable
if (interactive) {
out.print("> ");
out.flush();
}
}
out.println("\nLeaving JDB-LISP");
out.flush();
}
}

View File

@ -15,7 +15,7 @@ public class List implements SExp {
public SExp eval(SymbolTable table) throws LispException {
// null is NIL
if (seq == null) return null;
if (seq == null) return SExp.NIL;
// if the car of the sequence is a symbol,
if (seq.car instanceof Symbol) {
@ -35,7 +35,7 @@ public class List implements SExp {
}
return null;
return SExp.NIL;
}
public String display(String offset) {
@ -49,7 +49,7 @@ public class List implements SExp {
@Override
public String toString() {
return "(" + (seq == null ? "" : seq.toString()) + ")";
return seq == null ? "NIL" : "(" + seq.toString() + ")";
}
}

View File

@ -11,6 +11,7 @@ package edu.utexas.cs345.jdblisp.parser;
import edu.utexas.cs345.jdblisp.*;
public class Parser {
private static Symbol QUOTE_SYMB = new Symbol("QUOTE");
}
PARSER_END(Parser)
@ -28,12 +29,14 @@ TOKEN : /* PUNCTUATION */
{ < LPAREN: "(" >
| < RPAREN: ")" >
| < NIL: (["N","n"]["I","i"]["L","l"])>
| < QUOTE: "'" >
| < KEYWORD: ":" >
}
TOKEN : /* LITERALS & SYMBOLS */
{ < NUMB: (["+", "-"])? (["0"-"9"])+ ("." (["0"-"9"])+ )? >
| < STRG: "\"" (["A"-"Z", "a"-"z", "_"])* "\"" >
| < STRG: "\"" (~["\""])* "\"" >
| < SYMB: (["A"-"Z", "a"-"z", "_", "+", "-", "*", "/", "="])+
(["A"-"Z", "a"-"z", "0"-"9",
"_", "+", "-", "*", "/", "="])? >
@ -45,9 +48,10 @@ TOKEN : /* LITERALS & SYMBOLS */
SExp sexp():
{ SExp s = null; Token t;
}
{ t = <SYMB> { return new Symbol(t.image.toUpperCase()); }
{ s = symbol() { return s; }
| t = <STRG> { return new Str(t.image); }
| t = <NUMB> { return new Num(t.image); }
| t = <QUOTE> s = sexp() { return new List(new Seq(QUOTE_SYMB, s)); }
| s = list() { return s; }
}
@ -68,6 +72,15 @@ List list():
{ Seq sq; SExp se;
}
{ [ se = sexp() sq = seq() { return new Seq(se, sq); } ]
{ return null; }
}
/**
* Symbol -> Symbol | Keyword Symbol
*/
Symbol symbol():
{ Token t;
}
{ t = <SYMB> { return new Symbol(t.image.toUpperCase()); }
| <KEYWORD> t = <SYMB> { return new Keyword(t.image.toUpperCase()); }
}

View File

@ -21,9 +21,9 @@ public interface SExp {
public String toString() { return "T"; }
};
/*public static final SExp NIL = new SExp() {
SExp eval(SymbolTable table) { return this; }
String display(String offset) { return offset + "NIL\n"; }
String toString() { return "NIL"; }
};*/
public static final SExp NIL = new SExp() {
public SExp eval(SymbolTable table) { return this; }
public String display(String offset) { return offset + "NIL\n"; }
public String toString() { return "NIL"; }
};
}

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,7 @@ package edu.utexas.cs345.jdblisp;
public class Symbol implements SExp {
public final String name;
public Symbol(String name) {
this.name = name;
}
public Symbol(String name) { this.name = name; }
/** {@inheritdoc}*/
public SExp eval(SymbolTable table) throws LispException {

View File

@ -42,6 +42,38 @@ public class SymbolTable {
return s;
}
public Symbol rebind(Symbol s, VariableEntry v) throws LispException {
// look up the variable in the current table
VariableEntry curVal = variables.get(s);
// not present
if (curVal == null) {
// no parent table, variable is undefine
if (enclosingTable == null)
throw new LispException("No such variable defined: " + s.name);
// check parent table
return enclosingTable.rebind(s, v);
}
// it is present
else {
// if this variable is constant, err
if (curVal.isConstant)
throw new LispException("Cannot set variable " + s.name
+ ": the variable is constant.");
// if not, set the new value
variables.put(s, v);
}
return s;
}
public FormEntry lookupFunction(Symbol s) throws LispException {
FormEntry fe = functions.get(s);

View File

@ -7,6 +7,19 @@ package edu.utexas.cs345.jdblisp;
public class VariableEntry {
public final SExp value;
public final boolean isConstant;
public final HelpTopic helpinfo;
public VariableEntry(SExp value) { this(value, false); }
public VariableEntry(SExp value, boolean constant) {
this(value, constant, null);
}
public VariableEntry(SExp value, boolean constant, HelpTopic helpinfo) {
this.value = value;
this.isConstant = constant;
this.helpinfo = helpinfo;
}
public VariableEntry(SExp value) { this.value = value; }
}

View File

@ -0,0 +1,4 @@
Special Forms:
--------------
LET

View File

@ -4,15 +4,18 @@ package edu.utexas.cs345.jdblisp.parser;
import edu.utexas.cs345.jdblisp.*;
public class Parser implements ParserConstants {
private static Symbol QUOTE_SYMB = new Symbol("QUOTE");
/**
* SExp -> Symbol | Str | Num | List | "'" SExp
*/
static final public SExp sexp() throws ParseException {
SExp s = null; Token t;
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case KEYWORD:
case SYMB:
t = jj_consume_token(SYMB);
{if (true) return new Symbol(t.image.toUpperCase());}
s = symbol();
{if (true) return s;}
break;
case STRG:
t = jj_consume_token(STRG);
@ -22,6 +25,11 @@ public class Parser implements ParserConstants {
t = jj_consume_token(NUMB);
{if (true) return new Num(t.image);}
break;
case QUOTE:
t = jj_consume_token(QUOTE);
s = sexp();
{if (true) return new List(new Seq(QUOTE_SYMB, s));}
break;
case LPAREN:
case NIL:
s = list();
@ -67,6 +75,8 @@ public class Parser implements ParserConstants {
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case LPAREN:
case NIL:
case QUOTE:
case KEYWORD:
case NUMB:
case STRG:
case SYMB:
@ -82,6 +92,29 @@ public class Parser implements ParserConstants {
throw new Error("Missing return statement in function");
}
/**
* Symbol -> Symbol | Keyword Symbol
*/
static final public Symbol symbol() throws ParseException {
Token t;
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case SYMB:
t = jj_consume_token(SYMB);
{if (true) return new Symbol(t.image.toUpperCase());}
break;
case KEYWORD:
jj_consume_token(KEYWORD);
t = jj_consume_token(SYMB);
{if (true) return new Keyword(t.image.toUpperCase());}
break;
default:
jj_la1[3] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
}
throw new Error("Missing return statement in function");
}
static private boolean jj_initialized_once = false;
/** Generated Token Manager. */
static public ParserTokenManager token_source;
@ -92,13 +125,13 @@ public class Parser implements ParserConstants {
static public Token jj_nt;
static private int jj_ntk;
static private int jj_gen;
static final private int[] jj_la1 = new int[3];
static final private int[] jj_la1 = new int[4];
static private int[] jj_la1_0;
static {
jj_la1_init_0();
}
private static void jj_la1_init_0() {
jj_la1_0 = new int[] {0x1e80,0x280,0x1e80,};
jj_la1_0 = new int[] {0x7e80,0x280,0x7e80,0x4800,};
}
/** Constructor with InputStream. */
@ -119,7 +152,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
/** Reinitialise. */
@ -133,7 +166,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
/** Constructor. */
@ -150,7 +183,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
/** Reinitialise. */
@ -160,7 +193,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
/** Constructor with generated Token Manager. */
@ -176,7 +209,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
/** Reinitialise. */
@ -185,7 +218,7 @@ public class Parser implements ParserConstants {
token = new Token();
jj_ntk = -1;
jj_gen = 0;
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
for (int i = 0; i < 4; i++) jj_la1[i] = -1;
}
static private Token jj_consume_token(int kind) throws ParseException {
@ -236,12 +269,12 @@ public class Parser implements ParserConstants {
/** Generate ParseException. */
static public ParseException generateParseException() {
jj_expentries.clear();
boolean[] la1tokens = new boolean[13];
boolean[] la1tokens = new boolean[15];
if (jj_kind >= 0) {
la1tokens[jj_kind] = true;
jj_kind = -1;
}
for (int i = 0; i < 3; i++) {
for (int i = 0; i < 4; i++) {
if (jj_la1[i] == jj_gen) {
for (int j = 0; j < 32; j++) {
if ((jj_la1_0[i] & (1<<j)) != 0) {
@ -250,7 +283,7 @@ public class Parser implements ParserConstants {
}
}
}
for (int i = 0; i < 13; i++) {
for (int i = 0; i < 15; i++) {
if (la1tokens[i]) {
jj_expentry = new int[1];
jj_expentry[0] = i;

View File

@ -17,11 +17,15 @@ public interface ParserConstants {
/** RegularExpression Id. */
int NIL = 9;
/** RegularExpression Id. */
int NUMB = 10;
int QUOTE = 10;
/** RegularExpression Id. */
int STRG = 11;
int KEYWORD = 11;
/** RegularExpression Id. */
int SYMB = 12;
int NUMB = 12;
/** RegularExpression Id. */
int STRG = 13;
/** RegularExpression Id. */
int SYMB = 14;
/** Lexical state. */
int DEFAULT = 0;
@ -38,6 +42,8 @@ public interface ParserConstants {
"\"(\"",
"\")\"",
"<NIL>",
"\"\\\'\"",
"\":\"",
"<NUMB>",
"<STRG>",
"<SYMB>",

View File

@ -35,10 +35,14 @@ static private int jjMoveStringLiteralDfa0_0()
case 10:
jjmatchedKind = 4;
return jjMoveStringLiteralDfa1_0(0x20L);
case 39:
return jjStopAtPos(0, 10);
case 40:
return jjStopAtPos(0, 7);
case 41:
return jjStopAtPos(0, 8);
case 58:
return jjStopAtPos(0, 11);
case 59:
return jjMoveStringLiteralDfa1_0(0x40L);
default :
@ -103,6 +107,9 @@ static private int jjMoveStringLiteralDfa3_0(long old0, long active0)
}
return jjStartNfa_0(2, active0);
}
static final long[] jjbitVec0 = {
0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
};
static private int jjMoveNfa_0(int startState, int curPos)
{
int startsAt = 0;
@ -124,18 +131,18 @@ static private int jjMoveNfa_0(int startState, int curPos)
case 0:
if ((0x3ff000000000000L & l) != 0L)
{
if (kind > 10)
kind = 10;
if (kind > 12)
kind = 12;
jjCheckNAddTwoStates(4, 5);
}
else if ((0x2000ac0000000000L & l) != 0L)
{
if (kind > 12)
kind = 12;
if (kind > 14)
kind = 14;
jjCheckNAddTwoStates(10, 11);
}
else if (curChar == 34)
jjAddStates(0, 1);
jjCheckNAddTwoStates(8, 9);
if ((0x280000000000L & l) != 0L)
jjCheckNAdd(4);
break;
@ -146,8 +153,8 @@ static private int jjMoveNfa_0(int startState, int curPos)
case 4:
if ((0x3ff000000000000L & l) == 0L)
break;
if (kind > 10)
kind = 10;
if (kind > 12)
kind = 12;
jjCheckNAddTwoStates(4, 5);
break;
case 5:
@ -157,28 +164,32 @@ static private int jjMoveNfa_0(int startState, int curPos)
case 6:
if ((0x3ff000000000000L & l) == 0L)
break;
if (kind > 10)
kind = 10;
if (kind > 12)
kind = 12;
jjCheckNAdd(6);
break;
case 7:
if (curChar == 34)
jjAddStates(0, 1);
jjCheckNAddTwoStates(8, 9);
break;
case 8:
if ((0xfffffffbffffffffL & l) != 0L)
jjCheckNAddTwoStates(8, 9);
break;
case 9:
if (curChar == 34 && kind > 11)
kind = 11;
if (curChar == 34 && kind > 13)
kind = 13;
break;
case 10:
if ((0x2000ac0000000000L & l) == 0L)
break;
if (kind > 12)
kind = 12;
if (kind > 14)
kind = 14;
jjCheckNAddTwoStates(10, 11);
break;
case 11:
if ((0x23ffac0000000000L & l) != 0L && kind > 12)
kind = 12;
if ((0x23ffac0000000000L & l) != 0L && kind > 14)
kind = 14;
break;
default : break;
}
@ -194,8 +205,8 @@ static private int jjMoveNfa_0(int startState, int curPos)
case 0:
if ((0x7fffffe87fffffeL & l) != 0L)
{
if (kind > 12)
kind = 12;
if (kind > 14)
kind = 14;
jjCheckNAddTwoStates(10, 11);
}
if ((0x400000004000L & l) != 0L)
@ -210,19 +221,18 @@ static private int jjMoveNfa_0(int startState, int curPos)
kind = 9;
break;
case 8:
if ((0x7fffffe87fffffeL & l) != 0L)
jjAddStates(0, 1);
break;
case 10:
if ((0x7fffffe87fffffeL & l) == 0L)
break;
if (kind > 12)
kind = 12;
if (kind > 14)
kind = 14;
jjCheckNAddTwoStates(10, 11);
break;
case 11:
if ((0x7fffffe87fffffeL & l) != 0L && kind > 12)
kind = 12;
if ((0x7fffffe87fffffeL & l) != 0L && kind > 14)
kind = 14;
break;
default : break;
}
@ -236,6 +246,10 @@ static private int jjMoveNfa_0(int startState, int curPos)
{
switch(jjstateSet[--i])
{
case 8:
if ((jjbitVec0[i2] & l2) != 0L)
jjAddStates(0, 1);
break;
default : break;
}
} while(i != startsAt);
@ -259,14 +273,15 @@ static final int[] jjnextStates = {
/** Token literal values. */
public static final String[] jjstrLiteralImages = {
"", null, null, null, null, null, null, "\50", "\51", null, null, null, null, };
"", null, null, null, null, null, null, "\50", "\51", null, "\47", "\72", null,
null, null, };
/** Lexer state names. */
public static final String[] lexStateNames = {
"DEFAULT",
};
static final long[] jjtoToken = {
0x1f81L,
0x7f81L,
};
static final long[] jjtoSkip = {
0x7eL,

View File

@ -0,0 +1,7 @@
(defun make-cd (title artist rating ripped)
(list title artist rating ripped))
(make-cd "Roses" "Kathy Mattea" 7 t)
(defvar *db* nil)

View File

@ -1,3 +1,30 @@
Implement FORMAT
Implement READ and PRINT
Implement IF
Outstanding
-----------
- Implement FORMAT
- Implement lambdas
- Implement LIST*
- Implement macros
- Implement packages
- Implement READ and PRINT
- Redefine DEFUN as a macro
Partially Done
--------------
P Implement keywords
Done
----
D Add ' notation for quote
D Define NIL
D Define T
D Implement DEFPARAMETER
D Implement DEFVAR
D Implement IF
D Implement LET
D Implement LET*
D Implement LIST
D Implement PROGN
D Implement QUOTE