Refactored code for eclipse
This commit is contained in:
parent
cee46a41b9
commit
b875727361
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="owner.project.facets" value="java"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="build/classes"/>
|
||||
</classpath>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="jar,"/>
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_CLEAN_TARGETS" value="clean,"/>
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="jar,"/>
|
||||
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ant.uiSET_INPUTHANDLER" value="false"/>
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${workspace}"/>
|
||||
<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="LispInterpreter"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/LispInterpreter/build.xml}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="incremental,auto,clean"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
</launchConfiguration>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>LispInterpreter</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faceted-project>
|
||||
<installed facet="java" version="1.8"/>
|
||||
</faceted-project>
|
Binary file not shown.
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter Phase 1 - Lexical Analysis
|
||||
*/
|
||||
|
||||
package error;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* <code>ErrorManager</code> is an error handling class for a Lisp interpreter.
|
||||
*/
|
||||
public class ErrorManager {
|
||||
|
||||
/**
|
||||
* The lowest "criticality" level of an error that will cause the currently
|
||||
* running program to terminate.
|
||||
*/
|
||||
public static final int CRITICAL_LEVEL = 3;
|
||||
|
||||
public static final String ANSI_RESET = "\u001B[0m";
|
||||
public static final String ANSI_RED = "\u001B[31m";
|
||||
public static final String ANSI_YELLOW = "\u001B[33m";
|
||||
public static final String ANSI_PURPLE = "\u001B[35m";
|
||||
|
||||
/**
|
||||
* Prints out the specified error message to the console and decides
|
||||
* whether or not to terminate the currently running program.
|
||||
*
|
||||
* @param message
|
||||
* the error message
|
||||
* @param level
|
||||
* the "criticality" level of the error
|
||||
* @postcondition
|
||||
* If <code>level >= CRITICAL_LEVEL</code> the currently running
|
||||
* program has been terminated.
|
||||
*/
|
||||
public static void generateError(String message, int level) {
|
||||
String color = (level >= CRITICAL_LEVEL) ? ANSI_PURPLE : ANSI_RED;
|
||||
String formattedMessage = MessageFormat.format("{0}error: {1}{2}", color, message, ANSI_RESET);
|
||||
|
||||
System.out.println(formattedMessage);
|
||||
|
||||
if (level >= CRITICAL_LEVEL) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<body>
|
||||
Provides a class for managing errors in the Lisp Interpreter.
|
||||
</body>
|
Binary file not shown.
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>APPLY</code> represents the APPLY function in Lisp.
|
||||
*/
|
||||
public class APPLY extends LispFunction {
|
||||
|
||||
/**
|
||||
* Call APPLY with the specified argument list.
|
||||
*
|
||||
* @param argList
|
||||
* the list of arguments to be sent to APPLY (MUST BE A PROPER LIST)
|
||||
* @return
|
||||
* the result of evaluating APPLY on <code>argList</code>
|
||||
*/
|
||||
public static SExpression apply(Cons argList) {
|
||||
return new APPLY().call(argList);
|
||||
}
|
||||
|
||||
// The number of arguments that APPLY takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to APPLY
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("APPLY"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to APPLY: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression car = argList.getCar(); // function name
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression cadr = cdr.getCar(); // argument list
|
||||
|
||||
// make sure the second argument is a list
|
||||
if (cadr.listp()) {
|
||||
LispFunction function = EVAL.lookupFunction(car.toString());
|
||||
|
||||
if (function == null) {
|
||||
// check if the car of the list is a lambda expression
|
||||
if (car.functionp()) {
|
||||
function = ((LambdaExpression) car).getFunction();
|
||||
} else if (LAMBDA.isLambdaExpression(car)) {
|
||||
Cons lexpr = (Cons) car;
|
||||
|
||||
function = LAMBDA.createFunction(lexpr);
|
||||
} else {
|
||||
throw new RuntimeException("undefined function " + car);
|
||||
}
|
||||
}
|
||||
|
||||
// apply the given function to the given argument list
|
||||
return function.call((Cons) cadr);
|
||||
}
|
||||
|
||||
// the second argument is not a list
|
||||
throw new RuntimeException("APPLY: " + cadr + " is not a list");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>ATOM</code> represents the ATOM function in Lisp.
|
||||
*/
|
||||
public class ATOM extends LispFunction {
|
||||
|
||||
// The number of arguments that ATOM takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to ATOM
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("ATOM"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to ATOM: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
return (arg.atomp() ? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>CAR</code> represents the CAR function in Lisp.
|
||||
*/
|
||||
public class CAR extends LispFunction {
|
||||
|
||||
// The number of arguments that CAR takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to CAR
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("CAR"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to CAR: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
|
||||
// make sure that the argument is a list
|
||||
if (argCar.listp()) {
|
||||
Cons arg = (Cons) argCar;
|
||||
|
||||
return arg.getCar();
|
||||
}
|
||||
|
||||
// the argument is not a list
|
||||
throw new RuntimeException("CAR: " + argCar + " is not a list");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>CDR</code> represents the CDR function in Lisp.
|
||||
*/
|
||||
public class CDR extends LispFunction {
|
||||
|
||||
// The number of arguments that CDR takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to CDR
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("CDR"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to CDR: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
|
||||
// make sure that the argument is a list
|
||||
if (argCar.listp()) {
|
||||
Cons arg = (Cons) argCar;
|
||||
|
||||
return arg.getCdr();
|
||||
}
|
||||
|
||||
// the argument is not a list
|
||||
throw new RuntimeException("CDR: " + argCar + " is not a list");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>COND</code> represents the COND form in Lisp.
|
||||
*/
|
||||
public class COND extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
if (argList.nullp()) {
|
||||
// return NIL if there are were no arguments passed to COND
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar(); // first clause
|
||||
Cons argCdr = (Cons) argList.getCdr(); // list of remaining clauses
|
||||
|
||||
// make sure the first clause is a list and is not NIL
|
||||
if (argCar.consp()) {
|
||||
Cons clause = (Cons) argCar;
|
||||
SExpression test = EVAL.eval(clause.getCar());
|
||||
|
||||
if (test != Nil.getUniqueInstance()) {
|
||||
// the car of this clause is true, so we evaluate its cdr
|
||||
|
||||
SExpression cdr = clause.getCdr();
|
||||
SExpression retval = test;
|
||||
|
||||
// evaluate all the S-expressions in the cdr of the clause
|
||||
while (cdr.consp()) {
|
||||
retval = EVAL.eval(((Cons) cdr).getCar());
|
||||
cdr = ((Cons) cdr).getCdr();
|
||||
}
|
||||
|
||||
// return the value of the last S-expression evaluated
|
||||
return retval;
|
||||
}
|
||||
|
||||
// the car of this clause is false, so we test any remaining
|
||||
// clauses
|
||||
|
||||
// check if the list of remaining clauses is a list and is not NIL
|
||||
if (argCdr.consp()) {
|
||||
return call(argCdr);
|
||||
}
|
||||
|
||||
// there are no remaining clauses, so we return NIL
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
throw new RuntimeException("COND: clause " + argCar +
|
||||
" should be a list");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>CONS</code> represents the CONS function in Lisp.
|
||||
*/
|
||||
public class CONS extends LispFunction {
|
||||
|
||||
// The number of arguments that CONS takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
|
||||
public Cons call(Cons argList) {
|
||||
// retrieve the number of arguments passed to CONS
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("CONS"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to CONS: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
// the car of the CONS cell we are going to create
|
||||
SExpression argOne = argList.getCar();
|
||||
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
|
||||
// the cdr of the CONS cell we are going to create
|
||||
SExpression argTwo = cdr.getCar();
|
||||
|
||||
return new Cons(argOne, argTwo);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* <code>DEFUN</code> represents the DEFUN form in Lisp.
|
||||
*/
|
||||
public class DEFUN extends LispFunction {
|
||||
|
||||
// The minimum number of arguments that DEFUN takes.
|
||||
private static final int MIN_ARGS = 3;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to DEFUN
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength < MIN_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("DEFUN"), argList);
|
||||
String errMsg = "too few arguments given to DEFUN: " +
|
||||
originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression name = argList.getCar(); // name of the function
|
||||
|
||||
// make sure the function name is a symbol
|
||||
if (! name.symbolp()) {
|
||||
throw new RuntimeException("DEFUN: " + name + " is not a symbol");
|
||||
}
|
||||
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression cadr = cdr.getCar();
|
||||
|
||||
// make sure the list of arguments (lambda list) is a proper list
|
||||
if (! cadr.listp()) {
|
||||
throw new RuntimeException("DEFUN: " + cadr + " is not a list");
|
||||
} else if (EVAL.isDotted((Cons) cadr)) {
|
||||
throw new RuntimeException("DEFUN: " + cadr +
|
||||
" is not a proper list");
|
||||
}
|
||||
|
||||
Cons lambdaList = (Cons) cadr; // lambda list of the function
|
||||
|
||||
// list of S-expressions making up the body of the function
|
||||
Cons body = (Cons) cdr.getCdr();
|
||||
|
||||
HashMap<String, LispFunction> functionTable = EVAL.getFunctionTable();
|
||||
|
||||
// give a warning if this function has already been defined
|
||||
if (functionTable.containsKey(name.toString())) {
|
||||
System.out.println("WARNING: redefining function " +
|
||||
name.toString());
|
||||
}
|
||||
|
||||
// place the function in the function table
|
||||
functionTable.put(name.toString(),
|
||||
new UDFunction(name.toString(), lambdaList, body));
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>DIVIDE</code> represents the '/' function in Lisp.
|
||||
*/
|
||||
public class DIVIDE extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("/"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to /: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression argFirst = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
// make sure that the first argument is a number
|
||||
if (argFirst.numberp()) {
|
||||
LispNumber num1 = (LispNumber) argFirst;
|
||||
|
||||
if (argRest.nullp()) {
|
||||
// there is only one argument, so return the multiplicative
|
||||
// inverse of the number
|
||||
return new LispNumber(1 / num1.getValue());
|
||||
}
|
||||
|
||||
SExpression argSecond = argRest.getCar();
|
||||
|
||||
// make sure that the next argument is a number as well
|
||||
if (argSecond.numberp()) {
|
||||
LispNumber num2 = (LispNumber) argSecond;
|
||||
LispNumber quotient = new LispNumber(num1.getValue() /
|
||||
num2.getValue());
|
||||
SExpression argCddr = argRest.getCdr();
|
||||
|
||||
if (argCddr.consp()) {
|
||||
return call(new Cons(quotient, argCddr));
|
||||
}
|
||||
|
||||
return quotient;
|
||||
}
|
||||
|
||||
throw new RuntimeException("/: " + argSecond + " is not a number");
|
||||
}
|
||||
|
||||
throw new RuntimeException("/: " + argFirst + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>EQ</code> represents the EQ function in Lisp.
|
||||
*/
|
||||
public class EQ extends LispFunction {
|
||||
|
||||
// The number of arguments that EQ takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EQ
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EQ"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to EQ: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression argOne = argList.getCar(); // first argument
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression argTwo = cdr.getCar(); // second argumnet
|
||||
|
||||
if (argOne.atomp() && argTwo.atomp()) {
|
||||
return ((argOne.toString().equals(argTwo.toString()))
|
||||
? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
return ((argOne == argTwo) ? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>EQUAL</code> represents the EQUAL function in Lisp.
|
||||
*/
|
||||
public class EQUAL extends LispFunction {
|
||||
|
||||
// The number of arguments that EQUAL takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EQUAL
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EQUAL"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to EQUAL: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression argOne = argList.getCar(); // first argument
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression argTwo = cdr.getCar(); // second argumnet
|
||||
|
||||
if (argOne.consp() && argTwo.consp()) {
|
||||
Cons listOne = (Cons) argOne;
|
||||
Cons listTwo = (Cons) argTwo;
|
||||
SExpression listOneCar = listOne.getCar();
|
||||
SExpression listTwoCar = listTwo.getCar();
|
||||
SExpression listOneCdr = listOne.getCdr();
|
||||
SExpression listTwoCdr = listTwo.getCdr();
|
||||
|
||||
SExpression carEqual =
|
||||
call(new Cons(listOneCar, LIST.makeList(listTwoCar)));
|
||||
SExpression cdrEqual =
|
||||
call(new Cons(listOneCdr, LIST.makeList(listTwoCdr)));
|
||||
|
||||
return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T))
|
||||
? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
return ((argOne.toString().equals(argTwo.toString()))
|
||||
? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>EQUALSP</code> represents the '=' function in Lisp.
|
||||
*/
|
||||
public class EQUALSP extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("="), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to =: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression firstArg = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
// make sure that the first argument is a number
|
||||
if (firstArg.numberp()) {
|
||||
LispNumber num1 = (LispNumber) firstArg;
|
||||
|
||||
if (argRest.nullp()) {
|
||||
return Symbol.T;
|
||||
}
|
||||
|
||||
SExpression secondArg = argRest.getCar();
|
||||
|
||||
// make sure that the second argument is a number as well
|
||||
if (secondArg.numberp()) {
|
||||
LispNumber num2 = (LispNumber) secondArg;
|
||||
|
||||
if (num1.getValue() == num2.getValue()) {
|
||||
return call(argRest);
|
||||
}
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
throw new RuntimeException("=: " + secondArg + " is not a number");
|
||||
}
|
||||
|
||||
throw new RuntimeException("=: " + firstArg + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* <code>EVAL</code> represents the EVAL function in Lisp.
|
||||
*/
|
||||
public class EVAL extends LispFunction {
|
||||
|
||||
// A table to contain all the built-in and user-defined Lisp functions.
|
||||
private static HashMap<String, LispFunction> functionTable =
|
||||
new HashMap<String, LispFunction>();
|
||||
|
||||
static {
|
||||
// place all of the built-in functions into the function table
|
||||
functionTable.put("*", new MULTIPLY());
|
||||
functionTable.put("+", new PLUS());
|
||||
functionTable.put("-", new MINUS());
|
||||
functionTable.put("/", new DIVIDE());
|
||||
functionTable.put("<", new LESSP());
|
||||
functionTable.put("=", new EQUALSP());
|
||||
functionTable.put(">", new GREATERP());
|
||||
functionTable.put("APPLY", new APPLY());
|
||||
functionTable.put("ATOM", new ATOM());
|
||||
functionTable.put("CAR", new CAR());
|
||||
functionTable.put("CDR", new CDR());
|
||||
functionTable.put("COND", new COND());
|
||||
functionTable.put("CONS", new CONS());
|
||||
functionTable.put("DEFUN", new DEFUN());
|
||||
functionTable.put("EQ", new EQ());
|
||||
functionTable.put("EQUAL", new EQUAL());
|
||||
functionTable.put("EVAL", new EVAL());
|
||||
functionTable.put("EXIT", new EXIT());
|
||||
functionTable.put("FIRST", new CAR());
|
||||
functionTable.put("FUNCALL", new FUNCALL());
|
||||
functionTable.put("GREATERP", new GREATERP());
|
||||
functionTable.put("LAMBDA", new LAMBDA());
|
||||
functionTable.put("LENGTH", new LENGTH());
|
||||
functionTable.put("LET", new LET());
|
||||
functionTable.put("LIST", new LIST());
|
||||
functionTable.put("LISTP", new LISTP());
|
||||
functionTable.put("LOAD", new LOAD());
|
||||
functionTable.put("NULL", new NULL());
|
||||
functionTable.put("PRINT", new PRINT());
|
||||
functionTable.put("QUOTE", new QUOTE());
|
||||
functionTable.put("REST", new CDR());
|
||||
functionTable.put("SETF", new SETF());
|
||||
functionTable.put("SYMBOL-FUNCTION", new SYMBOL_FUNCTION());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the function table.
|
||||
*
|
||||
* @return
|
||||
* the function table
|
||||
*/
|
||||
public static HashMap<String, LispFunction> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a function by its name.
|
||||
*
|
||||
* @param functionName
|
||||
* the name of the function to look up
|
||||
* @return
|
||||
* the function with the name <code>functionName</code> if it exists; null
|
||||
* otherwise
|
||||
*/
|
||||
public static LispFunction lookupFunction(String functionName) {
|
||||
return functionTable.get(functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a symbol's value using its name.
|
||||
*
|
||||
* @param symbolName
|
||||
* the name of the symbol to look up (must not be null)
|
||||
* @return
|
||||
* the value of <code>symbolName</code> if it has one; null otherwise
|
||||
*/
|
||||
public static SExpression lookupSymbol(String symbolName) {
|
||||
if (symbolName.equals("NIL")) {
|
||||
return Nil.getUniqueInstance();
|
||||
} else if (symbolName.equals("T")) {
|
||||
return Symbol.T;
|
||||
} else if (symbolName.startsWith(":")) {
|
||||
return new Symbol(symbolName);
|
||||
}
|
||||
|
||||
return SETF.lookup(symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given list is dotted.
|
||||
*
|
||||
* @param list
|
||||
* the list to be tested (must not be null)
|
||||
* @return
|
||||
* <code>true</code> if <code>list</code> is dotted; <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
public static boolean isDotted(Cons list) {
|
||||
if (list.nullp()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SExpression cdr = list.getCdr();
|
||||
|
||||
if (cdr.listp()) {
|
||||
return isDotted((Cons) cdr);
|
||||
}
|
||||
|
||||
// the cdr of 'list' is not a list, therefore it is dotted
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the given S-expression.
|
||||
*
|
||||
* @param sexpr
|
||||
* the S-expression to evaluate
|
||||
* @return
|
||||
* the value of <code>sexpr</code>
|
||||
*/
|
||||
public static SExpression eval(SExpression sexpr) {
|
||||
Cons expList = LIST.makeList(sexpr);
|
||||
EVAL evalFunction = new EVAL();
|
||||
|
||||
return evalFunction.call(expList);
|
||||
}
|
||||
|
||||
// The number of arguments that EVAL takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EVAL
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EVAL"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to EVAL: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
if (arg.listp()) {
|
||||
if (arg.consp()) {
|
||||
return evaluateList((Cons) arg);
|
||||
}
|
||||
|
||||
return arg; // 'arg' is NIL
|
||||
}
|
||||
|
||||
if (arg.symbolp()) {
|
||||
SExpression symbolValue = lookupSymbol(arg.toString());
|
||||
|
||||
if (symbolValue != null) {
|
||||
return symbolValue;
|
||||
}
|
||||
|
||||
throw new RuntimeException("variable " + arg + " has no value");
|
||||
}
|
||||
|
||||
return arg; // 'arg' is a NUMBER or a STRING
|
||||
}
|
||||
|
||||
// Evaluate the specified list.
|
||||
//
|
||||
// Parameters: list - the list to evaluate
|
||||
// Returns: the value of 'list'
|
||||
// Precondition: 'list' must not be null.
|
||||
private SExpression evaluateList(Cons list) {
|
||||
SExpression car = list.getCar();
|
||||
SExpression cdr = list.getCdr();
|
||||
|
||||
LispFunction function = lookupFunction(car.toString());
|
||||
|
||||
if (function == null) {
|
||||
// check if the car of the list is a lambda expression
|
||||
if (car.functionp()) {
|
||||
function = ((LambdaExpression) car).getFunction();
|
||||
} else if (LAMBDA.isLambdaExpression(car)) {
|
||||
Cons lexpr = (Cons) car;
|
||||
|
||||
function = LAMBDA.createFunction(lexpr);
|
||||
} else {
|
||||
throw new RuntimeException("undefined function " + car);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the list of arguments for 'function' is a list
|
||||
if (cdr.listp()) {
|
||||
Cons args = (Cons) cdr;
|
||||
|
||||
// make sure the list of arguments is not dotted
|
||||
if (isDotted(args)) {
|
||||
throw new RuntimeException("argument list given to " + car +
|
||||
" is dotted: " + list);
|
||||
}
|
||||
|
||||
// determine if we should evaluate the arguments that will be
|
||||
// passed to 'function'
|
||||
if (function.evaluateArguments()) {
|
||||
args = evaluateArgList(args);
|
||||
}
|
||||
|
||||
return function.call(args);
|
||||
}
|
||||
|
||||
// the list of arguments is not a list!
|
||||
throw new RuntimeException("argument list given to " + car +
|
||||
" is dotted: " + list);
|
||||
}
|
||||
|
||||
// Evaluate a list of arguments for a function.
|
||||
//
|
||||
// Parameters: arguments - a list of arguments for a function
|
||||
// Returns: a list consisting of the values of the S-expressions found in
|
||||
// 'arguments'
|
||||
// Precondition: 'arguments' must not be null.
|
||||
private Cons evaluateArgList(Cons arguments) {
|
||||
if (arguments.nullp()) {
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
SExpression car = eval(arguments.getCar());
|
||||
SExpression cdr = arguments.getCdr();
|
||||
|
||||
if (cdr.listp()) {
|
||||
return new Cons(car, evaluateArgList((Cons) cdr));
|
||||
}
|
||||
|
||||
// remove any parameters found after a dot (put here in case the check
|
||||
// for a dotted parameter list is not done prior to this call)
|
||||
return new Cons(car, Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
public class EXIT extends LispFunction {
|
||||
|
||||
// The number of arguments that EXIT takes.
|
||||
private static final int NUM_ARGS = 0;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to EXIT
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength > NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("EXIT"), argList);
|
||||
String errMsg = "too many arguments given to EXIT: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>FUNCALL</code> represents the FUNCALL function in Lisp.
|
||||
*/
|
||||
public class FUNCALL extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("FUNCALL"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to FUNCALL: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression cdr = argList.getCdr();
|
||||
Cons applyArgs = new Cons(argList.getCar(), LIST.makeList(cdr));
|
||||
|
||||
return APPLY.apply(applyArgs);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>GREATERP</code> represents the '>' function in Lisp.
|
||||
*/
|
||||
public class GREATERP extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol(">"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to >: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression firstArg = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
// make sure that the first argument is a number
|
||||
if (firstArg.numberp()) {
|
||||
LispNumber num1 = (LispNumber) firstArg;
|
||||
|
||||
if (argRest.nullp()) {
|
||||
return Symbol.T;
|
||||
}
|
||||
|
||||
SExpression secondArg = argRest.getCar();
|
||||
|
||||
// make sure that the second argument is a number as well
|
||||
if (secondArg.numberp()) {
|
||||
LispNumber num2 = (LispNumber) secondArg;
|
||||
|
||||
if (num1.getValue() > num2.getValue()) {
|
||||
return call(argRest);
|
||||
}
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
throw new RuntimeException(">: " + secondArg + " is not a number");
|
||||
}
|
||||
|
||||
throw new RuntimeException(">: " + firstArg + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LAMBDA</code> represents the LAMBDA form in Lisp.
|
||||
*/
|
||||
public class LAMBDA extends LispFunction {
|
||||
|
||||
/**
|
||||
* Determine if the given S-expression is a lambda expression.
|
||||
*
|
||||
* @param sexpr
|
||||
* the S-expression to test (must not be null)
|
||||
* @return
|
||||
* <code>true</code> if <code>sexpr</code> is a valid lambda expression;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public static boolean isLambdaExpression(SExpression sexpr) {
|
||||
if (sexpr.consp()) {
|
||||
SExpression first = ((Cons) sexpr).getCar();
|
||||
|
||||
return "LAMBDA".equals(first.toString());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an internal representation of a user-defined function from the
|
||||
* specified lambda expression.
|
||||
*
|
||||
* @param lexpr
|
||||
* the lambda expression to create the function from (must not be null)
|
||||
* @return
|
||||
* an internal representation of a user-defined function created from
|
||||
* <code>lexpr</code>
|
||||
* @throws RuntimeException
|
||||
* Indicates that <code>lexpr</code> is not a valid lambda expression.
|
||||
*/
|
||||
public static UDFunction createFunction(Cons lexpr) {
|
||||
LAMBDA lambda = new LAMBDA();
|
||||
SExpression cdr = lexpr.getCdr();
|
||||
|
||||
// make sure lexpr is a proper list
|
||||
if (! cdr.consp()) {
|
||||
throw new RuntimeException("invalid lambda expression");
|
||||
} else if (EVAL.isDotted((Cons) cdr)) {
|
||||
throw new RuntimeException("dotted lambda expression " + lexpr);
|
||||
}
|
||||
|
||||
Cons rest = (Cons) cdr;
|
||||
|
||||
return lambda.call(rest).getFunction();
|
||||
}
|
||||
|
||||
// The minimum number of arguments that LAMBDA takes.
|
||||
private static final int MIN_ARGS = 2;
|
||||
|
||||
public LambdaExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to LAMBDA
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength < MIN_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("LAMBDA"), argList);
|
||||
String errMsg = "too few arguments given to LAMBDA: " +
|
||||
originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression car = argList.getCar();
|
||||
|
||||
// make sure the list of arguments is a proper list
|
||||
if (! car.listp()) {
|
||||
throw new RuntimeException("LAMBDA: " + car + " is not a list");
|
||||
} else if (EVAL.isDotted((Cons) car)) {
|
||||
throw new RuntimeException("LAMBDA: " + car +
|
||||
" must be a proper list");
|
||||
}
|
||||
|
||||
Cons lambdaList = (Cons) car;
|
||||
Cons body = (Cons) argList.getCdr();
|
||||
Cons lexpr = new Cons(new Symbol("LAMBDA"), argList);
|
||||
UDFunction function = new UDFunction(":LAMBDA", lambdaList, body);
|
||||
|
||||
return new LambdaExpression(lexpr, function);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LENGTH</code> represents the LENGTH function in Lisp.
|
||||
*/
|
||||
public class LENGTH extends LispFunction {
|
||||
|
||||
/**
|
||||
* Returns the length of the given list.
|
||||
*
|
||||
* @param list
|
||||
* the list to determine the length of
|
||||
* @return
|
||||
* the length of <code>list</code>
|
||||
*/
|
||||
public static int getLength(Cons list) {
|
||||
LENGTH lengthFunction = new LENGTH();
|
||||
LispNumber length = lengthFunction.call(LIST.makeList(list));
|
||||
|
||||
return length.getValue();
|
||||
}
|
||||
|
||||
public LispNumber call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("LENGTH"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to LENGTH: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
SExpression argCdr = argList.getCdr();
|
||||
|
||||
// make sure we have received only one argument
|
||||
if (! argCdr.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("LENGTH"), argList);
|
||||
|
||||
throw new RuntimeException("too many arguments given to LENGTH: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
// make sure that the argument is a list
|
||||
if (argCar.listp()) {
|
||||
Cons arg = (Cons) argCar;
|
||||
|
||||
if (arg.nullp()) {
|
||||
return new LispNumber(0);
|
||||
}
|
||||
|
||||
Cons cdr = LIST.makeList(arg.getCdr());
|
||||
LispNumber cdrLength = call(cdr);
|
||||
|
||||
return new LispNumber(1 + cdrLength.getValue());
|
||||
}
|
||||
|
||||
throw new RuntimeException("LENGTH: a proper list must not end with " +
|
||||
argCar);
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LESSP</code> represents the '<' function in Lisp.
|
||||
*/
|
||||
public class LESSP extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("<"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to <: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression firstArg = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
// make sure that the first argument is a number
|
||||
if (firstArg.numberp()) {
|
||||
LispNumber num1 = (LispNumber) firstArg;
|
||||
|
||||
if (argRest.nullp()) {
|
||||
return Symbol.T;
|
||||
}
|
||||
|
||||
SExpression secondArg = argRest.getCar();
|
||||
|
||||
// make sure that the second argument is a number as well
|
||||
if (secondArg.numberp()) {
|
||||
LispNumber num2 = (LispNumber) secondArg;
|
||||
|
||||
if (num1.getValue() < num2.getValue()) {
|
||||
return call(argRest);
|
||||
}
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
throw new RuntimeException("<: " + secondArg + " is not a number");
|
||||
}
|
||||
|
||||
throw new RuntimeException("<: " + firstArg + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LET</code> represents the LET form in Lisp.
|
||||
*/
|
||||
public class LET extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
throw new RuntimeException("too few arguments given to LET");
|
||||
}
|
||||
|
||||
// create a new symbol table on top of the current environment to add
|
||||
// all the local variables to
|
||||
SymbolTable environment = new SymbolTable(SETF.getEnvironment());
|
||||
|
||||
SExpression car = argList.getCar();
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
|
||||
addVariablesToTable(environment, car);
|
||||
SETF.setEnvironment(environment);
|
||||
|
||||
SExpression retval = Nil.getUniqueInstance();
|
||||
|
||||
// evaluate all S-expression in the body
|
||||
while (cdr.consp()) {
|
||||
retval = EVAL.eval(cdr.getCar());
|
||||
cdr = (Cons) cdr.getCdr();
|
||||
}
|
||||
|
||||
// restore the environment to its original value
|
||||
SETF.setEnvironment(environment.getParent());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Add a list of variables and their values to the specified symbol table.
|
||||
//
|
||||
// Parameters: environment - the symbol table to add the variables and
|
||||
// their values to (must not be null)
|
||||
// vars - a list of variable/value pairs (must be either a
|
||||
// proper list of pairs or NIL)
|
||||
// Throws: RuntimeException - Indicates that 'vars' is not a proper list or
|
||||
// that it contains an member that is not a
|
||||
// variable/value pair.
|
||||
// Precondition: 'environment' and 'vars' must not be null.
|
||||
// Postcondition: All of the variables in 'vars' have been placed into
|
||||
// 'environment' with their values.
|
||||
private void addVariablesToTable(SymbolTable environment,
|
||||
SExpression vars) {
|
||||
// makes sure the list of variable/value pairs is a list
|
||||
if (! vars.listp()) {
|
||||
throw new RuntimeException("LET: " + vars +
|
||||
" is not a properly formatted" +
|
||||
" variable/value pair list");
|
||||
}
|
||||
|
||||
// add all variables in 'vars' to 'environment'
|
||||
while (vars.consp()) {
|
||||
Cons varList = (Cons) vars;
|
||||
SExpression varListCar = varList.getCar();
|
||||
|
||||
// make sure this variable/value pair is a list
|
||||
if (! varListCar.consp()) {
|
||||
throw new RuntimeException("LET: " + varListCar +
|
||||
" is not a properly formatted" +
|
||||
" variable/value pair");
|
||||
}
|
||||
|
||||
Cons varSpec = (Cons) varListCar;
|
||||
SExpression symbol = varSpec.getCar();
|
||||
SExpression varSpecCdr = varSpec.getCdr();
|
||||
|
||||
// make sure this variable pair has a value associated with it
|
||||
if (! varSpecCdr.consp()) {
|
||||
throw new RuntimeException("LET: illegal variable " +
|
||||
"specification " + varSpec);
|
||||
}
|
||||
|
||||
Cons varValue = (Cons) varSpecCdr;
|
||||
SExpression value = varValue.getCar();
|
||||
|
||||
// make sure there are no more members of this variable/value pair
|
||||
// and that 'symbol' is actually a symbol
|
||||
if ((! varValue.getCdr().nullp()) || (! symbol.symbolp())) {
|
||||
throw new RuntimeException("LET: illegal variable " +
|
||||
"specification " + varSpec);
|
||||
}
|
||||
|
||||
environment.put(symbol.toString(), value);
|
||||
|
||||
vars = varList.getCdr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LIST</code> represents the LIST function in Lisp.
|
||||
*/
|
||||
public class LIST extends LispFunction {
|
||||
|
||||
/**
|
||||
* Places the given S-expression into a list.
|
||||
*
|
||||
* @param sexpr
|
||||
* the S-expression to be placed into a list
|
||||
* @return
|
||||
* a list with <code>sexpr</code> as the car and NIL as the cdr.
|
||||
*/
|
||||
public static Cons makeList(SExpression sexpr) {
|
||||
return new Cons(sexpr, Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
public Cons call(Cons argList) {
|
||||
if (argList.nullp()) {
|
||||
// return NIL if there were no arguments passed to LIST
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
Cons argCdr = (Cons) argList.getCdr();
|
||||
|
||||
return new Cons(argCar, call(argCdr));
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>LISTP</code> represents the LISTP function in Lisp.
|
||||
*/
|
||||
public class LISTP extends LispFunction {
|
||||
|
||||
// The number of arguments that LISTP takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to LISTP
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("LISTP"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to LISTP: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
return (arg.listp() ? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <code>LOAD</code> represents the LOAD function in Lisp.
|
||||
*/
|
||||
public class LOAD extends LispFunction {
|
||||
// The number of arguments that LOAD takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to LOAD
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("LOAD"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to LOAD: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
|
||||
// make sure the argument is a string
|
||||
if (! argCar.stringp()) {
|
||||
throw new RuntimeException("LOAD: " + argCar + " is not a string");
|
||||
}
|
||||
|
||||
LispString quotedName = (LispString) argCar;
|
||||
String fileName = quotedName.toString();
|
||||
|
||||
// remove the surrounding quotes from the file name
|
||||
fileName = fileName.substring(1, (fileName.length() - 1));
|
||||
|
||||
return processFile(fileName);
|
||||
}
|
||||
|
||||
// Evaluate all the S-expressions found in the file with the specified
|
||||
// name.
|
||||
//
|
||||
// Parameters: fileName - the name of the file to be evaluated
|
||||
// Returns: 'T' if the file was processed successfully; 'NIL' otherwise
|
||||
private SExpression processFile(String fileName) {
|
||||
LispParser parser = null;
|
||||
|
||||
// attempt to create a new 'LispParser' on the specified file
|
||||
try {
|
||||
parser = new LispParser(new FileInputStream(fileName), fileName);
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("LOAD: could not open " + fileName);
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
// attempt to evaluate all the S-expressions contained in the file
|
||||
while (! parser.eof()) {
|
||||
try {
|
||||
SExpression sexpr = parser.getSExpr();
|
||||
|
||||
EVAL.eval(sexpr);
|
||||
} catch (RuntimeException e) {
|
||||
System.out.println("LOAD: " + e.getMessage());
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
} catch (IOException e) {
|
||||
System.out.println("LOAD: " + e.getMessage());
|
||||
|
||||
return Nil.getUniqueInstance();
|
||||
}
|
||||
}
|
||||
|
||||
// success!
|
||||
return Symbol.T;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* This class represents a Lisp FUNCTION in the PL-Lisp implementation.
|
||||
*/
|
||||
public class LambdaExpression extends SExpression {
|
||||
|
||||
private Cons lexpr;
|
||||
private UDFunction function;
|
||||
|
||||
/**
|
||||
* Create a new FUNCTION with the specified lambda expression and
|
||||
* internal representation.
|
||||
*
|
||||
* @param lexpr
|
||||
* the lambda expression of this FUNCTION
|
||||
* @param function
|
||||
* the internal representation of this FUNCTION
|
||||
*/
|
||||
public LambdaExpression(Cons lexpr, UDFunction function) {
|
||||
this.lexpr = lexpr;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a FUNCTION.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean functionp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the lambda expression of this FUNCTION.
|
||||
*
|
||||
* @return
|
||||
* the lambda expression of this FUNCTION
|
||||
*/
|
||||
public Cons getLExpression() {
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the internal representation of this FUNCTION.
|
||||
*
|
||||
* @return
|
||||
* the user-defined function of this FUNCTION
|
||||
*/
|
||||
public UDFunction getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this FUNCTION.
|
||||
*
|
||||
* @return
|
||||
* a string representation of this FUNCTION
|
||||
*/
|
||||
public String toString() {
|
||||
return lexpr.toString();
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* A <code>LispFunction</code> is an internal representation of a built-in
|
||||
* function in the Lisp programming language.
|
||||
*/
|
||||
public abstract class LispFunction {
|
||||
|
||||
/**
|
||||
* Call this Lisp function with the given list of arguments.
|
||||
*
|
||||
* @param argList
|
||||
* the list of arguments to pass to this function (MUST BE A PROPER LIST)
|
||||
* @return
|
||||
* the resulting S-expression of calling this function with the specified
|
||||
* arguments
|
||||
* @throws RuntimeException
|
||||
* Indicates that an incorrect number of arguments has been passed to this
|
||||
* function or that one of the arguments is not of the expected type.
|
||||
*/
|
||||
public abstract SExpression call(Cons argList);
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated. A subclass should override this method to return
|
||||
* <code>false</code> if it does not want its arguments to be evaluated
|
||||
* prior to being passed.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>MINUS</code> represents the '-' function in Lisp.
|
||||
*/
|
||||
public class MINUS extends LispFunction {
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// make sure we have received at least one argument
|
||||
if (argList.nullp()) {
|
||||
Cons originalSExpr = new Cons(new Symbol("-"), argList);
|
||||
|
||||
throw new RuntimeException("too few arguments given to -: " +
|
||||
originalSExpr);
|
||||
}
|
||||
|
||||
SExpression argFirst = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
// make sure that the first argument is a number
|
||||
if (argFirst.numberp()) {
|
||||
LispNumber num1 = (LispNumber) argFirst;
|
||||
|
||||
if (argRest.nullp()) {
|
||||
// there is only one argument, so return the additive
|
||||
// inverse of the number
|
||||
return new LispNumber(- num1.getValue());
|
||||
}
|
||||
|
||||
SExpression argSecond = argRest.getCar();
|
||||
|
||||
// make sure that the next argument is a number as well
|
||||
if (argSecond.numberp()) {
|
||||
LispNumber num2 = (LispNumber) argSecond;
|
||||
LispNumber difference = new LispNumber(num1.getValue() -
|
||||
num2.getValue());
|
||||
SExpression argCddr = argRest.getCdr();
|
||||
|
||||
if (argCddr.consp()) {
|
||||
return call(new Cons(difference, argCddr));
|
||||
}
|
||||
|
||||
return difference;
|
||||
}
|
||||
|
||||
throw new RuntimeException("-: " + argSecond + " is not a number");
|
||||
}
|
||||
|
||||
throw new RuntimeException("-: " + argFirst + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>MULTIPLY</code> represents the '*' function in Lisp.
|
||||
*/
|
||||
public class MULTIPLY extends LispFunction {
|
||||
|
||||
public LispNumber call(Cons argList) {
|
||||
if (argList.nullp()) {
|
||||
return new LispNumber(1);
|
||||
}
|
||||
|
||||
SExpression argFirst = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
if (argFirst.numberp()) {
|
||||
LispNumber num1 = (LispNumber) argFirst;
|
||||
LispNumber num2 = call(argRest);
|
||||
|
||||
return new LispNumber(num1.getValue() * num2.getValue());
|
||||
}
|
||||
|
||||
throw new RuntimeException("*: " + argFirst + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>NULL</code> represents the NULL function in Lisp.
|
||||
*/
|
||||
public class NULL extends LispFunction {
|
||||
|
||||
// The number of arguments that NULL takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to NULL
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("NULL"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to NULL: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
return (arg.nullp() ? Symbol.T : Nil.getUniqueInstance());
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>PLUS</code> represents the '+' function in Lisp.
|
||||
*/
|
||||
public class PLUS extends LispFunction {
|
||||
|
||||
public LispNumber call(Cons argList) {
|
||||
if (argList.nullp()) {
|
||||
return new LispNumber(0);
|
||||
}
|
||||
|
||||
SExpression argFirst = argList.getCar();
|
||||
Cons argRest = (Cons) argList.getCdr();
|
||||
|
||||
if (argFirst.numberp()) {
|
||||
LispNumber num1 = (LispNumber) argFirst;
|
||||
LispNumber num2 = call(argRest);
|
||||
|
||||
return new LispNumber(num1.getValue() + num2.getValue());
|
||||
}
|
||||
|
||||
throw new RuntimeException("+: " + argFirst + " is not a number");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>PRINT</code> represents the PRINT function in Lisp.
|
||||
*/
|
||||
public class PRINT extends LispFunction {
|
||||
|
||||
// The number of arguments that PRINT takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to PRINT
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("PRINT"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to PRINT: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
System.out.println(arg);
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>QUOTE</code> represents the QUOTE form in Lisp.
|
||||
*/
|
||||
public class QUOTE extends LispFunction {
|
||||
|
||||
// The number of arguments that QUOTE takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to QUOTE
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received exactly one argument
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("QUOTE"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to QUOTE: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
return argList.getCar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>SETF</code> represents the SETF form in Lisp.
|
||||
*/
|
||||
public class SETF extends LispFunction {
|
||||
|
||||
private static SymbolTable environment = new SymbolTable();
|
||||
|
||||
/**
|
||||
* Look up the value of a symbol using its name.
|
||||
*
|
||||
* @param symbolName
|
||||
* the name of the symbol to look up
|
||||
* @return
|
||||
* the value of <code>symbolName</code> if it has one; null otherwise
|
||||
*/
|
||||
public static SExpression lookup(String symbolName) {
|
||||
SymbolTable current = environment;
|
||||
|
||||
while (current != null) {
|
||||
if (current.contains(symbolName)) {
|
||||
return current.get(symbolName);
|
||||
}
|
||||
|
||||
current = current.getParent();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current environment to the specified value.
|
||||
*
|
||||
* @param newEnvironment
|
||||
* the value to set the environment to
|
||||
*/
|
||||
public static void setEnvironment(SymbolTable newEnvironment) {
|
||||
environment = newEnvironment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current environment.
|
||||
*
|
||||
* @return
|
||||
* the current environment
|
||||
*/
|
||||
public static SymbolTable getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
// The number of arguments that SETF takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to SETF
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("SETF"), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to SETF: " + originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression symbol = argList.getCar();
|
||||
|
||||
// make sure the first argument is a symbol
|
||||
if (! symbol.symbolp()) {
|
||||
throw new RuntimeException("SETF: " + symbol + " is not a symbol");
|
||||
}
|
||||
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression value = EVAL.eval(cdr.getCar());
|
||||
|
||||
SymbolTable current = environment;
|
||||
|
||||
// set 'current' to the symbol table that contains 'symbol' or the
|
||||
// global symbol table if 'symbol' is not in the environment
|
||||
while ((! current.contains(symbol.toString())) &&
|
||||
(current.getParent() != null)) {
|
||||
current = current.getParent();
|
||||
}
|
||||
|
||||
current.put(symbol.toString(), value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the arguments passed to this Lisp function should be
|
||||
* evaluated.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
|
||||
/**
|
||||
* <code>SYMBOL_FUNCTION</code> represents the SYMBOL-FUNCTION function in
|
||||
* Lisp.
|
||||
*/
|
||||
public class SYMBOL_FUNCTION extends LispFunction {
|
||||
|
||||
// The number of arguments that SYMBOL-FUNCTION takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to SYMBOL-FUNCTION
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("SYMBOL-FUNCTION"),
|
||||
argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to SYMBOL-FUNCTION: " +
|
||||
originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
// make sure the argument is a symbol
|
||||
if (arg.symbolp()) {
|
||||
LispFunction function = EVAL.lookupFunction(arg.toString());
|
||||
|
||||
// make sure the function actually exists
|
||||
if (function != null) {
|
||||
if (function instanceof UDFunction) {
|
||||
// this is a user-defined function
|
||||
|
||||
UDFunction udFunction = (UDFunction) function;
|
||||
|
||||
return udFunction.getLexpr();
|
||||
}
|
||||
|
||||
// this is a built-in function
|
||||
|
||||
return new Symbol("SUBR-" + arg.toString());
|
||||
}
|
||||
|
||||
throw new RuntimeException("SYMBOL-FUNCTION: undefined function " +
|
||||
arg);
|
||||
}
|
||||
|
||||
throw new RuntimeException("SYMBOL-FUNCTION: " + arg +
|
||||
" is not a symbol");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A <code>SymbolTable</code> maps symbol names to values.
|
||||
*/
|
||||
public class SymbolTable {
|
||||
|
||||
private HashMap<String, SExpression> table;
|
||||
private SymbolTable parent;
|
||||
|
||||
/**
|
||||
* Create a new symbol table with no parent.
|
||||
*/
|
||||
public SymbolTable() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new symbol table with the specified parent.
|
||||
*
|
||||
* @param parent
|
||||
* the parent of this symbol table
|
||||
*/
|
||||
public SymbolTable(SymbolTable parent) {
|
||||
this.table = new HashMap<String, SExpression>();
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified symbol name is in this symbol table.
|
||||
*
|
||||
* @param symbolName
|
||||
* the name of the symbol to look up
|
||||
* @return
|
||||
* <code>true</code> if the symbol is in this symbol table;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean contains(String symbolName) {
|
||||
return table.containsKey(symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified symbol name is mapped in this
|
||||
* symbol table.
|
||||
*
|
||||
* @param symbolName
|
||||
* the name of the symbol whose associated value is to be returned
|
||||
* @return
|
||||
* the value to which this symbol table maps <code>symbolName</code>, or
|
||||
* null if no mapping exists
|
||||
*/
|
||||
public SExpression get(String symbolName) {
|
||||
return table.get(symbolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the specified symbol name with the specified value in this
|
||||
* symbol table. If the symbol table previously contained a mapping for
|
||||
* this symbol name, the old value has been replaced.
|
||||
*
|
||||
* @param symbolName
|
||||
* the name of the symbol with which the specified value is to be
|
||||
* associated
|
||||
* @param value
|
||||
* the value to be associated with the specified symbol name
|
||||
*/
|
||||
public void put(String symbolName, SExpression value) {
|
||||
table.put(symbolName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent of this symbol table.
|
||||
*
|
||||
* @return
|
||||
* the parent of this symbol table
|
||||
*/
|
||||
public SymbolTable getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 2
|
||||
*/
|
||||
|
||||
package eval;
|
||||
|
||||
import parser.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A <code>UDFunction</code> is an internal representation of a user-defined
|
||||
* function in the Lisp programming language.
|
||||
*/
|
||||
public class UDFunction extends LispFunction {
|
||||
|
||||
// the number of arguments that this user-defined function takes.
|
||||
private final int NUM_ARGS;
|
||||
|
||||
private String name;
|
||||
private Cons body;
|
||||
private Cons lexpr;
|
||||
private SymbolTable environment;
|
||||
private ArrayList<String> parameters;
|
||||
|
||||
/**
|
||||
* Create a new user-defined function with the specified name, lambda list
|
||||
* and body.
|
||||
*
|
||||
* @param name
|
||||
* the name of this user-defined function
|
||||
* @param lambdaList
|
||||
* a list of the formal parameters of this user-defined function (MUST BE
|
||||
* A PROPER LIST)
|
||||
* @param body
|
||||
* the body of this user-defined function (MUST BE A PROPER LIST)
|
||||
*/
|
||||
public UDFunction(String name, Cons lambdaList, Cons body) {
|
||||
this.name = name;
|
||||
this.body = body;
|
||||
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
||||
this.environment = SETF.getEnvironment();
|
||||
this.parameters = new ArrayList<String>();
|
||||
|
||||
// retrieve the names of all the formal parameters of this function
|
||||
while (lambdaList.consp()) {
|
||||
this.parameters.add(lambdaList.getCar().toString());
|
||||
|
||||
lambdaList = (Cons) lambdaList.getCdr();
|
||||
}
|
||||
|
||||
this.NUM_ARGS = this.parameters.size();
|
||||
}
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to this function
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol(name), argList);
|
||||
String errMsg = "too " +
|
||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
||||
" arguments given to " + name + ": " +
|
||||
originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
// push a new symbol table onto this function's environment (for its
|
||||
// parameters)
|
||||
environment = new SymbolTable(environment);
|
||||
|
||||
// bind the values of the arguments to the formal parameter names
|
||||
for (String param : parameters) {
|
||||
SExpression currentArg = argList.getCar();
|
||||
|
||||
environment.put(param, currentArg);
|
||||
|
||||
argList = (Cons) argList.getCdr();
|
||||
}
|
||||
|
||||
// store the environment of the S-expression that called this function
|
||||
// (the current environment)
|
||||
SymbolTable currentEnvironment = SETF.getEnvironment();
|
||||
|
||||
// replace the current environment with the environment of this
|
||||
// function
|
||||
SETF.setEnvironment(environment);
|
||||
|
||||
Cons currentSExpression = body;
|
||||
SExpression retval = null;
|
||||
|
||||
// evaluate all the S-expressions making up this function's body
|
||||
while (currentSExpression.consp()) {
|
||||
retval = EVAL.eval(currentSExpression.getCar());
|
||||
currentSExpression = (Cons) currentSExpression.getCdr();
|
||||
}
|
||||
|
||||
// replace the environment of the S-expression that called this
|
||||
// function
|
||||
SETF.setEnvironment(currentEnvironment);
|
||||
|
||||
// remove the bindings of the arguments to the formal parameter names
|
||||
// in the environment of this function
|
||||
environment = new SymbolTable(environment.getParent());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lambda expression that represents this user-defined function.
|
||||
*
|
||||
* @return
|
||||
* the lambda expression that represents this user-defined function
|
||||
*/
|
||||
public Cons getLexpr() {
|
||||
return lexpr;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<body>
|
||||
Provides functions and forms to be used during the evaluation of an
|
||||
S-expression.
|
||||
</body>
|
Binary file not shown.
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter 1
|
||||
*/
|
||||
|
||||
package main;
|
||||
|
||||
import parser.*;
|
||||
import eval.*;
|
||||
import error.ErrorManager;
|
||||
import java.io.*;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* <code>LispInterpreter</code> is an interpreter for the Lisp programming
|
||||
* language. It takes the name of a file as a command-line argument, evaluates
|
||||
* the S-expressions found in the file and then prints the results to the
|
||||
* console. If no file name is provided at the command-line, this program will
|
||||
* read from standard input.
|
||||
*/
|
||||
public class LispInterpreter {
|
||||
|
||||
private static final String GREETING = "SUNY Potsdam Lisp Interpreter - Version 1.0.1";
|
||||
private static final String PROMPT = "~ ";
|
||||
|
||||
public static final String ANSI_RESET = "\u001B[0m";
|
||||
public static final String ANSI_GREEN = "\u001B[32m";
|
||||
|
||||
/**
|
||||
* Evaluate the S-expressions found in the file given as a command-line
|
||||
* argument and print the results to the console. If no file name was
|
||||
* given, retrieve the S-expressions from standard input.
|
||||
*
|
||||
* @param args
|
||||
* the command-line arguments:
|
||||
* <ul>
|
||||
* <li><code>args[0]</code> - file name (optional)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LispParser parser = null;
|
||||
boolean interactive = false;
|
||||
|
||||
if (args.length > 0) {
|
||||
// a file name was given at the command-line, attempt to create a
|
||||
// 'LispParser' on it
|
||||
try {
|
||||
parser = new LispParser(new FileInputStream(args[0]), args[0]);
|
||||
} catch (FileNotFoundException e) {
|
||||
ErrorManager.generateError(e.getMessage(), ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
} else {
|
||||
// no file name was given, create a 'LispParser' on standard input
|
||||
parser = new LispParser(System.in, "System.in");
|
||||
interactive = true;
|
||||
|
||||
System.out.println(GREETING);
|
||||
System.out.println();
|
||||
System.out.print(PROMPT);
|
||||
}
|
||||
|
||||
while (! parser.eof()) {
|
||||
try {
|
||||
SExpression sexpr = parser.getSExpr();
|
||||
String result = MessageFormat.format("{0}{1}{2}", ANSI_GREEN, EVAL.eval(sexpr), ANSI_RESET);
|
||||
|
||||
LispInterpreter.erasePrompt(interactive);
|
||||
System.out.println(result);
|
||||
} catch (RuntimeException e) {
|
||||
LispInterpreter.erasePrompt(interactive);
|
||||
ErrorManager.generateError(e.getMessage(), 2);
|
||||
} catch (IOException e) {
|
||||
ErrorManager.generateError(e.getMessage(), ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
|
||||
if (interactive) {
|
||||
System.out.print(PROMPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void erasePrompt(boolean interactive) {
|
||||
if (interactive) {
|
||||
for (int i = 0; i < PROMPT.length(); i++) {
|
||||
System.out.print("\b");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package main;
|
||||
|
||||
import parser.*;
|
||||
import error.ErrorManager;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <code>LispParserDriver</code> is a program that takes the name of a file
|
||||
* as a command-line argument, creates an internal representation of the
|
||||
* S-expressions found in the file and prints them to the console. If no file
|
||||
* name is provided at the command-line, this program will read from standard
|
||||
* input.
|
||||
*/
|
||||
public class LispParserDriver {
|
||||
|
||||
/**
|
||||
* Create internal representations of the S-expressions found in the file
|
||||
* whose name was given as a command-line argument and print them to the
|
||||
* console. If no file name was given, retrieve the S-expressions from
|
||||
* standard input.
|
||||
*
|
||||
* @param args
|
||||
* the command-line arguments:
|
||||
* <ul>
|
||||
* <li><code>args[0]</code> - file name (optional)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LispParser parser = null;
|
||||
|
||||
if (args.length > 0) {
|
||||
// a file name was given at the command-line, attempt to create a
|
||||
// 'LispParser' on it
|
||||
try {
|
||||
parser = new LispParser(new FileInputStream(args[0]), args[0]);
|
||||
} catch (FileNotFoundException e) {
|
||||
ErrorManager.generateError(e.getMessage(),
|
||||
ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
} else {
|
||||
// no file name was given, create a 'LispParser' on standard input
|
||||
parser = new LispParser(System.in, "System.in");
|
||||
}
|
||||
|
||||
while (! parser.eof()) {
|
||||
try {
|
||||
SExpression sexpr = parser.getSExpr();
|
||||
|
||||
System.out.println(sexpr.toString());
|
||||
} catch (RuntimeException e) {
|
||||
ErrorManager.generateError(e.getMessage(), 2);
|
||||
} catch (IOException e) {
|
||||
ErrorManager.generateError(e.getMessage(),
|
||||
ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Interpreter Phase 1 - Lexical Analysis
|
||||
*/
|
||||
|
||||
package main;
|
||||
|
||||
import scanner.*;
|
||||
import error.ErrorManager;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <code>LispScannerDriver</code> is a program that takes the name of a file
|
||||
* as a command-line argument, retrieves all of the Lisp tokens from the file
|
||||
* and prints them to the console. If no file name is provided at the
|
||||
* command-line, this program will read from standard input.
|
||||
*/
|
||||
public class LispScannerDriver {
|
||||
|
||||
/**
|
||||
* Obtain the Lisp tokens from the file whose name was given as a
|
||||
* command-line argument and print them to the console. If no file name was
|
||||
* given, retrieve the tokens from standard input.
|
||||
*
|
||||
* @param args
|
||||
* the command-line arguments:
|
||||
* <ul>
|
||||
* <li><code>args[0]</code> - file name (optional)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LispScanner in = null;
|
||||
|
||||
if (args.length > 0) {
|
||||
// a file name was given at the command-line, attempt to create a
|
||||
// 'LispScanner' on it
|
||||
try {
|
||||
in = new LispScanner(new FileInputStream(args[0]), args[0]);
|
||||
} catch (FileNotFoundException e) {
|
||||
ErrorManager.generateError(e.getMessage(),
|
||||
ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
} else {
|
||||
// no file name was given, create a 'LispScanner' on standard input
|
||||
in = new LispScanner(System.in, "System.in");
|
||||
}
|
||||
|
||||
Token t = null;
|
||||
|
||||
do {
|
||||
try {
|
||||
t = in.nextToken();
|
||||
|
||||
System.out.printf("%-15s%-25s%5d%5d%25s\n", t.getType(),
|
||||
t.getText(),
|
||||
t.getLine(),
|
||||
t.getColumn(),
|
||||
t.getFName());
|
||||
} catch (RuntimeException e) {
|
||||
ErrorManager.generateError(e.getMessage(), 2);
|
||||
} catch (IOException e) {
|
||||
ErrorManager.generateError(e.getMessage(),
|
||||
ErrorManager.CRITICAL_LEVEL);
|
||||
}
|
||||
} while ((t == null) || (t.getType() != Token.Type.EOF));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<body>
|
||||
Provides test drivers for the various stages of the Lisp Interpreter.
|
||||
</body>
|
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This class represents an ATOM in the PL-Lisp implementation.
|
||||
*/
|
||||
public class Atom extends SExpression {
|
||||
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* Create a new ATOM with the specified text.
|
||||
*
|
||||
* @param text
|
||||
* the text representing this ATOM
|
||||
*/
|
||||
public Atom(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is an ATOM.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean atomp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this ATOM.
|
||||
*
|
||||
* @return
|
||||
* a string representation of this ATOM
|
||||
*/
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This class represents a Lisp CONS cell in the PL-Lisp implementation.
|
||||
*/
|
||||
public class Cons extends SExpression {
|
||||
|
||||
private SExpression car;
|
||||
private SExpression cdr;
|
||||
|
||||
/**
|
||||
* Create a new CONS cell with the specified car and cdr.
|
||||
*
|
||||
* @param car
|
||||
* the car of this CONS cell
|
||||
* @param cdr
|
||||
* the cdr of this CONS cell
|
||||
*/
|
||||
public Cons(SExpression car, SExpression cdr) {
|
||||
this.car = car;
|
||||
this.cdr = cdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the car of this CONS cell.
|
||||
*
|
||||
* @return
|
||||
* the car of this CONS cell
|
||||
*/
|
||||
public SExpression getCar() {
|
||||
return car;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the cdr of this CONS cell.
|
||||
*
|
||||
* @return
|
||||
* the cdr of this CONS cell
|
||||
*/
|
||||
public SExpression getCdr() {
|
||||
return cdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the car of this CONS cell to the specified value.
|
||||
*
|
||||
* @param newCar
|
||||
* the value to assign to the car of this CONS cell
|
||||
*/
|
||||
public void setCar(SExpression newCar) {
|
||||
car = newCar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cdr of this CONS cell to the specified value.
|
||||
*
|
||||
* @param newCdr
|
||||
* the value to assign to the cdr of this CONS cell
|
||||
*/
|
||||
public void setCdr(SExpression newCdr) {
|
||||
cdr = newCdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a CONS cell.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean consp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this CONS cell.
|
||||
*
|
||||
* @return
|
||||
* a string representation of this CONS cell
|
||||
*/
|
||||
public String toString() {
|
||||
return ("(" + toStringAux());
|
||||
}
|
||||
|
||||
// Returns a string representation of the car of a CONS cell followed by
|
||||
// its cdr. If the cdr of this CONS cell is not a CONS cell itself, this
|
||||
// method places a ')' at the end of its return value. Also, if the cdr of
|
||||
// this CONS cell is NIL, it will not be included in the return value of
|
||||
// this method. When used in conjunction with the 'toString' method of this
|
||||
// class, this method provides a means for creating the correct string
|
||||
// representation of a list.
|
||||
//
|
||||
// Returns: a string representation of the car of a CONS cell followed by
|
||||
// its cdr
|
||||
private String toStringAux() {
|
||||
if (cdr.nullp()) {
|
||||
return (car.toString() + ")");
|
||||
} else if (cdr.consp()) {
|
||||
return (car.toString() + " " + ((Cons) cdr).toStringAux());
|
||||
}
|
||||
|
||||
// the cdr of this CONS cell is not a list
|
||||
return (car.toString() + " . " + cdr.toString() + ")");
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This class represents a NUMBER in the PL-Lisp implementation.
|
||||
*/
|
||||
public class LispNumber extends Atom {
|
||||
|
||||
private int value;
|
||||
|
||||
/**
|
||||
* Create a new NUMBER with the specified text.
|
||||
*
|
||||
* @param text
|
||||
* the text representing this NUMBER
|
||||
* @throws IllegalArgumentException
|
||||
* Indicates that <code>text</code> does not represent a valid integer.
|
||||
*/
|
||||
public LispNumber(String text) {
|
||||
super(text.replaceFirst("^0+(?!$)", ""));
|
||||
|
||||
try {
|
||||
this.value = Integer.parseInt(text);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(text +
|
||||
" is not a valid integer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new NUMBER with the specified value.
|
||||
*
|
||||
* @param value
|
||||
* the integer value of this NUMBER
|
||||
*/
|
||||
public LispNumber(int value) {
|
||||
super(Integer.toString(value));
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a NUMBER.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean numberp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the integer value of this NUMBER.
|
||||
*
|
||||
* @return
|
||||
* the integer value of this NUMBER
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
import scanner.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A <code>LispParser</code> converts a stream of bytes into internal
|
||||
* representations of Lisp S-expressions. When the end of stream has been
|
||||
* reached the <code>eof</code> method of this parser will return true.
|
||||
*/
|
||||
public class LispParser {
|
||||
|
||||
private LispScanner scanner;
|
||||
private Token nextToken;
|
||||
|
||||
// A field to store an exception that has been thrown in the 'eof' method
|
||||
// as a result of reading in the next token from 'scanner'.
|
||||
private Exception delayedException;
|
||||
|
||||
// A field to notify us if the next token has already been stored in
|
||||
// 'nextToken' by the 'eof' method.
|
||||
private boolean nextTokenStored;
|
||||
|
||||
/**
|
||||
* Create a new <code>LispParser</code> that produces S-expressions from
|
||||
* the specified input stream.
|
||||
*
|
||||
* @param in
|
||||
* the input stream to obtain S-expressions from (must not be
|
||||
* <code>null</code>)
|
||||
* @param fileName
|
||||
* the name of the file that <code>in</code> is reading from
|
||||
*/
|
||||
public LispParser(InputStream in, String fileName) {
|
||||
scanner = new LispScanner(in, fileName);
|
||||
nextToken = null;
|
||||
delayedException = null;
|
||||
nextTokenStored = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determing if this parser has reached the end of its underlying input
|
||||
* stream.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code> if this parser has reached the end of its underlying
|
||||
* input stream; <code>false</code> otherwise
|
||||
*/
|
||||
public boolean eof() {
|
||||
if (! nextTokenStored) {
|
||||
// attempt to read the next token from 'scanner' and store it in
|
||||
// 'nextToken'
|
||||
try {
|
||||
nextToken = scanner.nextToken();
|
||||
nextTokenStored = true;
|
||||
} catch (Exception e) {
|
||||
// this method should give the illusion of not actually reading
|
||||
// a token, so we store any exceptions thrown as a result of
|
||||
// reading in the next token from 'scanner' (it will be thrown
|
||||
// the next time the 'getSExpr' method is called)
|
||||
delayedException = e;
|
||||
|
||||
if (nextToken == null) {
|
||||
// we have not successfully read in any tokens yet, so we
|
||||
// could not have read in an end-of-file token
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (nextToken.getType() == Token.Type.EOF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next S-expression from this parser.
|
||||
*
|
||||
* @return
|
||||
* the next S-expression from this parser
|
||||
* @throws RuntimeException
|
||||
* Indicates that an illegal S-expression was encountered in the
|
||||
* underlying input stream.
|
||||
* @throws IOException
|
||||
* Indicates that an I/O error has occurred.
|
||||
*/
|
||||
public SExpression getSExpr() throws IOException {
|
||||
if (delayedException != null) {
|
||||
// the 'eof' method has stored an exception for us to throw
|
||||
|
||||
// determine the type of the stored exception and throw it!
|
||||
if (delayedException instanceof IOException) {
|
||||
IOException e = (IOException) delayedException;
|
||||
|
||||
// remove the exception from 'delayedException'
|
||||
delayedException = null;
|
||||
|
||||
throw e;
|
||||
} else if (delayedException instanceof RuntimeException) {
|
||||
RuntimeException e = (RuntimeException) delayedException;
|
||||
|
||||
// remove the exception from 'delayedException'
|
||||
delayedException = null;
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (! nextTokenStored) {
|
||||
// the next token has not been stored in 'nextToken' by the 'eof'
|
||||
// method
|
||||
|
||||
nextToken = scanner.nextToken();
|
||||
} else {
|
||||
// the 'eof' method has been called and has read in the next token
|
||||
// already to determine if we have reached the end-of-file
|
||||
|
||||
nextTokenStored = false;
|
||||
}
|
||||
|
||||
return sExpr();
|
||||
}
|
||||
|
||||
// sExpr ::= NUMBER | IDENTIFIER | RESERVED | STRING | QUOTE_MARK sExpr |
|
||||
// LEFT_PAREN sExprTail
|
||||
//
|
||||
// Returns: an S-expression that matches the rules given above
|
||||
// Throws: RuntimeException - Indicates that an illegal S-expression was
|
||||
// encountered in the underlying input stream.
|
||||
// Throws: IOException - Indicates that an I/O error has occurred.
|
||||
// Precondition: 'nextToken' is not null.
|
||||
private SExpression sExpr() throws IOException {
|
||||
// determine the type of 'nextToken' and create the appropriate
|
||||
// S-expression
|
||||
switch (nextToken.getType()) {
|
||||
case NUMBER:
|
||||
return new LispNumber(nextToken.getText());
|
||||
case IDENTIFIER:
|
||||
case RESERVED:
|
||||
return new Symbol(nextToken.getText());
|
||||
case STRING:
|
||||
return new LispString(nextToken.getText());
|
||||
case QUOTE_MARK:
|
||||
nextToken = scanner.nextToken();
|
||||
SExpression arg = sExpr();
|
||||
|
||||
return new Cons(new Symbol("QUOTE"),
|
||||
new Cons(arg, Nil.getUniqueInstance()));
|
||||
case LEFT_PAREN:
|
||||
return sExprTail();
|
||||
case RIGHT_PAREN:
|
||||
throw new RuntimeException("expression begins with \')\'" +
|
||||
" - line " + nextToken.getLine() +
|
||||
" column " + nextToken.getColumn());
|
||||
case EOF:
|
||||
throw new RuntimeException("end-of-file encountered" +
|
||||
" - line " + nextToken.getLine() +
|
||||
" column " + nextToken.getColumn());
|
||||
default: // unrecognized token type
|
||||
throw new RuntimeException("unrecognizable token" +
|
||||
" - line " + nextToken.getLine() +
|
||||
" column " + nextToken.getColumn());
|
||||
}
|
||||
}
|
||||
|
||||
// sExprTail ::= RIGHT_PAREN | sExpr sExprTail
|
||||
//
|
||||
// Returns: an S-expression that matches the rules given above
|
||||
// Throws: IOException - Indicates that an I/O error has occurred.
|
||||
// Precondition: 'scanner' is not null.
|
||||
private SExpression sExprTail() throws IOException {
|
||||
nextToken = scanner.nextToken();
|
||||
|
||||
// determine the type of 'nextToken' and create the appropriate
|
||||
// S-expression
|
||||
switch (nextToken.getType()) {
|
||||
case RIGHT_PAREN:
|
||||
return Nil.getUniqueInstance();
|
||||
default:
|
||||
SExpression car = sExpr();
|
||||
SExpression cdr = sExprTail();
|
||||
|
||||
return new Cons(car, cdr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This class represents a STRING in the PL-Lisp implementation.
|
||||
*/
|
||||
public class LispString extends Atom {
|
||||
|
||||
/**
|
||||
* Create a new STRING with the specified text.
|
||||
*
|
||||
* @param text
|
||||
* the text representing this STRING
|
||||
*/
|
||||
public LispString(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a STRING.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean stringp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This class represents NIL in the PL-Lisp implementation.
|
||||
*/
|
||||
public class Nil extends Cons {
|
||||
|
||||
private static Nil uniqueInstance = new Nil();
|
||||
|
||||
/**
|
||||
* Retrieve the single unique instance of NIL.
|
||||
*
|
||||
* @return
|
||||
* the single unique instance of NIL
|
||||
*/
|
||||
public static Nil getUniqueInstance() {
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
// We are using the Singleton pattern, so the constructor for 'Nil' is
|
||||
// private.
|
||||
private Nil() {
|
||||
super(null, null);
|
||||
|
||||
// the car and cdr of NIL both refer to NIL
|
||||
super.setCar(this);
|
||||
super.setCdr(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is NULL.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean nullp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is an ATOM.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean atomp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a CONS cell.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean consp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a SYMBOL.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code>
|
||||
*/
|
||||
public boolean symbolp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the car of this CONS cell to the specified value. This method does
|
||||
* nothing (the car of NIL can not be changed).
|
||||
*
|
||||
* @param newCar
|
||||
* the value to assign to the car of this CONS cell
|
||||
*/
|
||||
public void setCar(SExpression newCar) {}
|
||||
|
||||
/**
|
||||
* Set the cdr of this CONS cell to the specified value. This method does
|
||||
* nothing (the cdr of NIL can not be changed).
|
||||
*
|
||||
* @param newCdr
|
||||
* the value to assign to the cdr of this CONS cell
|
||||
*/
|
||||
public void setCdr(SExpression newCdr) {}
|
||||
|
||||
/**
|
||||
* Returns a string representation of NIL.
|
||||
*
|
||||
* @return
|
||||
* a string representation of NIL
|
||||
*/
|
||||
public String toString() {
|
||||
return "NIL";
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Name: Mike Cifelli
|
||||
* Course: CIS 443 - Programming Languages
|
||||
* Assignment: Lisp Parser
|
||||
*/
|
||||
|
||||
package parser;
|
||||
|
||||
/**
|
||||
* This is the base class for memory in the PL-Lisp implementation.
|
||||
*/
|
||||
public class SExpression {
|
||||
|
||||
// for mark and sweep garbage collection
|
||||
private boolean marked = false;
|
||||
|
||||
/**
|
||||
* Determine if this <code>SExpression</code> is marked.
|
||||
*
|
||||
* @return
|
||||
* <code>true</code> if this <code>SExpression</code> is marked;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public final boolean isMarked() {
|
||||
return marked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the marked status of this S-expression to the specified value.
|
||||
*
|
||||
* @param value
|
||||
* the value to assign to this S-expression's marked status
|
||||
*/
|
||||
public final void setMarked(final boolean value) {
|
||||
marked = value;
|
||||
}
|
||||
|
||||
// Lisp type predicates;
|
||||
// by default, all return false (an SExpression effectively has NO type);
|
||||
// overridden in subclasses to describe their Lisp type
|
||||
|
||||
/**
|
||||
* Test if this S-expression is NULL.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean nullp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is an ATOM.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean atomp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a CONS cell.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean consp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a LIST.
|
||||
*
|
||||
* @return
|
||||
* the value of <code>(consp() || nullp())</code>
|
||||
*/
|
||||
public boolean listp() {
|
||||
return (consp() || nullp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a NUMBER.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean numberp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a SYMBOL.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean symbolp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a FUNCTION.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean functionp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this S-expression is a STRING.
|
||||
*
|
||||
* @return
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean stringp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue