Additional refactoring for eclipse
This commit is contained in:
		
							parent
							
								
									b875727361
								
							
						
					
					
						commit
						4ad31c0570
					
				| @ -1,10 +1,12 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <classpath> | ||||
| 	<classpathentry kind="src" path="src"/> | ||||
| 	<classpathentry kind="src" path="test"/> | ||||
| 	<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="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> | ||||
| 	<classpathentry kind="output" path="build/classes"/> | ||||
| </classpath> | ||||
|  | ||||
							
								
								
									
										13
									
								
								.project
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								.project
									
									
									
									
									
								
							| @ -15,6 +15,19 @@ | ||||
| 			<arguments> | ||||
| 			</arguments> | ||||
| 		</buildCommand> | ||||
| 		<buildCommand> | ||||
| 			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name> | ||||
| 			<arguments> | ||||
| 				<dictionary> | ||||
| 					<key>LaunchConfigHandle</key> | ||||
| 					<value><project>/.externalToolBuilders/Ant_Builder.launch</value> | ||||
| 				</dictionary> | ||||
| 				<dictionary> | ||||
| 					<key>incclean</key> | ||||
| 					<value>true</value> | ||||
| 				</dictionary> | ||||
| 			</arguments> | ||||
| 		</buildCommand> | ||||
| 	</buildSpec> | ||||
| 	<natures> | ||||
| 		<nature>org.eclipse.wst.common.project.facet.core.nature</nature> | ||||
|  | ||||
| @ -1,11 +1,12 @@ | ||||
| <?xml version="1.0"?> | ||||
| 
 | ||||
| <project name="LispInterpreter" basedir="." default="compile"> | ||||
|     <property name="src.dir" value="." /> | ||||
|     <property name="src.dir" value="src" /> | ||||
|     <property name="build.dir" value="build" /> | ||||
|     <property name="classes.dir" value="${build.dir}/classes" /> | ||||
|     <property name="jar.dir" value="jar" /> | ||||
|     <property name="doc.dir" value="doc" /> | ||||
| 	<property name="test.dir" value="test" /> | ||||
|     <property name="jar-file" value="${jar.dir}/LispInterpreter.jar" /> | ||||
|     <property name="main-class" value="main.LispInterpreter" /> | ||||
| 
 | ||||
| @ -16,11 +17,8 @@ | ||||
|     </target> | ||||
| 
 | ||||
|     <target name="compile"> | ||||
|         <mkdir dir="${classes.dir}" /> | ||||
|         <javac srcdir="${src.dir}" | ||||
|                destdir="${classes.dir}" | ||||
|                includeantruntime="false" | ||||
|                excludes="main/LispInterpreter2.java" /> | ||||
|                includeantruntime="false" /> | ||||
|     </target> | ||||
| 
 | ||||
|     <target name="jar" depends="compile"> | ||||
|  | ||||
| @ -1,50 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| <body> | ||||
|     Provides a class for managing errors in the Lisp Interpreter. | ||||
| </body> | ||||
| @ -1,74 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,38 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,46 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,46 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,73 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,44 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,82 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,60 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										45
									
								
								eval/EQ.java
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								eval/EQ.java
									
									
									
									
									
								
							| @ -1,45 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,58 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,55 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										251
									
								
								eval/EVAL.java
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								eval/EVAL.java
									
									
									
									
									
								
							| @ -1,251 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,26 +0,0 @@ | ||||
| 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,31 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,55 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										108
									
								
								eval/LAMBDA.java
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								eval/LAMBDA.java
									
									
									
									
									
								
							| @ -1,108 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,69 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,55 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										116
									
								
								eval/LET.java
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								eval/LET.java
									
									
									
									
									
								
							| @ -1,116 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,40 +0,0 @@ | ||||
| /* | ||||
|  * 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)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,38 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,87 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,73 +0,0 @@ | ||||
| /* | ||||
|  * 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(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,44 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,60 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,34 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,38 +0,0 @@ | ||||
| /* | ||||
|  * 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()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,34 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,40 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,47 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										112
									
								
								eval/SETF.java
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								eval/SETF.java
									
									
									
									
									
								
							| @ -1,112 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,65 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,90 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,122 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| <body> | ||||
|     Provides functions and forms to be used during the evaluation of an | ||||
|     S-expression. | ||||
| </body> | ||||
| @ -1,91 +0,0 @@ | ||||
| /* | ||||
|  * 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"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,50 +0,0 @@ | ||||
| package main; | ||||
| 
 | ||||
| import parser.*; | ||||
| import eval.*; | ||||
| import error.ErrorManager; | ||||
| import java.io.*; | ||||
| import java.net.*; | ||||
| import remotefs.RemoteFileInputStream; | ||||
| 
 | ||||
| public class LispInterpreter2 { | ||||
| 
 | ||||
|     public static final String HOST_NAME = "localhost"; | ||||
|     public static final int PORT_NUM = 5150; | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         LispParser parser = null; | ||||
| 
 | ||||
|         if (args.length > 0) { | ||||
|             try { | ||||
|                 InetAddress host = InetAddress.getByName(HOST_NAME); | ||||
|                 RemoteFileInputStream remoteIn = | ||||
|                         new RemoteFileInputStream(host, PORT_NUM, args[0]); | ||||
| 
 | ||||
|                 parser = new LispParser(remoteIn, args[0]); | ||||
|             } catch (UnknownHostException e) { | ||||
|                 ErrorManager.generateError(e.getMessage(), | ||||
|                                            ErrorManager.CRITICAL_LEVEL); | ||||
|             } catch (FileNotFoundException e) { | ||||
|                 ErrorManager.generateError(e.getMessage(), | ||||
|                                            ErrorManager.CRITICAL_LEVEL); | ||||
|             } | ||||
|         } else { | ||||
|             parser = new LispParser(System.in, "System.in"); | ||||
|         } | ||||
| 
 | ||||
|         while (! parser.eof()) { | ||||
|             try { | ||||
|                 SExpression sexpr = parser.getSExpr(); | ||||
| 
 | ||||
|                 System.out.println(EVAL.eval(sexpr)); | ||||
|             } catch (RuntimeException e) { | ||||
|                 ErrorManager.generateError(e.getMessage(), 2); | ||||
|             } catch (IOException e) { | ||||
|                 ErrorManager.generateError(e.getMessage(), | ||||
|                                            ErrorManager.CRITICAL_LEVEL); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,65 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,69 +0,0 @@ | ||||
| /* | ||||
|  * 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)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| <body> | ||||
|     Provides test drivers for the various stages of the Lisp Interpreter. | ||||
| </body> | ||||
| @ -1,46 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										111
									
								
								parser/Cons.java
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								parser/Cons.java
									
									
									
									
									
								
							| @ -1,111 +0,0 @@ | ||||
| /* | ||||
|  * 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() + ")"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,67 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,192 +0,0 @@ | ||||
| /* | ||||
|  * 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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,34 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										104
									
								
								parser/Nil.java
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								parser/Nil.java
									
									
									
									
									
								
							| @ -1,104 +0,0 @@ | ||||
| /* | ||||
|  * 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"; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,122 +0,0 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,37 +0,0 @@ | ||||
| /* | ||||
|  * Name: Mike Cifelli | ||||
|  * Course: CIS 443 - Programming Languages | ||||
|  * Assignment: Lisp Parser | ||||
|  */ | ||||
| 
 | ||||
| package parser; | ||||
| 
 | ||||
| /** | ||||
|  * This class represents a SYMBOL in the PL-Lisp implementation. | ||||
|  */ | ||||
| public class Symbol extends Atom { | ||||
| 
 | ||||
|     /** This SYMBOL represents TRUE in the PL-Lisp implementation. */ | ||||
|     public static final Symbol T = new Symbol("T"); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new SYMBOL with the specified text. | ||||
|      * | ||||
|      * @param text | ||||
|      *  the text representing this SYMBOL | ||||
|      */ | ||||
|     public Symbol(String text) { | ||||
|         super(text.toUpperCase()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test if this S-expression is a SYMBOL. | ||||
|      * | ||||
|      * @return | ||||
|      *  <code>true</code> | ||||
|      */ | ||||
|     public boolean symbolp() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| <body> | ||||
|     Provides the classes necessary for creating an internal representation of | ||||
|     the Lisp programming language. | ||||
| </body> | ||||
| @ -1,160 +0,0 @@ | ||||
| /* | ||||
|  * Name: Mike Cifelli | ||||
|  * Course: CIS 443 - Programming Languages | ||||
|  * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis | ||||
|  */ | ||||
| 
 | ||||
| package scanner; | ||||
| 
 | ||||
| import java.io.InputStream; | ||||
| import java.io.FilterInputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * A <code>LispFilterStream</code> is an input stream that returns the bytes | ||||
|  * from an underlying input stream with all Lisp comments removed and replaced | ||||
|  * with newlines. | ||||
|  */ | ||||
| public class LispFilterStream extends FilterInputStream { | ||||
| 
 | ||||
|     private boolean inQuote; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a <code>LispFilterStream</code> with the specified underlying | ||||
|      * <code>InputStream</code>. | ||||
|      * | ||||
|      * @param in | ||||
|      *  the underlying input stream (must not be <code>null</code>) | ||||
|      */ | ||||
|     public LispFilterStream(InputStream in) { | ||||
|         super(in); | ||||
| 
 | ||||
|         inQuote = false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reads the next byte of data from this input stream. The value byte is | ||||
|      * returned as an <code>int</code> in the range <code>0</code> to | ||||
|      * <code>255</code>. If no byte is available because the end of the stream | ||||
|      * has been reached, the value <code>-1</code> is returned.  | ||||
|      * | ||||
|      * @return | ||||
|      *  the next byte of data, or <code>-1</code> if the end of the stream has | ||||
|      *  been reached. | ||||
|      * @throws IOException | ||||
|      *  Indicates that an I/O error has occurred. | ||||
|      */ | ||||
|     @Override | ||||
|     public int read() throws IOException { | ||||
|         int next = super.read(); | ||||
| 
 | ||||
|         if ((next == ';') && (! inQuote)) { | ||||
|             // we have entered a comment, consume all the bytes from the | ||||
|             // underlying input stream until we reach a newline character or | ||||
|             // the end of the stream | ||||
|             while ((next != '\n') && (next != -1)) { | ||||
|                 next = super.read(); | ||||
|             } | ||||
|         } else if (next == '\n') { | ||||
|             inQuote = false; | ||||
|         } else if (next == '\"') {  // we have entered or left a quoted string | ||||
|             inQuote = (! inQuote); | ||||
|         } | ||||
| 
 | ||||
|         return next; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reads up to the specified number of data bytes from this input stream | ||||
|      * into an array of bytes starting at the specified offset. If no bytes are | ||||
|      * available because the end of this stream has been reached then | ||||
|      * <code>-1</code> is returned. Also, If the specified number of bytes is | ||||
|      * more than the number of remaining data bytes in this input stream, then | ||||
|      * only the number of remaining data bytes are copied into the byte array. | ||||
|      * | ||||
|      * @param b | ||||
|      *  the buffer into which the data bytes are read (must not be | ||||
|      *  <code>null</code>) | ||||
|      * @param off | ||||
|      *  the start offset in <code>b</code> at which the data is written (must | ||||
|      *  be <code>>= 0</code> and <code>< b.length</code>) | ||||
|      * @param len | ||||
|      *  the maximum number of bytes to read into <code>b</code> (<code>len + | ||||
|      *  off</code> must be <code>< b.length</code>) | ||||
|      * @return | ||||
|      *  the total number of bytes read into the buffer, or <code>-1</code> if | ||||
|      *  there is no more data because the end of the stream has been reached | ||||
|      * @throws IOException | ||||
|      *  Indicates that the first byte could not be read into <code>b</code> | ||||
|      *  for some reason other than reaching the end of the stream. | ||||
|      * @throws IndexOutOfBoundsException | ||||
|      *  Indicates that this method attempted to access an index in | ||||
|      *  <code>b</code> that was either negative or greater than or equal to | ||||
|      *  <code>b.length</code> as a result of the given parameters. | ||||
|      * @throws NullPointerException | ||||
|      *  Indicates that <code>b</code> is <code>null</code>. | ||||
|      */ | ||||
|     @Override | ||||
|     public int read(byte[] b, int off, int len) throws IOException { | ||||
|         int bytesRead = 0; | ||||
| 
 | ||||
|         // make sure we are supposed to read at least one byte into 'b' | ||||
|         if (len > 0) { | ||||
|             int next = read(); | ||||
| 
 | ||||
|             if (next == -1) { | ||||
|                 // there are no more bytes to read from this input stream | ||||
| 
 | ||||
|                 return -1; | ||||
|             } | ||||
| 
 | ||||
|             int i = off; | ||||
| 
 | ||||
|             while (next != -1) { | ||||
|                 ++bytesRead; | ||||
| 
 | ||||
|                 b[i++] = (byte) next; | ||||
| 
 | ||||
|                 if (i >= (off + len)) {  // we have read 'len' bytes into 'b' | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 try { | ||||
|                     next = read(); | ||||
|                 } catch (IOException e) { | ||||
|                     // treat this exception like an end of stream | ||||
| 
 | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return bytesRead; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Skip over and discard the specified number of bytes from this input | ||||
|      * stream. This method may, for a variety of reasons, end up skipping some | ||||
|      * smaller number of bytes, possibly <code>0</code>. The actual number of | ||||
|      * bytes skipped is returned. | ||||
|      * | ||||
|      * @param n | ||||
|      *  the number of bytes to be skipped | ||||
|      * @return | ||||
|      *  the actual number of bytes skipped | ||||
|      * @throws IOException | ||||
|      *  Indicates that an I/O error has occurred. | ||||
|      */ | ||||
|     @Override | ||||
|     public long skip (long n) throws IOException { | ||||
|         long bytesSkipped = 0; | ||||
| 
 | ||||
|         while ((n > 0) && (read() != -1)) { | ||||
|             ++bytesSkipped; | ||||
|             --n; | ||||
|         } | ||||
| 
 | ||||
|         return bytesSkipped; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,320 +0,0 @@ | ||||
| /* | ||||
|  * Name: Mike Cifelli | ||||
|  * Course: CIS 443 - Programming Languages | ||||
|  * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis | ||||
|  */ | ||||
| 
 | ||||
| package scanner; | ||||
| 
 | ||||
| import java.io.InputStream; | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * A <code>LispScanner</code> converts a stream of bytes into a stream of Lisp | ||||
|  * tokens. When the end of stream has been reached a token with a type of | ||||
|  * <code>Token.Type.EOF</code> is returned from the <code>nextToken</code> | ||||
|  * method of this scanner. | ||||
|  */ | ||||
| public class LispScanner { | ||||
| 
 | ||||
|     private LispFilterStream inStream; | ||||
|     private Token currToken; | ||||
|     private String fileName; | ||||
|     private int line; | ||||
|     private int column; | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new <code>LispScanner</code> that produces Lisp tokens from the | ||||
|      * specified input stream. | ||||
|      * | ||||
|      * @param in | ||||
|      *  the input stream to obtain Lisp tokens from (must not be | ||||
|      *  <code>null</code>) | ||||
|      * @param fileName | ||||
|      *  the name of the file that <code>in</code> is reading from | ||||
|      */ | ||||
|     public LispScanner(InputStream in, String fileName) { | ||||
|         this.inStream = new LispFilterStream(new BufferedInputStream(in)); | ||||
|         this.currToken = null; | ||||
|         this.fileName = fileName; | ||||
|         this.line = 1; | ||||
|         this.column = 0; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the same Lisp token returned from the last call to the | ||||
|      * <code>nextToken</code> method of this scanner. In the case that no calls | ||||
|      * to <code>nextToken</code> have been made yet, this method returns | ||||
|      * <code>null</code>. | ||||
|      * | ||||
|      * @return | ||||
|      *  the last Lisp token returned from this scanner or <code>null</code> (if | ||||
|      *  no tokens have been returned from this scanner yet) | ||||
|      */ | ||||
|     public Token getCurrToken() { | ||||
|         return currToken; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the next Lisp token from this scanner. | ||||
|      * | ||||
|      * @return | ||||
|      *  the next Lisp token from this scanner. | ||||
|      * @throws RuntimeException | ||||
|      *  Indicates that an illegal character or an unterminated quoted string | ||||
|      *  was encountered in the input stream (not counting comments). | ||||
|      * @throws IOException | ||||
|      *  Indicates that an I/O error has occurred. | ||||
|      */ | ||||
|     public Token nextToken() throws IOException { | ||||
|         currToken = retrieveNextToken(); | ||||
| 
 | ||||
|         return currToken; | ||||
|     } | ||||
| 
 | ||||
|     // Retrieve the next Lisp token from 'inStream'. | ||||
|     // | ||||
|     // Returns: the next Lisp token found in 'inStream' | ||||
|     // Precondition: 'inStream' must not be null. | ||||
|     // Throws: RuntimeException - Indicates that an illegal character or an | ||||
|     //                            unterminated quoted string was encountered in | ||||
|     //                            'inStream'. | ||||
|     // Throws: IOException - Indicates that an I/O error has occurred. | ||||
|     private Token retrieveNextToken() throws IOException { | ||||
|         int c; | ||||
| 
 | ||||
|         while ((c = inStream.read()) != -1) { | ||||
|             char nextChar = (char) c; | ||||
| 
 | ||||
|             ++column; | ||||
| 
 | ||||
|             // determine the type of the Lisp token from the character obtained | ||||
|             // from 'inStream' | ||||
|             switch (nextChar) { | ||||
|             case '\n': | ||||
|                 // we have hit a new line so increment 'line' and reset | ||||
|                 // 'column' | ||||
|                 ++line; | ||||
|                 column = 0; | ||||
| 
 | ||||
|                 break; | ||||
|             case '(': | ||||
|                 return new Token(Token.Type.LEFT_PAREN, | ||||
|                                  "(", | ||||
|                                  fileName, | ||||
|                                  line, | ||||
|                                  column); | ||||
|             case ')': | ||||
|                 return new Token(Token.Type.RIGHT_PAREN, | ||||
|                                  ")", | ||||
|                                  fileName, | ||||
|                                  line, | ||||
|                                  column); | ||||
|             case '\'': | ||||
|                 return new Token(Token.Type.QUOTE_MARK, | ||||
|                                  "\'", | ||||
|                                  fileName, | ||||
|                                  line, | ||||
|                                  column); | ||||
|             case '\"': | ||||
|                 return retrieveString(nextChar); | ||||
|             default: | ||||
|                 if (Character.isWhitespace(nextChar)) {  // skip whitespace | ||||
|                     continue; | ||||
|                 } else if (Character.isDigit(nextChar)) {  // number | ||||
|                     return retrieveNumber(nextChar); | ||||
|                 } else if (isLegalIdChar(nextChar)) {  // identifier | ||||
|                     return retrieveIdentifier(nextChar); | ||||
|                 } else { | ||||
|                     // 'nextChar' can not start any Lisp token | ||||
| 
 | ||||
|                     throw new RuntimeException("illegal character " + | ||||
|                                                "\'" + nextChar + "\'" + | ||||
|                                                " - line " + line + | ||||
|                                                " column " + column); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // we have reached the end of 'inStream' so we return an end-of-file | ||||
|         // token | ||||
|         return new Token(Token.Type.EOF, "EOF", fileName, line, column); | ||||
|     } | ||||
| 
 | ||||
|     // Retrieve a quoted string token from 'inStream'. | ||||
|     // | ||||
|     // Parameters: firstDoubleQuote - the opening double quote of this quoted | ||||
|     //                                string | ||||
|     // Returns: a quoted string token obtained from 'instream' | ||||
|     // Throws: RuntimeException - Indicates that this quoted string was | ||||
|     //                            missing its terminating double quote. | ||||
|     // Throws: IOException - Indicates that an I/O error has occurred. | ||||
|     // Precondition: 'firstDoubleQuote' must be the leading double quote | ||||
|     //               character of this quoted string and 'inStream' must not | ||||
|     //               be null. | ||||
|     private Token retrieveString(char firstDoubleQuote) throws IOException { | ||||
|         StringBuffer text = new StringBuffer(); | ||||
|         int startLine = line; | ||||
|         int startColumn = column; | ||||
|         char prevChar = firstDoubleQuote; | ||||
| 
 | ||||
|         text.append(firstDoubleQuote); | ||||
| 
 | ||||
|         int c; | ||||
| 
 | ||||
|         while ((c = inStream.read()) != -1) { | ||||
|             char nextChar = (char) c; | ||||
| 
 | ||||
|             ++column; | ||||
|             text.append(nextChar); | ||||
| 
 | ||||
|             switch(nextChar) { | ||||
|                 case '\n': | ||||
|                     ++line; | ||||
|                     column = 0; | ||||
| 
 | ||||
|                     break; | ||||
|                 case '\"': | ||||
|                     if (prevChar != '\\') { | ||||
|                         // we have found the terminating double quote | ||||
| 
 | ||||
|                         return new Token(Token.Type.STRING, | ||||
|                                          text.toString(), | ||||
|                                          fileName, | ||||
|                                          startLine, | ||||
|                                          startColumn); | ||||
|                     } | ||||
| 
 | ||||
|                     // this is an escaped double quote | ||||
|             } | ||||
| 
 | ||||
|             prevChar = nextChar; | ||||
|         } | ||||
| 
 | ||||
|         // the end of 'inStream' was reached before the terminating double | ||||
|         // quote | ||||
| 
 | ||||
|         throw new RuntimeException("unterminated quoted string" + | ||||
|                                    " - line " + startLine + | ||||
|                                    " column " + startColumn); | ||||
|     } | ||||
| 
 | ||||
|     // Retrieve a number token from 'inStream'. | ||||
|     // | ||||
|     // Parameters: firstDigit - the first digit of this number | ||||
|     // Returns: a number token obtained from 'inStream' | ||||
|     // Throws: IOException - Indicates that an I/O error has occurred. | ||||
|     // Precondition: 'firstDigit' must be the first digit of this number and | ||||
|     //               'inStream' must not be null. | ||||
|     private Token retrieveNumber(char firstDigit) throws IOException { | ||||
|         StringBuffer text = new StringBuffer(); | ||||
|         int startColumn = column; | ||||
| 
 | ||||
|         text.append(firstDigit); | ||||
|         inStream.mark(1); | ||||
| 
 | ||||
|         int c; | ||||
| 
 | ||||
|         while ((c = inStream.read()) != -1) { | ||||
|             char nextChar = (char) c; | ||||
| 
 | ||||
|             if (Character.isDigit(nextChar)) { | ||||
|                 // 'nextChar' is a digit in this number | ||||
| 
 | ||||
|                 text.append(nextChar); | ||||
|                 ++column; | ||||
|             } else { | ||||
|                 // we have reached the end of the number | ||||
| 
 | ||||
|                 inStream.reset();  // unread the last character | ||||
| 
 | ||||
|                 return new Token(Token.Type.NUMBER, | ||||
|                                  text.toString(), | ||||
|                                  fileName, | ||||
|                                  line, | ||||
|                                  startColumn); | ||||
|             } | ||||
| 
 | ||||
|             inStream.mark(1); | ||||
|         } | ||||
| 
 | ||||
|         // there are no more bytes to be read from 'inStream' after this number | ||||
|         // token | ||||
| 
 | ||||
|         return new Token(Token.Type.NUMBER, | ||||
|                          text.toString(), | ||||
|                          fileName, | ||||
|                          line, | ||||
|                          startColumn); | ||||
|     } | ||||
| 
 | ||||
|     // Retrieve an identifier token from 'inStream'. | ||||
|     // | ||||
|     // Parameters: firstChar - the first character of this identifier | ||||
|     // Returns: an identifier token obtained from 'inStream' | ||||
|     // Throws: IOException - Indicates that an I/O error has occurred. | ||||
|     // Precondition: 'firsChar' must be the first character of this identifier | ||||
|     //               and 'inStream' must not be null. | ||||
|     private Token retrieveIdentifier(char firstChar) throws IOException { | ||||
|         StringBuffer text = new StringBuffer(); | ||||
|         int startColumn = column; | ||||
| 
 | ||||
|         text.append(firstChar); | ||||
|         inStream.mark(1); | ||||
| 
 | ||||
|         int c; | ||||
| 
 | ||||
|         while ((c = inStream.read()) != -1) { | ||||
|             char nextChar = (char) c; | ||||
| 
 | ||||
|             if (isLegalIdChar(nextChar)) { | ||||
|                 // 'nextChar' is part of the identifier | ||||
| 
 | ||||
|                 text.append(nextChar); | ||||
|                 ++column; | ||||
|             } else { | ||||
|                 // we have reached the end of this identifier | ||||
| 
 | ||||
|                 inStream.reset();  // unread the last character | ||||
| 
 | ||||
|                 return new Token(Token.Type.IDENTIFIER, | ||||
|                                  text.toString(), | ||||
|                                  fileName, | ||||
|                                  line, | ||||
|                                  startColumn); | ||||
|             } | ||||
| 
 | ||||
|             inStream.mark(1); | ||||
|         } | ||||
| 
 | ||||
|         // there are no more bytes to be read from 'inStream' after this | ||||
|         // identifier token | ||||
| 
 | ||||
|         return new Token(Token.Type.IDENTIFIER, | ||||
|                          text.toString(), | ||||
|                          fileName, | ||||
|                          line, | ||||
|                          startColumn); | ||||
|     } | ||||
| 
 | ||||
|     // Test if a character is legal to be contained within an identifier in | ||||
|     // Lisp. | ||||
|     // | ||||
|     // Returns: 'true' if the character can be found within an identifier in | ||||
|     //          Lisp; 'false' otherwise | ||||
|     private boolean isLegalIdChar(char c) { | ||||
|         return ((! Character.isWhitespace(c)) && (c != '\"') | ||||
|                                               && (c != '\'') | ||||
|                                               && (c != '\\') | ||||
|                                               && (c != '`') | ||||
|                                               && (c != '(') | ||||
|                                               && (c != ')') | ||||
|                                               && (c != '[') | ||||
|                                               && (c != ']') | ||||
|                                               && (c != '#') | ||||
|                                               && (c != '.') | ||||
|                                               && (c != ';')); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,126 +0,0 @@ | ||||
| /* | ||||
|  * Name: Mike Cifelli | ||||
|  * Course: CIS 443 - Programming Languages | ||||
|  * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis | ||||
|  */ | ||||
| 
 | ||||
| package scanner; | ||||
| 
 | ||||
| /** | ||||
|  * A <code>Token</code> represents a token in Common Lisp. | ||||
|  */ | ||||
| public class Token { | ||||
| 
 | ||||
|     /** | ||||
|      * An enumeration representing all of the types of tokens found in Common | ||||
|      * Lisp. | ||||
|      */ | ||||
|     public enum Type { | ||||
|         /** A left parenthesis token */ | ||||
|         LEFT_PAREN, | ||||
| 
 | ||||
|         /** A right parenthesis token */ | ||||
|         RIGHT_PAREN, | ||||
| 
 | ||||
|         /** A quoted string token */ | ||||
|         STRING, | ||||
| 
 | ||||
|         /** A quote mark */ | ||||
|         QUOTE_MARK, | ||||
| 
 | ||||
|         /** A number token */ | ||||
|         NUMBER, | ||||
| 
 | ||||
|         /** A reserved word token */ | ||||
|         RESERVED, | ||||
| 
 | ||||
|         /** An identifier token */ | ||||
|         IDENTIFIER, | ||||
| 
 | ||||
|         /** An end-of-file token */ | ||||
|         EOF | ||||
|     } | ||||
| 
 | ||||
|     private Type type; | ||||
|     private String text; | ||||
|     private String fName; | ||||
|     private int line; | ||||
|     private int column; | ||||
| 
 | ||||
|     /** | ||||
|      * Create a new token with the specified type, text, file name, line number | ||||
|      * and column number. | ||||
|      * | ||||
|      * @param type | ||||
|      *  the type of this token | ||||
|      * @param text | ||||
|      *  the text associated with this token | ||||
|      * @param fName | ||||
|      *  the name of the file that this token is located in | ||||
|      * @param line | ||||
|      *  the line number that this token is found on | ||||
|      * @param column | ||||
|      *  the column number that this token is found on | ||||
|      */ | ||||
|     public Token(Type type, String text, String fName, int line, int column) { | ||||
|         this.type = type; | ||||
|         this.text = text; | ||||
|         this.fName = fName; | ||||
|         this.line = line; | ||||
|         this.column = column; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accessor method to determine the type of this token. | ||||
|      * | ||||
|      * @return | ||||
|      *  the type of this token | ||||
|      */ | ||||
|     public Type getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accessor method to determine the text associated with this token. | ||||
|      * | ||||
|      * @return | ||||
|      *  the text associated with this token | ||||
|      */ | ||||
|     public String getText() { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accessor method to determine the name of the file that this token was | ||||
|      * located in. | ||||
|      * | ||||
|      * @return | ||||
|      *  the name of the file that this token was located in | ||||
|      */ | ||||
|     public String getFName() { | ||||
|         return fName; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accessor method to determine the line number that this token was found | ||||
|      * on. | ||||
|      * | ||||
|      * @return | ||||
|      *  the line number this token was found on | ||||
|      */ | ||||
|     public int getLine() { | ||||
|         return line; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Accessor method to determine the column number that this token was found | ||||
|      * on. | ||||
|      * | ||||
|      * @return | ||||
|      *  the column number this token was found on | ||||
|      */ | ||||
|     public int getColumn() { | ||||
|         return column; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,4 +0,0 @@ | ||||
| <body> | ||||
|     Provides the classes necessary to perform a lexical analysis of the Lisp | ||||
|     programming language. | ||||
| </body> | ||||
										
											Binary file not shown.
										
									
								
							| @ -1,9 +1,3 @@ | ||||
| /* | ||||
|  * Name: Mike Cifelli | ||||
|  * Course: CIS 443 - Programming Languages | ||||
|  * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis | ||||
|  */ | ||||
| 
 | ||||
| package scanner; | ||||
| 
 | ||||
| import java.io.InputStream; | ||||
| @ -11,150 +5,48 @@ import java.io.FilterInputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * A <code>LispFilterStream</code> is an input stream that returns the bytes | ||||
|  * from an underlying input stream with all Lisp comments removed and replaced | ||||
|  * with newlines. | ||||
|  * Replaces Lisp comments with newlines in an input stream. | ||||
|  */ | ||||
| public class LispFilterStream extends FilterInputStream { | ||||
| 
 | ||||
|     private boolean inQuote; | ||||
|     private int nextCharacter; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a <code>LispFilterStream</code> with the specified underlying | ||||
|      * <code>InputStream</code>. | ||||
|      * | ||||
|      * @param in | ||||
|      *  the underlying input stream (must not be <code>null</code>) | ||||
|      */ | ||||
|     public LispFilterStream(InputStream in) { | ||||
|         super(in); | ||||
| 
 | ||||
|         inQuote = false; | ||||
|         nextCharacter = 0; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reads the next byte of data from this input stream. The value byte is | ||||
|      * returned as an <code>int</code> in the range <code>0</code> to | ||||
|      * <code>255</code>. If no byte is available because the end of the stream | ||||
|      * has been reached, the value <code>-1</code> is returned.  | ||||
|      * | ||||
|      * @return | ||||
|      *  the next byte of data, or <code>-1</code> if the end of the stream has | ||||
|      *  been reached. | ||||
|      * @throws IOException | ||||
|      *  Indicates that an I/O error has occurred. | ||||
|      */ | ||||
|     @Override | ||||
|     public int read() throws IOException { | ||||
|         int next = super.read(); | ||||
|         nextCharacter = super.read(); | ||||
| 
 | ||||
|         if ((next == ';') && (! inQuote)) { | ||||
|             // we have entered a comment, consume all the bytes from the | ||||
|             // underlying input stream until we reach a newline character or | ||||
|             // the end of the stream | ||||
|             while ((next != '\n') && (next != -1)) { | ||||
|                 next = super.read(); | ||||
|             } | ||||
|         } else if (next == '\n') { | ||||
|             inQuote = false; | ||||
|         } else if (next == '\"') {  // we have entered or left a quoted string | ||||
|             inQuote = (! inQuote); | ||||
|         if (haveEnteredComment()) { | ||||
|             consumeAllBytesInComment(); | ||||
|         } else if (haveEncounteredStringBoundary()) { | ||||
|             inQuote = (!inQuote); | ||||
|         } | ||||
| 
 | ||||
|         return next; | ||||
|         return nextCharacter; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reads up to the specified number of data bytes from this input stream | ||||
|      * into an array of bytes starting at the specified offset. If no bytes are | ||||
|      * available because the end of this stream has been reached then | ||||
|      * <code>-1</code> is returned. Also, If the specified number of bytes is | ||||
|      * more than the number of remaining data bytes in this input stream, then | ||||
|      * only the number of remaining data bytes are copied into the byte array. | ||||
|      * | ||||
|      * @param b | ||||
|      *  the buffer into which the data bytes are read (must not be | ||||
|      *  <code>null</code>) | ||||
|      * @param off | ||||
|      *  the start offset in <code>b</code> at which the data is written (must | ||||
|      *  be <code>>= 0</code> and <code>< b.length</code>) | ||||
|      * @param len | ||||
|      *  the maximum number of bytes to read into <code>b</code> (<code>len + | ||||
|      *  off</code> must be <code>< b.length</code>) | ||||
|      * @return | ||||
|      *  the total number of bytes read into the buffer, or <code>-1</code> if | ||||
|      *  there is no more data because the end of the stream has been reached | ||||
|      * @throws IOException | ||||
|      *  Indicates that the first byte could not be read into <code>b</code> | ||||
|      *  for some reason other than reaching the end of the stream. | ||||
|      * @throws IndexOutOfBoundsException | ||||
|      *  Indicates that this method attempted to access an index in | ||||
|      *  <code>b</code> that was either negative or greater than or equal to | ||||
|      *  <code>b.length</code> as a result of the given parameters. | ||||
|      * @throws NullPointerException | ||||
|      *  Indicates that <code>b</code> is <code>null</code>. | ||||
|      */ | ||||
|     @Override | ||||
|     public int read(byte[] b, int off, int len) throws IOException { | ||||
|         int bytesRead = 0; | ||||
| 
 | ||||
|         // make sure we are supposed to read at least one byte into 'b' | ||||
|         if (len > 0) { | ||||
|             int next = read(); | ||||
| 
 | ||||
|             if (next == -1) { | ||||
|                 // there are no more bytes to read from this input stream | ||||
| 
 | ||||
|                 return -1; | ||||
|             } | ||||
| 
 | ||||
|             int i = off; | ||||
| 
 | ||||
|             while (next != -1) { | ||||
|                 ++bytesRead; | ||||
| 
 | ||||
|                 b[i++] = (byte) next; | ||||
| 
 | ||||
|                 if (i >= (off + len)) {  // we have read 'len' bytes into 'b' | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 try { | ||||
|                     next = read(); | ||||
|                 } catch (IOException e) { | ||||
|                     // treat this exception like an end of stream | ||||
| 
 | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|     private void consumeAllBytesInComment() throws IOException { | ||||
|         while (stillInComment()) { | ||||
|             nextCharacter = super.read(); | ||||
|         } | ||||
| 
 | ||||
|         return bytesRead; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Skip over and discard the specified number of bytes from this input | ||||
|      * stream. This method may, for a variety of reasons, end up skipping some | ||||
|      * smaller number of bytes, possibly <code>0</code>. The actual number of | ||||
|      * bytes skipped is returned. | ||||
|      * | ||||
|      * @param n | ||||
|      *  the number of bytes to be skipped | ||||
|      * @return | ||||
|      *  the actual number of bytes skipped | ||||
|      * @throws IOException | ||||
|      *  Indicates that an I/O error has occurred. | ||||
|      */ | ||||
|     @Override | ||||
|     public long skip (long n) throws IOException { | ||||
|         long bytesSkipped = 0; | ||||
|     private boolean stillInComment() { | ||||
|         return (nextCharacter != '\n') && (nextCharacter != -1); | ||||
|     } | ||||
| 
 | ||||
|         while ((n > 0) && (read() != -1)) { | ||||
|             ++bytesSkipped; | ||||
|             --n; | ||||
|         } | ||||
|     private boolean haveEnteredComment() { | ||||
|         return (nextCharacter == ';') && (!inQuote); | ||||
|     } | ||||
| 
 | ||||
|         return bytesSkipped; | ||||
|     private boolean haveEncounteredStringBoundary() { | ||||
|         return nextCharacter == '\"'; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -19,19 +19,4 @@ public class LispFilterStreamTester { | ||||
|         fail("Not yet implemented"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testReadByteArrayIntInt() { | ||||
|         fail("Not yet implemented"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testSkip() { | ||||
|         fail("Not yet implemented"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void testLispFilterStream() { | ||||
|         fail("Not yet implemented"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user