From b8757273611000eab38782c5bd134a2c9ac15c7f Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Wed, 7 Dec 2016 16:38:26 -0500 Subject: [PATCH] Refactored code for eclipse --- .classpath | 10 + .externalToolBuilders/Ant_Builder.launch | 18 + .project | 23 ++ .settings/org.eclipse.jdt.core.prefs | 7 + ....eclipse.wst.common.project.facet.core.xml | 4 + src/error/ErrorManager.class | Bin 0 -> 836 bytes src/error/ErrorManager.java | 50 +++ src/error/package.html | 3 + src/eval/APPLY.class | Bin 0 -> 1696 bytes src/eval/APPLY.java | 74 ++++ src/eval/ATOM.class | Bin 0 -> 1145 bytes src/eval/ATOM.java | 38 +++ src/eval/CAR.class | Bin 0 -> 1108 bytes src/eval/CAR.java | 46 +++ src/eval/CDR.class | Bin 0 -> 1127 bytes src/eval/CDR.java | 46 +++ src/eval/COND.class | Bin 0 -> 1081 bytes src/eval/COND.java | 73 ++++ src/eval/CONS.class | Bin 0 -> 1091 bytes src/eval/CONS.java | 44 +++ src/eval/DEFUN.class | Bin 0 -> 1847 bytes src/eval/DEFUN.java | 82 +++++ src/eval/DIVIDE.class | Bin 0 -> 1192 bytes src/eval/DIVIDE.java | 60 ++++ src/eval/EQ.class | Bin 0 -> 1298 bytes src/eval/EQ.java | 45 +++ src/eval/EQUAL.class | Bin 0 -> 1539 bytes src/eval/EQUAL.java | 58 ++++ src/eval/EQUALSP.class | Bin 0 -> 1184 bytes src/eval/EQUALSP.java | 55 +++ src/eval/EVAL.class | Bin 0 -> 4754 bytes src/eval/EVAL.java | 251 ++++++++++++++ src/eval/EXIT.class | Bin 0 -> 860 bytes src/eval/EXIT.java | 26 ++ src/eval/FUNCALL.class | Bin 0 -> 918 bytes src/eval/FUNCALL.java | 31 ++ src/eval/GREATERP.class | Bin 0 -> 1185 bytes src/eval/GREATERP.java | 55 +++ src/eval/LAMBDA.class | Bin 0 -> 2009 bytes src/eval/LAMBDA.java | 108 ++++++ src/eval/LENGTH.class | Bin 0 -> 1398 bytes src/eval/LENGTH.java | 69 ++++ src/eval/LESSP.class | Bin 0 -> 1182 bytes src/eval/LESSP.java | 55 +++ src/eval/LET.class | Bin 0 -> 1860 bytes src/eval/LET.java | 116 +++++++ src/eval/LIST.class | Bin 0 -> 642 bytes src/eval/LIST.java | 40 +++ src/eval/LISTP.class | Bin 0 -> 1148 bytes src/eval/LISTP.java | 38 +++ src/eval/LOAD.class | Bin 0 -> 2093 bytes src/eval/LOAD.java | 87 +++++ src/eval/LambdaExpression.class | Bin 0 -> 549 bytes src/eval/LambdaExpression.java | 73 ++++ src/eval/LispFunction.class | Bin 0 -> 239 bytes src/eval/LispFunction.java | 44 +++ src/eval/MINUS.class | Bin 0 -> 1190 bytes src/eval/MINUS.java | 60 ++++ src/eval/MULTIPLY.class | Bin 0 -> 934 bytes src/eval/MULTIPLY.java | 34 ++ src/eval/NULL.class | Bin 0 -> 1145 bytes src/eval/NULL.java | 38 +++ src/eval/PLUS.class | Bin 0 -> 930 bytes src/eval/PLUS.java | 34 ++ src/eval/PRINT.class | Bin 0 -> 1115 bytes src/eval/PRINT.java | 40 +++ src/eval/QUOTE.class | Bin 0 -> 1029 bytes src/eval/QUOTE.java | 47 +++ src/eval/SETF.class | Bin 0 -> 1898 bytes src/eval/SETF.java | 112 ++++++ src/eval/SYMBOL_FUNCTION.class | Bin 0 -> 1474 bytes src/eval/SYMBOL_FUNCTION.java | 65 ++++ src/eval/SymbolTable.class | Bin 0 -> 921 bytes src/eval/SymbolTable.java | 90 +++++ src/eval/UDFunction.class | Bin 0 -> 2291 bytes src/eval/UDFunction.java | 122 +++++++ src/eval/package.html | 4 + src/main/LispInterpreter.class | Bin 0 -> 1689 bytes src/main/LispInterpreter.java | 91 +++++ src/main/LispParserDriver.class | Bin 0 -> 1026 bytes src/main/LispParserDriver.java | 65 ++++ src/main/LispScannerDriver.class | Bin 0 -> 1452 bytes src/main/LispScannerDriver.java | 69 ++++ src/main/package.html | 3 + src/parser/Atom.class | Bin 0 -> 310 bytes src/parser/Atom.java | 46 +++ src/parser/Cons.class | Bin 0 -> 991 bytes src/parser/Cons.java | 111 ++++++ src/parser/LispNumber.class | Bin 0 -> 914 bytes src/parser/LispNumber.java | 67 ++++ src/parser/LispParser$1.class | Bin 0 -> 874 bytes src/parser/LispParser.class | Bin 0 -> 2288 bytes src/parser/LispParser.java | 192 +++++++++++ src/parser/LispString.class | Bin 0 -> 190 bytes src/parser/LispString.java | 34 ++ src/parser/Nil.class | Bin 0 -> 695 bytes src/parser/Nil.java | 104 ++++++ src/parser/SExpression.class | Bin 0 -> 632 bytes src/parser/SExpression.java | 122 +++++++ src/parser/Symbol.class | Bin 0 -> 362 bytes src/parser/Symbol.java | 37 ++ src/parser/package.html | 4 + src/scanner/LispFilterStream.class | Bin 0 -> 682 bytes src/scanner/LispFilterStream.java | 160 +++++++++ src/scanner/LispScanner.class | Bin 0 -> 2966 bytes src/scanner/LispScanner.java | 320 ++++++++++++++++++ src/scanner/Token$Type.class | Bin 0 -> 1095 bytes src/scanner/Token.class | Bin 0 -> 719 bytes src/scanner/Token.java | 126 +++++++ src/scanner/package.html | 4 + test/scanner/LispFilterStreamTester.java | 37 ++ 111 files changed, 3967 insertions(+) create mode 100644 .classpath create mode 100644 .externalToolBuilders/Ant_Builder.launch create mode 100644 .project create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 src/error/ErrorManager.class create mode 100644 src/error/ErrorManager.java create mode 100644 src/error/package.html create mode 100644 src/eval/APPLY.class create mode 100644 src/eval/APPLY.java create mode 100644 src/eval/ATOM.class create mode 100644 src/eval/ATOM.java create mode 100644 src/eval/CAR.class create mode 100644 src/eval/CAR.java create mode 100644 src/eval/CDR.class create mode 100644 src/eval/CDR.java create mode 100644 src/eval/COND.class create mode 100644 src/eval/COND.java create mode 100644 src/eval/CONS.class create mode 100644 src/eval/CONS.java create mode 100644 src/eval/DEFUN.class create mode 100644 src/eval/DEFUN.java create mode 100644 src/eval/DIVIDE.class create mode 100644 src/eval/DIVIDE.java create mode 100644 src/eval/EQ.class create mode 100644 src/eval/EQ.java create mode 100644 src/eval/EQUAL.class create mode 100644 src/eval/EQUAL.java create mode 100644 src/eval/EQUALSP.class create mode 100644 src/eval/EQUALSP.java create mode 100644 src/eval/EVAL.class create mode 100644 src/eval/EVAL.java create mode 100644 src/eval/EXIT.class create mode 100644 src/eval/EXIT.java create mode 100644 src/eval/FUNCALL.class create mode 100644 src/eval/FUNCALL.java create mode 100644 src/eval/GREATERP.class create mode 100644 src/eval/GREATERP.java create mode 100644 src/eval/LAMBDA.class create mode 100644 src/eval/LAMBDA.java create mode 100644 src/eval/LENGTH.class create mode 100644 src/eval/LENGTH.java create mode 100644 src/eval/LESSP.class create mode 100644 src/eval/LESSP.java create mode 100644 src/eval/LET.class create mode 100644 src/eval/LET.java create mode 100644 src/eval/LIST.class create mode 100644 src/eval/LIST.java create mode 100644 src/eval/LISTP.class create mode 100644 src/eval/LISTP.java create mode 100644 src/eval/LOAD.class create mode 100644 src/eval/LOAD.java create mode 100644 src/eval/LambdaExpression.class create mode 100644 src/eval/LambdaExpression.java create mode 100644 src/eval/LispFunction.class create mode 100644 src/eval/LispFunction.java create mode 100644 src/eval/MINUS.class create mode 100644 src/eval/MINUS.java create mode 100644 src/eval/MULTIPLY.class create mode 100644 src/eval/MULTIPLY.java create mode 100644 src/eval/NULL.class create mode 100644 src/eval/NULL.java create mode 100644 src/eval/PLUS.class create mode 100644 src/eval/PLUS.java create mode 100644 src/eval/PRINT.class create mode 100644 src/eval/PRINT.java create mode 100644 src/eval/QUOTE.class create mode 100644 src/eval/QUOTE.java create mode 100644 src/eval/SETF.class create mode 100644 src/eval/SETF.java create mode 100644 src/eval/SYMBOL_FUNCTION.class create mode 100644 src/eval/SYMBOL_FUNCTION.java create mode 100644 src/eval/SymbolTable.class create mode 100644 src/eval/SymbolTable.java create mode 100644 src/eval/UDFunction.class create mode 100644 src/eval/UDFunction.java create mode 100644 src/eval/package.html create mode 100644 src/main/LispInterpreter.class create mode 100644 src/main/LispInterpreter.java create mode 100644 src/main/LispParserDriver.class create mode 100644 src/main/LispParserDriver.java create mode 100644 src/main/LispScannerDriver.class create mode 100644 src/main/LispScannerDriver.java create mode 100644 src/main/package.html create mode 100644 src/parser/Atom.class create mode 100644 src/parser/Atom.java create mode 100644 src/parser/Cons.class create mode 100644 src/parser/Cons.java create mode 100644 src/parser/LispNumber.class create mode 100644 src/parser/LispNumber.java create mode 100644 src/parser/LispParser$1.class create mode 100644 src/parser/LispParser.class create mode 100644 src/parser/LispParser.java create mode 100644 src/parser/LispString.class create mode 100644 src/parser/LispString.java create mode 100644 src/parser/Nil.class create mode 100644 src/parser/Nil.java create mode 100644 src/parser/SExpression.class create mode 100644 src/parser/SExpression.java create mode 100644 src/parser/Symbol.class create mode 100644 src/parser/Symbol.java create mode 100644 src/parser/package.html create mode 100644 src/scanner/LispFilterStream.class create mode 100644 src/scanner/LispFilterStream.java create mode 100644 src/scanner/LispScanner.class create mode 100644 src/scanner/LispScanner.java create mode 100644 src/scanner/Token$Type.class create mode 100644 src/scanner/Token.class create mode 100644 src/scanner/Token.java create mode 100644 src/scanner/package.html create mode 100644 test/scanner/LispFilterStreamTester.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..1938c4d --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.externalToolBuilders/Ant_Builder.launch b/.externalToolBuilders/Ant_Builder.launch new file mode 100644 index 0000000..dcc6b4b --- /dev/null +++ b/.externalToolBuilders/Ant_Builder.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..d1cb933 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + LispInterpreter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..0c68a61 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..f4ef8aa --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/error/ErrorManager.class b/src/error/ErrorManager.class new file mode 100644 index 0000000000000000000000000000000000000000..a7f40c100059f6786697bf857f3f1d8e1e5a2915 GIT binary patch literal 836 zcmZuvZEw<06n^dsZRtR*={e7N?m748?{7Zy<{OykYHFX4AA7ScM@`9ymjfJ6@Cb4uwRt5`(s}X;*gY zrfoJDbZei#<3^7=9mDqAuG3j(P^TF$7-j>vWm?wOwu*ay1GQK6nq@M`&$>?6d(I$b zvQ36adGK0L+m3LA%ROPb?!aYO$o$`>;^!x9kMF&$@`DE7?Fj`daV#K3s)S!?1m#uk z@QxssXu4f2^(SY6&g3XR4)UHZjtb+^+L%J8m)Y9g7keH_O1JZU1*>t~hoK-JM*(XJ zigB87DUOGDG+`|IjHl(3Sumu6kSC5jqbi0&Qu1=(_Bj#DZ>G+ZGj7)oU3j8oJsS$0 zOgh~0{m>I6LK++r`}`!kJ1}ar6pso7@6&4L0zLnR8I%J*spnAL8DfIXh@-AQjSS5l zOPHaj1w?TfaU?*mhtLep6Hem7304T}Asit*7s3|_&xf!?9JFnu$X+5wpNaW>a$mtd zkpsl2i0YB59+kgCZb>V4E0VKYQC+c*p>BRgZ1oE?KUIkw XW7el*NRv%M(l!)a{e@++^Z|bW5QMN= literal 0 HcmV?d00001 diff --git a/src/error/ErrorManager.java b/src/error/ErrorManager.java new file mode 100644 index 0000000..255c61d --- /dev/null +++ b/src/error/ErrorManager.java @@ -0,0 +1,50 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis + */ + +package error; + +import java.text.MessageFormat; + +/** + * ErrorManager 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 level >= CRITICAL_LEVEL 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); + } + } + +} diff --git a/src/error/package.html b/src/error/package.html new file mode 100644 index 0000000..b8e7489 --- /dev/null +++ b/src/error/package.html @@ -0,0 +1,3 @@ + + Provides a class for managing errors in the Lisp Interpreter. + diff --git a/src/eval/APPLY.class b/src/eval/APPLY.class new file mode 100644 index 0000000000000000000000000000000000000000..2b22463a8213c45d337dde155d9f87c785e8c853 GIT binary patch literal 1696 zcmZuxTUQfT6#fp$%o&CeC0sN}?O1Ik(3I9HwLz=_BG`sY3D9CM_K+Onz+@&(Ca6D! zr@nM8U-cznm9<*mx|V;%f8ayuKDm$xJj|YR_WAa=ujjn^@2|fB+`>~6*D=ZQm5DA) zDsjie*GOhiC%WAvA@x6%=teVJRO^I~_8!C=F27WN`BgZC#v9!MUIJr8XVPFp#&dvH> zIS^j3A>4`#QS4m|`d!C!f_n_1(bxtelC@Wl-_%ngX?k9YnsIHSTX&^aB)ZMi3wMD`H4(Wa=iRZ#c^}8L=gqP zZ(9)9qIE%dluBq@K4rLUi&DN)kX}%>^Uj|1?7+9{#ECjSYas_Jz;K&-wc-U%L8hK% zWigui;R*7TmIVhp9J?H@g#zf%#}30_J;$^tY~@6|R2GW(oug!-jKD$#dkp;* zFDJJhPv-3HikDRmYzE#8iJ{ka%C_eRwy<5N95D1XsGV~0K@-n#p&f0b5Dbx4_1f;K zzzy5f()`*2Lw8;VY3b#IC&X}~(KIfDqv?~hQ))!UkD;AYaMolfv`&*Gy&OaQEV@%3 znjNH}dJn(6wIj0u&ELt0+IS=ITe%O6o(2-5PWjFXnvNklKV6;{B1Z^K)w)=}6p!93 zZzB+@UA>a2jbxfyQ6CXXd5uJ_(TZYJSW1^+ yg5)yz5pE*P@j1sAj6RUKc|^yZx-QajeEAN;N04wAQlq2YHhf&T$QxtpZ` literal 0 HcmV?d00001 diff --git a/src/eval/APPLY.java b/src/eval/APPLY.java new file mode 100644 index 0000000..f7fa819 --- /dev/null +++ b/src/eval/APPLY.java @@ -0,0 +1,74 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * APPLY 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 argList + */ + 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"); + } + +} diff --git a/src/eval/ATOM.class b/src/eval/ATOM.class new file mode 100644 index 0000000000000000000000000000000000000000..b5cf96e7bf83317f1436ad83e5cc75e3b0d94a42 GIT binary patch literal 1145 zcmZuwOH&g;5dH=>+07D!tULr!qxc9!j3B-eKp}>QCP7J{DqgH1jBzp9U6T#MPx0i% zDz4%op-h$D{YjQ3_9lcNaG0L$-mkxzue;~h-|s&FOkz#N1q4)#U{pp>#%&p63htqtcmvC7|)Qe|`F?hrl&xdBy z%L#^#W8B1Y=%scF>n5EoIUpx{-Z2Xd{hNG?hw|LWg;I7=H*#}jJ-;D}1hq}m@5LfW zq*UO>4yk!7J~9mYc`;Wm2*WPR7q74)BjrUJs|>!nmbhNB=F3LbK{Ir>s2Z1K(3-+pMI-Hv+*ooUy+~Eb z2|F%~oc)d%PSl(<^#z|A8^8DHmANP;g8OKj9+Ey|u?8tqgDa!CtB`|LdU-W?GF7NrM+M#?=?fIC za~Ce{9JyK-nXwAGEAWM-8nn!SRK@w9!3uhk6z}~6&o}h#!o83Ful2*PkqyIjfC)%4 ghGkr5v_R&@0p03&tc_waZvMvLANXY4nxh5$19eLc-2eap literal 0 HcmV?d00001 diff --git a/src/eval/ATOM.java b/src/eval/ATOM.java new file mode 100644 index 0000000..fbee068 --- /dev/null +++ b/src/eval/ATOM.java @@ -0,0 +1,38 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * ATOM 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()); + } + +} diff --git a/src/eval/CAR.class b/src/eval/CAR.class new file mode 100644 index 0000000000000000000000000000000000000000..86a7ae3bc72bc9baddb108cc4a015543278d0cc3 GIT binary patch literal 1108 zcmZuw%Tg0T6g^EQ%rJ!4$ipD&C_Vx)Mi5aGP$7nghF}q-DsHSHv~h4Ulge}uzQAvA z<;E(vx=AckrLNuhKb9rlNr*vU(YO2FIp@rMbpQDCvoth1S5wRKzi(U{=9B8TT2K^wX8+ zb8Cwk2DZ%5m2hlV7`E6jtTOje4ve9F#1C3;#S(X2)3M{En-NCt)rwJEH#RNaEM-E*0~vDxoW(gA^8qCAkW%71h80cB ztub^Sk|vP@FSA$Jbm-SU!g$=IXBHTSwv8PlY8iGunh_<_&d--kYm1jCSK&B%0E<|n zbHT9pi2Q=TW(ev=DPJydTey1O+~Kw^9Gzrib@XxokMNjbxFx(+wuM>X$=w_;3aTxD z6jtgrq_N82uX7o?b<@>tN9cxbnXX{ys~43r-Qq&o&Us9R-j-}5Uk0sNVyk=9g$6g7 zUR6vKk0?}DfTA(8Evy8(mO2GAZ2Ut zXSMb!CAR 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"); + } + +} diff --git a/src/eval/CDR.class b/src/eval/CDR.class new file mode 100644 index 0000000000000000000000000000000000000000..128383f1546a4df715f8a67503d0a7bf68d8f133 GIT binary patch literal 1127 zcmZuw+fvg|6kUg=O(;bma8>WdTFSc7SjX-*Noz;E!$ z7iWCcm)5Z}>a#EYkK>3trL_o5CVQWKvewGJob%()m#+XOk@X{pupi@yh`1&qD&o3? zm>*u;@I$~&5fgrNA}ryS>nA1LmM|sZjvL)|%{>v*e#i&-xF0i^b(wP#?n`(eVxB=t zKV5r1pIOc_uvLccgk?HhHTkA$R5TAI!Weurx~cOy22Uuw$si=Gf<`W{8V18yC}pc< zM=Qr%YCPPEvdLY$tT~QunQ_w1ay9>IO|>`FEkkS7Ga+I@L?VFmxFBLNfFzbEC2dDF zVu{5JL)Rf`5@|-+z0#INzxEKumu9vjrZeFuF z)fPY+>x~*7<4FJ+tTT8U0t}}V-BC=7E2?7X4rl0VRF={md#PgPT{=T=Tl*ks2Dw#d zyM@$>18y?Cyg{XQ7B!yI%p!kD3P&bDV;l&jj>^W}(MA4250B@hk-2D}YTKGwV2GY1 zckB<%Zqu~?!>?~`Yk5uw<7h^0yu__m?fs$SKvMKky$O{jIY{4+w}%j3x5akjj6Q4P z3uTPLL$`=dF^1_mOMZl+4xFQxxyO#ILOXrr8F}w`4eS#wT*@deHb4KQOXsD%H<8ci zm>m(`VWkcsSBEzz`)Uv)HM&T3bmnUC%Ux9jMuhi}wCP?IX3p#||>UL(CRvQrTDF#$ouB@vey ay&!XCpYlGu*Fk$CuKvRCZw!eD0e=Bh$_9u4 literal 0 HcmV?d00001 diff --git a/src/eval/CDR.java b/src/eval/CDR.java new file mode 100644 index 0000000..0cc281e --- /dev/null +++ b/src/eval/CDR.java @@ -0,0 +1,46 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * CDR 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"); + } + +} diff --git a/src/eval/COND.class b/src/eval/COND.class new file mode 100644 index 0000000000000000000000000000000000000000..29bb23a981149583856af2e1f849087e741e680e GIT binary patch literal 1081 zcmaJ=T~pIg5IvVRNl63R%7;b4R8&djOo16uW^jB7>75!3X>1aPpCUiN z@x=#xDU8gh&p!JH{29E6d)oq)am>T+-rbYkbI&F}et-E2U;>LOx{*{N_+O%0!%Rtr0Bm3y95ai$nLR(->KyJWa8j18OD z8xJXXz!2lxh8-9_&sEF87I%EFKIWB%9`tH>2wlM=4OvWSn8u8TS&YB}Y(z_LrcN<{N3%kx>? zw2i>yx`sUFg((nI-Fs6B?2^90bwjr;&)2Ykr-JA+hIVm}jCi?ur%ciE+=aj~8x!MA z#x1fiNKRneE`!=EE?XpMtjztFj`c3!i;m|Tj!9Z~rcQMw4CyHoC~pwop0i3z>k~wY z5RyrIp&<>1g|%Ffb|=^}q)&I(`tIqd)+CKIT$ei~hOt!fynM9w^Qoqy#N;ph%El%) z{r}=4exn^1B{I@?$jhTOD7$z)N^v%v2vg|*k*t)E2>AiyA|qwxgp^eh zavj>AkO|wwQL=s@$j9Sf31x4rhW1^wr^%~(V%Q;~>xaCOND 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/CONS.class b/src/eval/CONS.class new file mode 100644 index 0000000000000000000000000000000000000000..c95ed567a8b46155f1531cca445ea276e0ed8e14 GIT binary patch literal 1091 zcmZ`&-%}D%6#g#kvg?Y4n?J&^Fe_0a%; zM}vf@f>{lHm{M_9_&F8#RLrZmFQNy+JXG*VgMNyCERtdx+=we!U{KR9H(xDpuVon6 z2E#zYwyKU{IlD%&#@!^r#o$>mEz?Dp+Kg{7-5od04LSYSpx@xEBG8D_HX437#_a@dKk6O>Ct} zZ-3XhbWl6W9F_KL(j^Iy$X*s^g<*8xI546`!zx5GPQ|neD>bv2=M{oFwjJ~$foJqx zGOQ!2^fiCSFcvf_g<6SQPBmCC54aU{?4aO{wctrFRF!;{$PnA(^r?6ytZD*aTE^sHst%CE0z&)2nO&boS zdKu!PQQ<$(?i=kisC!MIJx00Atvo~IUv%eAXy0DE2fwwq&vOoqL9e1Syz1DUGKWIv zfyC&cdJ_h9W`y=TeeD{GHX>ia1P$^iO(``2m*H=Dnps?-b(&3#lf6p&gX9@`d8Pq& zOdleJ8q(fArr*g!Yj*fET#EtuJ=U9$vQ5ZY-P3>)ZqSd?L|?W6P4BP68<0Oh)dxO8 z)-O<~UnCQ$!&k>(Olm^U`lSXgeGAtylqNI$9a2p4OBBXr!5s0+MER*DV}k4~+$WfW tq~N-ONk%Wo+&Ce9-D@sdQ*iSq#(c{p|5jVRP8GX|#WO=^jR;nHegi-}`C9-0 literal 0 HcmV?d00001 diff --git a/src/eval/CONS.java b/src/eval/CONS.java new file mode 100644 index 0000000..db967a7 --- /dev/null +++ b/src/eval/CONS.java @@ -0,0 +1,44 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * CONS 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); + } + +} diff --git a/src/eval/DEFUN.class b/src/eval/DEFUN.class new file mode 100644 index 0000000000000000000000000000000000000000..fd9c7076ff8de2d058e40a7c72577f8da7f2a7f8 GIT binary patch literal 1847 zcmZ`(TUQ%Z6#fpmoMAfL($bpR+9|XOjTmjKVkor~!o`NP5-x_SI3$NKG|Y^d6AJoE z+DD&#P#+SOtkwGLZ>nAHGf4~toQHGS``fo~?=yeD{qq%oyZBkhFz)Dd`jq1{j?X#9 zHGH8Xf|QOhCOGct=*ArllWM=OmM_)vfMZHWUjz0~$24X%q&3VcvpIF2*RY`DD?HMW zQTw8fEFS21j3?dr8cP~-I+n4*v8uzwn$mp3k!R2r7qS~uOLI8}w!qLc?K-}+9Jy+h zt0F{+hZv&wY{!=O8A2nYs|?|3wy}IJdlljPw(Crg z-<-4x&lW9j+1e}%j`g7arwjvPk0M!8OjSzNUExSS2(xZr1fv|^8u$+1Gw2GIoJr5F zWEsvK3rMb;x7@+*rb`J$0+h1fP|FVtmv*c@D_ORjQZgqiwo`gowaZ0OVHlFGYi^0> zrqzmWmh3&@n9?-^H!0JAg-x{-3=~0iUv7I_syfo%73uwg@FW##U<)NG&cHTqGw`Mh zhJMrbO~;j{W%@yy25giJ>?l}oTUoY!$??oU8M_RFZG~5HJy9{0-hcy_!{c~r;73$A zd;=0yhO28+OWB3&T*|D7qS&IQIVE$e>J(INCdZzE=h$HA3&>oVnQf{RP5TB8@KduN z$&BrLEiFT=#c;c&1Po}XO1qq#xBP8tEj1=^oJnWrmggC|OG0LZQsuNz~H2q>h%<;>@XzH=uV5H;JIX%Vg? zME_fW9xQI)ChhOjtqUKJoT;A+t+z-rKs%#7a;pyZI~|ls0v|TiEDuh9V6dBsLv&4E ziT;ASM+oPS5Xr})b?`(TTJ{Lt`8xF2xf+bI8hUEzO@)upmyd_*=zpE4VIWKL*h>s6 zX$yY736EW%1KBjOgMT5M3dh4_m5Rh8HC%j&8=ZDa-V?jjHjGEe>=5s~_&;pC1DlGf z5J510h|4K0u2GKf)^OzouKj_ltt{VbWJwB@V-43DxFeW(g^x$$ypHQN46Tj*7LYea u>kuMuFu~p+!ST^Q80SdRA@LTI!HF&(6TzS0c7ta0(yqGD75bG{`u+u@a?>mT literal 0 HcmV?d00001 diff --git a/src/eval/DEFUN.java b/src/eval/DEFUN.java new file mode 100644 index 0000000..c435737 --- /dev/null +++ b/src/eval/DEFUN.java @@ -0,0 +1,82 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; +import java.util.HashMap; + +/** + * DEFUN 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 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/DIVIDE.class b/src/eval/DIVIDE.class new file mode 100644 index 0000000000000000000000000000000000000000..edb174508e08af4bbc6571338a25a4a86c40deea GIT binary patch literal 1192 zcmZuwT~pIg5IvVRy&(jp<;#E{K@iKAMMc4apcK$b3rZbk>RTwW6AVeFO%eZs|A2pi zFYSz-QJ(!XzUm9QH!Xs|%iiqnxqHv<+59;E`VGJoHWc(@SV0JPIpQ26GDa1IF(yLe z91|S(6trSkMnasE!rT|;fdaV!dnm9|3LfDx$Fzb@%n0*DM3M^nFe_tD##4@Yjs=Fu zoaI>lJVPixvdIumx!Wck1;e%(2ICpeD3#4pBIP>e*^v`3x4iF_%yQXsomqzVoNp99 zWDW1Fv1OYa&jRw(^n!}(xS`@X78%;kRH8dgFZXG8%cYlCLSR$EEHU)$7<)#-Hk@K& zqvH71uDQHlFg>5%W9U6i=KPZ76c;O&y=|5lZu+jPzc)YXMyXiYH66dK7p* zBy|Mc!gCJ8LSdz6&TtUIo+8@dyKsY`RuuoFw^&GgbTl?yykY^CB98uVi)ouAH-L2@d#?FAydW9W`& z&i6Pg#2Nc1$5{a`6GfmShUb~iHp9eaGc-eOwLNIj2 zF9NAzq-gpngB0qa{KfuH5Zi>{jY-lhWV*Cz*cDnw+RZdAWjrnVk_xno9tLQa`{}m< zTEN7fk-bS?lukycG+G1uBJ$*tXpJDI@haM@xKhK_?{udlOD1}R&>F>K2lzaGgwAAmBB&Otqcb1Y!c}zHHFO_R zv?D2LQh;30Bms>GOaRd$ODIVIDE 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"); + } + +} diff --git a/src/eval/EQ.class b/src/eval/EQ.class new file mode 100644 index 0000000000000000000000000000000000000000..83a270ce6197e64268c8fe039f838ae470c8726e GIT binary patch literal 1298 zcmZuwOH&g;5dH>sGn-`3 z$yGfhmQ<-{e~%{*XzxM{f`{#%p8fipe*Red@)f`kgpPfP=s1o6juRYFj*}Wr=}BYtALt|Ng_ zjxh!;H9NU*ZF(%tz$O@WjM!G$5tcJ2@)g-kVKp)ME}E9on;*40#%X)T09OE1l214lJxMAQX zk_=ofi+nUO#n7^enK(AA^sB<6O)obkrd-cSSELv^pNeG>%?m3RO*gQe4BWzPIv0fXiZXdDUoh+qiBhgokd{*p<;-Pig&aGSn2LE|BA*78rK`a^U9lXq zAQLaMvglA^24*m8U=Fih7I$!$BSSeEn8!T>_wj(^p@9WFVrciWN}A>3XvNC9-VALG z>h+Kr0`(*t<)b>R`zBIjGvf^YoOF`X$~jMnVN3O?g}cMat+a8sZIQpw&8_)gyIizS z6pPYYVi@=z-L@AtYE7N~2Y+kvsmwYw6k8)|;5Emt=iU+C4kSh&S2-(n_+1E`-(Sd^nkwcY|5m$Yo~Z-E%SLr zPI$YLrDfRJ2#qjt^q`q`8KCh&H};c0;O-I*(#PC!CwYi&+DS9g>aiNwM>@DJz3AKc z{gal}M|W=`pV4%wTYZc1RVbNNsF{GT1|F%=0tW-nK6}cdtRe2sCv4a%ue^*S;gMh@P9&Z z1-{Sd`Y;ew-*2|Pm=BX2h4veRP&kfo9A)%@MEEx)v-z%x?l}5?p=%B2IgSyI0` H@g)8L$$>El literal 0 HcmV?d00001 diff --git a/src/eval/EQ.java b/src/eval/EQ.java new file mode 100644 index 0000000..0227525 --- /dev/null +++ b/src/eval/EQ.java @@ -0,0 +1,45 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * EQ 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()); + } + +} diff --git a/src/eval/EQUAL.class b/src/eval/EQUAL.class new file mode 100644 index 0000000000000000000000000000000000000000..3fc65a843c2681df0ab4fad4aac45cc71a7c7746 GIT binary patch literal 1539 zcmZux-BTM?6#re=&D|^uB@tQ|sHUwSfiy;Itr|)dFa$c**bf2cD)i0AGS5<_Q_bMCqKcfQZrzyJN?PXL$Um^h21iFc6V zc$ecnj!OpKH=*OQ2@M}`Trm+w(!hs`e`Mfe18D>EO1i4Z0>?EI(E$I6Qu@@yB9=@n z<1-V($b`w-brUOCHL->T6QAP?jx2+b+giW7xUrIFU~3Gc%Qd&@3D?^em6jZ)0EZYt zR~^^!t}zV9XSW%&9@QJN*>q~|JlV~AqWEB4 z)HlU$MRxPN!m-Ygvv3|4IBr<@5;qx4xhE>A%+0Muif^RPIGH(;@{g;#HFB=|D5bxl z2qkgmzSt9~ig3%Ryw`Bt@>0vGlw^bA^=h@4g-vYHxhmYpl+Qi+J;QWNG|H{2biHP* z?CeQ5=G9`p;k1w6wr~r#8K!!sH(IXeRAuH-QPw@m&_V$_7VcojPvuc=LXDk_X9vyBt7aySq5TbeSrZjHB4Z4XCXT6p@kX!XRIDTD;z*CL_;0$M2Ef!2M8BBFry=FSTp)l7}3#Z z(4%7{Mo$q*wlUsDB&{7FTClYaUU{BqVx4V~1bepbb2q8pLbk3L zw?hhI*j%x&k|xupk|xt5b1Ed;u*3T}L-DlnYT63!OnanvH)>nI!~O*kd(`J)qR$Z8 z$JDRnd0M%hZe!*N`X2mpyiN267>Bq7jU&!6%jgdxbB9!?{<|T%<4F92sYCpPv19Z_ aQs4+^aG-PV2P~0zNPa?tD!_z#1O5X|hhe|~ literal 0 HcmV?d00001 diff --git a/src/eval/EQUAL.java b/src/eval/EQUAL.java new file mode 100644 index 0000000..0e4e02e --- /dev/null +++ b/src/eval/EQUAL.java @@ -0,0 +1,58 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * EQUAL 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()); + } + +} diff --git a/src/eval/EQUALSP.class b/src/eval/EQUALSP.class new file mode 100644 index 0000000000000000000000000000000000000000..4cd829e798f871b4449006da93bb2c633b31cdf1 GIT binary patch literal 1184 zcmZuxTT>EY7=AusSy9q6}6Zv=QYzVDLH*lGZouX z=E91M7?!wsA>$>MWxT?Qj5t;(Ul|FWq_>e)TrU-p<$PKz%1B~W#v0aT+=L=xLq-al z)GT6T=v4HQVp_JMDrODOAZvT75sIyEEyPo6L|Hp>!lkmAsh8k8t^T};41!rUj6zL? z*9<*@_{BOST%F*V9?c3|r3y#8)Ivcsvka40(Ortr=p+gHAAU8xt7UA`{$fVwc(-lU z#bD?TTm}-OE2r5}l~n2_|K<8m5m`cr^;S|Z7&W@%3|*TQ0=kK6TQ$lwr8Kh33{rzH zsnaNV$-8Ch@5TFg~PY2kGRcmC-7USHV7UKOIT- zhWi%;h;;WOSV7AHrjFp)If8S?Csg4IRv{*i;HDeTP8E``wE}sfg0>3UtLXSnZ#olX zyvJ}P>E3q$b>bLZVdrFxP5g}RL)vzR1;0>p5BUY|cln(a^!Qz5KEg9jklw>D=sRqV xb&X>2S8YB&?HUm;0(dgb{#tcIWCtNkpI}79EfK>aM*i|&5A8?(!10@^$3G*PA94Ty literal 0 HcmV?d00001 diff --git a/src/eval/EQUALSP.java b/src/eval/EQUALSP.java new file mode 100644 index 0000000..1c6fb65 --- /dev/null +++ b/src/eval/EQUALSP.java @@ -0,0 +1,55 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * EQUALSP 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"); + } + +} diff --git a/src/eval/EVAL.class b/src/eval/EVAL.class new file mode 100644 index 0000000000000000000000000000000000000000..a661ef5ab276ea97fa34760beb47bb28cadfbb25 GIT binary patch literal 4754 zcma)833yyp75;DXChz6twP`0!OWM*7P}(dFVJT3Ov@l7g&Ctmt%}iQS)@d?LhfZcf zW~MBPq9}@@s3;mYP|=E34WLQnDO5#J+;QJ<-}hZ=Dg5`ncW0(e_&&dH=DqWud+s^s z{`cH_-jl~4egwcKag_-Tb~WnpDH9#|w2ns%JZjt1|FBnCv<$l zB>tj_yYQq5KfWX%UpDa-d{xKSOgj3yiCgdu9ZyMM%f~lO+=Oo#__nnDj*jn|SOwd_ z_vHKg27X}RhX#Hm(U0ZhX&pZ?u}((u$Da)R*}z{6{8g^v$|W<8f9d$QiLEl(4*bW! ze|0=#qDu}P)$uqCpocP2?n6Wr)?fI8_orv_=vtcw;CcSv!gE?Q08DaEr4(WZ;DWgQTmql?@FW#$x7C^5UA=* zWm5UA0+o$Ty9BiE>?p%78B6AsD=*jj#-{nXFi7V@`u{)2#p!JJK%tnoz=p>8>uXwI zfdZC0HFo3p-fUW+alwfbiOF1YvMm<6VPZ0w%aMELyeO7Wj2s}_-r9^*t|yz%Cr7#R z#)vmXvenVFM;GUj7D=!`b8)cTUz3_quH>ANM4EHXD9&*mE@aFLffoc1zb-a$T{2i9 zkxz0%^SpEfYLzB9IVP0?t6#vY6N5Y7Ig)nv)xy1akA=5k$`a>`3j~(VD-~{iG#p`M zOI#>6>*69yv%7AZ0v#_3vIY>7*7za@gA%M#t9hh$kIB)SA@ z%2>4UVH~!^HnE+>?Zgl53PvnU;{i+b%F@(a#l7NEffde~C@b%-LMlC)oTODgn+;fE zhlo%fPh@Un>id${3#<$zCdUfn$xJ>M7)u>YW&-(aK)P&q%=;`675y|Tc^)ie@~QD; z=!TKxgglUz7!W;{*vWNZMy53=x^xk<@Ilxu4h18QO4f!mYx`g*7!M87 z%oiMBTs7ANS}@+(!aFh-qDkKMrttIau*ZAEC5)>#z^_I33H z6>SPtMMBZ-@!q1^LzR&b{kp4lL@g4Qk=&KIvQNIqpvSrkv`BxjNP;VC(IJ_dJJpqa z1B2lx-MLde;M+OWALmZGN)Kp*AsJVTh2qI@!%lA-Ve?wdj#RSYO;)R*+bXCr*#{@{x!tM!{*wZE9kq#pPDnuM z*(0mmzQcOT6w>Jlr*+c2im7yu@|s#+ihp89@X4c1dt*Ftz`5MZyFg_G~FOgK{UuMVI!cL$>&;#Kc50!&cW?POw_vyyolOz9j7g`vtbpby2c6 z@>y5K5>g)tW!E}AI+P_ynQw&6mdxlmr?pTjDH~#WD&0FpI@F_- z^zKjPA}3wOyk{5WN^bY!k;x>Ru5us{D4KemdwvL~o61(r#_aYVR>MSr^}e~BT#u|W zZWo}>Q{gmzfNT6XtAHu{HU!@8pm$&;-idb+zuUq0a9qgt&gXlnS<1KI+t)k`@c;#& z8t=n>bR>tDID>%pAS$MvQP=JJX~iDqIaxt#>7<5M%`>Px0?jq9mYvWu>P4kvbWXG1 zH-oAv=yTAgoBf6h9z->PIfI%hST?L-CbVd}c@B%ED}fL3=|klrYbitX%fR#6&UXce z)-rDG6nvG3DJ+S!%wXvhYFduKKZm-*+To&)YE)DoL!FL~&<~rT=VvXw$dB7PMqC!L zQ9nG3<$W9JXN9{IAwN7k<7b$OkH&{u=5WfE)!IGiwc#I@S^FE9cFQbQMs2L3kJbKD zXRv0qb{`D?+C%X91BCw5_-LKM=`%Q^U9+)nxIvr6nU6Bs`Y82Gy`HZPWTLs1OPEFD zbn7%VO;gy!7jtZB*BZ3PQPrSL%lRtUM$fUIR%_^8dTlKccnS39a4s|*59)YG@DDyd z{v6j;uB)I<$0v?rxJeP%Vj01j-!Q(cYd?W$;f8X zR(ljWx!@O-$Hg8Nggk$pOn`Oh)V8E$4(%>8+z@W-GFc}Zy-nTBGGR7U@FYmN7}Y{W z&9hkNhJ}HL)p@Ph;6y>iDjOXvug-^1!9(ZYVq+`e#WT2Mx5PmkUBulA_t*##Z&P@? zjb7rg!k60EK^#%I&qkEEU*Q28JBbGsj@gJ44=KFM#%|)v6lOv0A--JUD{Ndze3imi z+qi}}q3~WCBgCT$CvEH_9#eR~jTG^<3LmhMCLUL~!8@@EXKZ9SKB4e+C*?C~BggT) z8ZVr*zJoTd=lBh3{6-r$5x+>`7u&d*_$3Oz)W$8uFH`vCHf|+;g~G42aU1cg6n?dh u+lgPJ@M~?{LHs&}UvJ}1;x{P##*_Gala0GL{$@4)78`dHzg1%Q7RU1nT-H4R literal 0 HcmV?d00001 diff --git a/src/eval/EVAL.java b/src/eval/EVAL.java new file mode 100644 index 0000000..2eacfc2 --- /dev/null +++ b/src/eval/EVAL.java @@ -0,0 +1,251 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; +import java.util.HashMap; + +/** + * EVAL 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 functionTable = + new HashMap(); + + 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 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 functionName 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 symbolName 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 + * true if list is dotted; false + * 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 sexpr + */ + 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()); + } + +} diff --git a/src/eval/EXIT.class b/src/eval/EXIT.class new file mode 100644 index 0000000000000000000000000000000000000000..a5733c52a81cac56426e4c3b0201cf5b485206a9 GIT binary patch literal 860 zcmZuvYflqF6g@*9Tb6laM0Vb9e|WXKRb*g!hVe~T`ie_c;!aBh zs2&)?8@9C73x+^EQDO*gx-~(r${mMcHD2&|(-+OOPR%C%M#WsmYYN}DU701`qT#tk3Qxi>w73I2CgUhbPoAp*hNab5~yDg-pTuakrtSAZiNSnt|Ji$|jg%h^jmQ;2_ zLR*x6^=EcyZncLS2++>MN>Q5(Fs1H z++mXp)A92_VvLtEX#tlpO@4-=5nQ34#)&zy^RzQb zo{7`hb_oLySCM{EYPh0_6dM<*85~;bb4i&H#~eAEQ%d4`Znw hqCJdff&)yH=YxG*`VlxpjD0!cT_hU@`-KdZ`~yHX&l&&# literal 0 HcmV?d00001 diff --git a/src/eval/EXIT.java b/src/eval/EXIT.java new file mode 100644 index 0000000..1def13f --- /dev/null +++ b/src/eval/EXIT.java @@ -0,0 +1,26 @@ +package eval; + +import parser.*; + +public class EXIT extends LispFunction { + + // The number of arguments that EXIT takes. + private static final int NUM_ARGS = 0; + + public SExpression call(Cons argList) { + // retrieve the number of arguments passed to EXIT + int argListLength = LENGTH.getLength(argList); + + // make sure we have received the proper number of arguments + if (argListLength > NUM_ARGS) { + Cons originalSExpr = new Cons(new Symbol("EXIT"), argList); + String errMsg = "too many arguments given to EXIT: " + originalSExpr; + + throw new RuntimeException(errMsg); + } + + System.exit(0); + return null; + } + +} diff --git a/src/eval/FUNCALL.class b/src/eval/FUNCALL.class new file mode 100644 index 0000000000000000000000000000000000000000..60b34d34f5362596e82744ea2314be0fc0a54eb7 GIT binary patch literal 918 zcmZuwTXWJ-5dKcN1kzLm+oH8=^Q^4OFygLxSN+?8-o!u<$T89^-gM-L<{ zN?4K+#e4)0ef`K6kA0Dp5gEc#K6Y6~8W|Z`Jdu!-u)+{tGc3bfX9y%ypBaKByDmuS z+%y>$lbXX@u4v^-w&fO5Cst+a&}j+RHEgTEFjeumez3!xJzg_~f>|UKJjFAH$+2j{ zjjYO1vu0CvY5P;TRMa#-;<+#K40HRu!*eFL8o7^c%QKo{>rfYtN0k^7XU>Y(GOWgC z+c4{*#jxbrw)$0kQ+cb=ZVJnD)rQd#mg?E+sLHCU;00d#;+2Bec%xty1qEv;NO-GY z9UBtfDJWu&K@lBp=0=eWv4N=>uCv{?^kFk0t8JRjfVVFUGfC}Ya|NHz^eKbmoL$AE zj}CLk5muccdsVti6-L*m5uC$+sO<~gqiJ32=nNn6>>+~;)5*&~${214uT&>$XUTsu zxN~D4AUGkSLw4R*_81~fejtb_Z+v;iuYQ_ruu%;1Ah@`@t5q37bbs>*3z(*b_rD2H z14xj(MOKV7BOO}qf&KLTWZuTy$gLwpj{+#CyO{Wnl|BO1K7!SFsE2U62Wh8|2%SW$ tJ;?FNE|g3cQ(au^;rbtnxk3Iwm40HGW5fwx&K~3Dk3p3?Bm-c1;6Gh#;e!AG literal 0 HcmV?d00001 diff --git a/src/eval/FUNCALL.java b/src/eval/FUNCALL.java new file mode 100644 index 0000000..395dd88 --- /dev/null +++ b/src/eval/FUNCALL.java @@ -0,0 +1,31 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; + +/** + * FUNCALL 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); + } + +} diff --git a/src/eval/GREATERP.class b/src/eval/GREATERP.class new file mode 100644 index 0000000000000000000000000000000000000000..38cddbf9d08e3f1ab3a2193f91cca6c20cae4ac0 GIT binary patch literal 1185 zcmZuxTT>EY7=AuEEUfDRJcX96sfD6pWmaI65}FBUpw8Ic0vofo>=G) z&Qw=j^n;qInVjAaP)NObzr*`{&wF^@-Jd64z56PfLj9mE=-BAW13$D z1k4DS72(FD3%B_iGZ0kah_!lZB(5O0lRKIfmKG=q^NPwvrV655JMwQ?nL{e?FrY-es8$ zH5mH+7lFj+%&S&ZA(;lrf3f~kM2-+bqnFeRMxE|CL)V9efG(oiQS=IpDb4H}gV^Lt zYBWn8@@^a2+lsnolr6=`60ExwlQ3b7(YG){UmVZ@#;26*D4jgCGFlzeHL#D|Pe;HY-=1iJeXsG{Q#bH}jl9>c!tb=2St)F32|;i4P&ZVjThvkGaZimocUYv}n#Z+a7C zJl|nU(!KW(%FK84h3vC+HsKTck7(N)a`+r|_n6PY{Z5~~iUFUK%m=uq2{L%}8AC_y yv93@o{;JFCqg^xNc>qtQ-CwV6jO-{J^Cy@Pa6`bjfQi5S-$VO}Kd}9#>hTXo03W#k literal 0 HcmV?d00001 diff --git a/src/eval/GREATERP.java b/src/eval/GREATERP.java new file mode 100644 index 0000000..2dfc7aa --- /dev/null +++ b/src/eval/GREATERP.java @@ -0,0 +1,55 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * GREATERP 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"); + } + +} diff --git a/src/eval/LAMBDA.class b/src/eval/LAMBDA.class new file mode 100644 index 0000000000000000000000000000000000000000..10468c939ef18b7d20f456e7405b5bb36b1c4329 GIT binary patch literal 2009 zcmaJ>+ji4d5Zx!fNKurVAprwTl?G^RCp9g!6bERX3n8s-N)pnVUZ`vzTm@MYmK;L= z1Rnd$1AVbs^;(7JKJ-ue2ehkmY$0 zNVu*bgc~w$D)Ef zf`SFyQScS+O4wF#T6l%9BV$*@yC-8$#@8~wkx-OzUx9{iC448mzL)R=gPh+gJjiZu z?l7<|hVeDqay{Mh_H?tsLqvasA$r}g4DTjGXfd(J5MHw@oFQhoIlWe@=o^Plox84K zTMVZbbBOo-FMAjA;vDw0T1Topg! zD#Ms>A~>qhQ6hPA+5GByRzg`t1zf^I6;=F1ww(;Rw<-)_duCrh(9@=FRnyxI%QI?x zI9iTt(9z3ggYR4JlobD@+X=e2&Ywz18!-at#z}?5bP5n ziyXXDVKu|mEZfs`%`{w(VOFa(Tu&=;I&tc@!|VRVkT>%HWOt5?E zmo=R;Tqo!d>d7FDUh^?T%2X?d>Qv?4noc6kE+&R`DZ^Ax*E^+sUMBLgXLluLI7x0j zgYGG{SD#a08Rd@~x=C#|v)Jd+h3tF`9V!)~a?HSo6yMlrC-aTHY>p@x?s})H6lhs5pB2L@BNT~!k_C+!JkU*54X#mi=L?_d`(ZDIWN z5`n(L#52r^vojrG zAwn7ef2LmH)QxkIUvQ<35W$}=#v(1mQ!Sh+1i{WyFv1qWGGW0Y9u`3<$#8+r&ppRN zKeu;$^Vl3c_ym`OEQVXYd)zV;CTxXVGLiqV%0%1Him~~4I8H?0%Sdf36ywpj)WZ2* w=Hm#x#R_{XX8Gj=CH)Dm`l(OQE{ZzRDGsKxB+IA%UCgg&G)V+z1RVYT1wHZfssI20 literal 0 HcmV?d00001 diff --git a/src/eval/LAMBDA.java b/src/eval/LAMBDA.java new file mode 100644 index 0000000..eaec557 --- /dev/null +++ b/src/eval/LAMBDA.java @@ -0,0 +1,108 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; + +/** + * LAMBDA 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 + * true if sexpr is a valid lambda expression; + * false 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 + * lexpr + * @throws RuntimeException + * Indicates that lexpr 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/LENGTH.class b/src/eval/LENGTH.class new file mode 100644 index 0000000000000000000000000000000000000000..e5619b9cc6cd61d37664951aff0d664769ef3f11 GIT binary patch literal 1398 zcmaJ>TUQcM6#k9^GfrbEsfA@tYQ;sP%x=(4jno1xAsaN z>Q*VfT(vx-%u|~M?s(*w;n21+=edSenyngUk-HSPXWQCSzM<)EsaociSJ6twI=3{> z)|yTdnu;uzgt({TK9*JFkXP{lc}kvPTriY%>*d}QDS$TSaZd@SbVJ(JUXe$6>L>Uk5mn9DQBW&H&wuU==T zI(rjo_j+q4$bbfBMK`N7J2Xf%B7UoCn$FhgF~eXuy|biAF>bLxW6(+7=I*=`=z#7x zlo`Y1zvy;(Xf=&y@Gtz*+H+p;l94^|vS&B@&M*+(4J5_@u zHB<>-crmhq6ZEu4=-mT8FfrgHH9Gav%4qdR>tOF_1A6NxFxpa&l36$14K>iUT1R&} z7JUz24gSnT4S_dXcLENGTH 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 list + */ + 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); + } + +} diff --git a/src/eval/LESSP.class b/src/eval/LESSP.class new file mode 100644 index 0000000000000000000000000000000000000000..bdb80e4e08aa727ebe294968c453e2d1a26e1edd GIT binary patch literal 1182 zcmZuxT~iWa6nmR*9y?5B9!FR(74 z$(i!1i+)fuHIvhM0fp3?^SGQ^E))B{*sT+DHCOM=*d-R9Uk60zMCu;3x@dlLF^U&1gRNC+b$A}ZpcfJXuz zGq|I=soRej9D%7V24~F5X>?>&!(bQ>B#LUOtd&AB%PdExPPBAVaLPY^jm2#rQkFBrAC=M-Jv6atDwwWS&r+EH5AWomenFQwBW zdC9tI>hCJrvRSrOGfS}UR!qV~Fh(E32z_oq2N+*blB1+~>11@erfXoIxSdoQdei(1 zE(rAYBUnYpKIRVL*gk}F+vlpm9jrk}9zvuS&vp%xud@nyri!jAx@+k9PCmU!65b;? zQuOZIhdOhFzOZw)&L(_D{{dZl!!Ez8ZXWZyxZUk{Rx#jrllTbFG(iRrzF_E}J=P_P v#l5CBHGhl=0oMeK3z+!Je>`-b_yfmpsviFUu#+C! literal 0 HcmV?d00001 diff --git a/src/eval/LESSP.java b/src/eval/LESSP.java new file mode 100644 index 0000000..162d8c6 --- /dev/null +++ b/src/eval/LESSP.java @@ -0,0 +1,55 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * LESSP 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"); + } + +} diff --git a/src/eval/LET.class b/src/eval/LET.class new file mode 100644 index 0000000000000000000000000000000000000000..fa99e32b011b13265e0d08bc4ea6179a5de06960 GIT binary patch literal 1860 zcmb7E-Bue_6#foLW|Cn*2yHRc(y5>g5DdjuYrs}YgH{8rg`(8@b4Z3bbeNgWOt5_n zFX07x*UCX)H`^?!t=iA>t`~3C%_dft!!~+d)k50!rLmaC5-+D&+|+Q3EegI=aa+Z*fHG@2R(M4qksn(XNY1-8 zlT=mOw!lcf;z>U+{o=gq1T$kV{+7!RJ>Luh%XMZ1dX__3y}u~E6}fJkQQ}#uOT~)7 zfUMP4rEjq%SaBl{fw6qW+?IB6`O((8Ye$P2(5xBT zElP{bjcIt&@(tSxLLK)(eVh8f!2+WZ0?W3|y0l;BHv-SBS{qhXGM5B!i;Ht~xbOth z5oZ+G>Qb>{1>Qo#sm8=-TSOhXEmWz~ux*MxnXh!RF~jZ7#C<5QEC}@0&9LljTfXaX z;{{IS$Bti|C|76qqFf5a&r72B6vZ6}LsvKQsF6o+&~cR3@?Wxu&wfgD$FUwX%o|P+ zN~cOA(%a5SK9nm}r5T~h;tI;Ea}}B+#w9TRa*mF0@w#!!&|$Zv9~GS9rczEtdYY^UFMalU2#nchx?_SPqw=-NTg z0TOH3!hq{OKBH1!aB(x{!E+xkclY7t$`{>z6Zz+{aHu1&|hFE9z(HHN; zu8$9&7MkcM*Ieq?=;S=fGf4Cw5&}iVn2K=~6DkVPq5uq|i=ToRo|vL)Gz$5f(qwlr z!tf3-u(pR2*^^D2qV2)#o3v;m$DrwdXa`RU1axVV@RX7aYiJjvosqmhm_6MN%_X_I zR4&C~3M;Lo=F}+q?9u4AD2C00tuu2f2c~mr4$QF9nmDtA?wr!Z@Gkx{c!HhI<}ytf zgjZX9e0Y_cB)~*XLplEprI?!MxEwEttYrdrMICC$C>O8i2S GzJCDJ&(Eg- literal 0 HcmV?d00001 diff --git a/src/eval/LET.java b/src/eval/LET.java new file mode 100644 index 0000000..becdbdd --- /dev/null +++ b/src/eval/LET.java @@ -0,0 +1,116 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; + +/** + * LET 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/LIST.class b/src/eval/LIST.class new file mode 100644 index 0000000000000000000000000000000000000000..f33586b76e1a414d478c5c1100bb2a5e87110358 GIT binary patch literal 642 zcmZ9K%TB^j5QhK5tyl_DyrJS1#R3{P?l2~XXhH&PKoi{^YhxN}sckX7if@4%HJTXL zK9q3|mWyuYoX&hR^Us`qeZPGGIDjTY#;k-n8S_|>5kgj&MPZhNS(Y({oP-q#s|>M2 z(>DDhhOkyVXNXk0*9JrUmUoQ0>G=$Kt?qEwGu-{w$%Eq>o@aLLN^$6{c5Sahc{;Z& zhTI4q`2SPMme2K0gF9`0Wl@`P?Z5bBCj|*842eL5041y`SjUD4Z7RrPOTjh@3U-7^ zLuHsU?zy#JueI6?>hIn3oYS7I`y`)14$3u6Qmx(?{+Vsw^^BVB`P|k?T1p#LIST 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 sexpr 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)); + } + +} diff --git a/src/eval/LISTP.class b/src/eval/LISTP.class new file mode 100644 index 0000000000000000000000000000000000000000..2bb22ae61f3c1256661e949e334e2c2763d797f1 GIT binary patch literal 1148 zcmZuwTT|0e5dID%O&h|ck&7T|6)%N~6~tQ$DAaP%QjivA>WdS~u?Ewmwkg6-@yQow zcoiR7#?I)wKgn^#O-d;O4`)wy^X+%`JG(N*_vsuYet#3QXP!JGpU=pJ9A0M-V%8?7Evp#@!%#3$(26Bq z3_GdO;f9xr?-Yu>RMIUoO1vps%f4UI3TbV_;0-xr5@saKD!7a*5@HITBhDc6ZOsTL z7E|dJhPD&rM04b&cJmt+9WJ^kCx6Z{^9+4k+O`%pG&2`Y*+t#V&6agzlNYI8+p+=* z7C$%$4)pv`c}UzRk^mZ3SH7h>L%r;3X0a15N7HvT5si9^c9G zf=vn)EFtMCS;mTjS6G#hQjo?PgTF3EFBRs>X4XM7bTz5!RWhgzY0Y~h_4V9%az4Gl z;LCA4!Ofigju=i|JBjKECQj2voqmOmp(lHCUY{JaM=KP#xydkk9^IJ}j;@zl{2zXK zV~b~PnugOAHSu2CYH05co&^%4hxEoYYF#h=KYKld5DmR#7u>;oO#_@}=sX6xBSIMY zC^MqS`^O+DT@#g02eu5upY((=SwU;b*9V?j*%~KEd}5y?gK+pzo`D_;s=oh=&-5 hAYn+t4Mq!OZXQxqCu1!XlW^-d2L8Y=;r1*o;2*p{4*UQB literal 0 HcmV?d00001 diff --git a/src/eval/LISTP.java b/src/eval/LISTP.java new file mode 100644 index 0000000..b2ad0ce --- /dev/null +++ b/src/eval/LISTP.java @@ -0,0 +1,38 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * LISTP 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()); + } + +} diff --git a/src/eval/LOAD.class b/src/eval/LOAD.class new file mode 100644 index 0000000000000000000000000000000000000000..0529e4792a4f87fec8b64f9b80b5824700887c11 GIT binary patch literal 2093 zcmZ`)Npl-T6#m*CxuwZuu@XD6i4%pec!@Df2w)|E<9GvE4wmhpuq0z?tc)YgDALG@ z*+SUYutQZ2aG}aqlY^YXRlu1)z(3&1ouV*bYq4cp9Hx7^=e^hO``*`Ye*gF9UjQ7( zcRG48sN)QVB!(qMBu4!h)8WH2Iy5{h5z!IApdaIEj`}g-$5}s~Q>#fe#3ZJ41k3i* zI%aUrkLUe}OPtqn05Kge;6*jOq@xipOI(n+sN<0G=zu9P8$bd{KP(+{Na?r)TYZ^V z!(|<5WK?`d!qw3YC&1*g5?2KL(dqFE1Ct{$0Wl`9bI^72p6PfqX1ZWC5}*)hI%zw$ z_oP5$XV;8?Hs~fTP6;!e7C71&$(p&mmFrWk;jZc`HgqkUv+{Y{b;67r^UTEMaWgw* z&Zey@PZ5cnL|$M=Hs>a2JZz^KxwA7eZ!Va9Y12vd#k`#Dr0T~l@i0sBh|9pkctpZ8 zP{4vfz*;cVeUXWQGb;K{XQk@CK(hHC=*w;q1FV5gH-j;5aLh72s? z6~1RoXOWc5Syu(xLuM{j$XJe-52fq{%L#dINX6|hnZIh_HM~x z^~jNdH*lR?7=U{A=-haA@nnW21%34!JcfQX&Xmf0bV2HwKk2HwHD22O#s zs>!e2#ZyM2o1F(+H_=x>=B1^hjMj#7G+&r#PKb_-5&Jwu824SawP1zO6@;9GBwKjrz|gGIVtZFBW#f31>V$^oex@oO` z>uFlugeEgfK5^Nm1Hn7u% z5gRRcjy;a1rE*r=!qCh>gg00TMu3>=@by0=>I^l`MrEdWoR|{Wz3yCUCt)06gYH#* z6YY2aeViZUssRsiU#K3%@i=#yISbCd?iGli_@Z1M#fi%2KiQ$1xc7a}9Wu&R{ z;NWs8>&G~rfVM_-n#AK0PY6EX(7#4FwR;WRlL-Hf_J7bLagxNaTU9XsLChLs-4x@i z=wNDx;)HpaPiTAzN20fJcQxIk%#u)4rbXOy2lp-?E8@OenB;VSwD%4=&n>O}RqIg! z*tN;2j=|=rw{dKlg=@fGw6e5e3}KW%QZ?KBkqRj6hv8e}=f)EDu*6de`qLf!s}Ee1 II2{8118CO|jQ{`u literal 0 HcmV?d00001 diff --git a/src/eval/LOAD.java b/src/eval/LOAD.java new file mode 100644 index 0000000..4a94235 --- /dev/null +++ b/src/eval/LOAD.java @@ -0,0 +1,87 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; +import java.io.*; + +/** + * LOAD 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; + } + +} diff --git a/src/eval/LambdaExpression.class b/src/eval/LambdaExpression.class new file mode 100644 index 0000000000000000000000000000000000000000..bc54d92952787dcbffddd8ef4dd9964215dfc5cc GIT binary patch literal 549 zcmZvY%TB^j5QhJ0DJ@Wn+`Qo>?4X)-;|}8nb=4iwg}b9vQd3*fR^mgs&_pzG;REU2&T!I)BpSDa^~mv>l?rc4vWZRvj7cS*|A;34t904bnFqdz8cCQJ!el+w5g+<9RLG5&J z2-e6;-3#vTCCRK+rPEz0M<}sn(U(wXzCMhRMuRl=!x5puh6gbbP9VaOGgo^iO4v7{ z!!S`mQOALa2AYKCtd=VtZ--)ejGElVU|Hmm`7NcTHKEPx%=3;F{true + */ + 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(); + } + +} diff --git a/src/eval/LispFunction.class b/src/eval/LispFunction.class new file mode 100644 index 0000000000000000000000000000000000000000..a6f82978512ae8f24ff5d68e38aa9505f8cf3d3d GIT binary patch literal 239 zcmXv|y9&ZU5S%p^;~V`1u~C~ec8VaPm0%%Q*q!l^NW6sHMf@lmE5X7K@T0_y#4UDq zn3>&uf1WP@BeZI8Q1{UA&?J;6p$_eo;PeMuf|$n##Sq9SBJ}#JM5aci{yf%ZJovNC z;+mw&m@w93LPuR>lu4^*=`lMiZOw1nt^onJko{F?l4Yg?%NauZBrnpBq(1uV{YeE@ qbW!5B@^ZlU;c_oC>o5|dJA8odxh@DEDm)OXs1>$WVJnGS?g74nEiPgJ literal 0 HcmV?d00001 diff --git a/src/eval/LispFunction.java b/src/eval/LispFunction.java new file mode 100644 index 0000000..c861fa2 --- /dev/null +++ b/src/eval/LispFunction.java @@ -0,0 +1,44 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * A LispFunction 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 + * false if it does not want its arguments to be evaluated + * prior to being passed. + * + * @return + * true + */ + public boolean evaluateArguments() { + return true; + } + +} diff --git a/src/eval/MINUS.class b/src/eval/MINUS.class new file mode 100644 index 0000000000000000000000000000000000000000..cdd4ee9530949ca876f596a3cd8fccc4073013db GIT binary patch literal 1190 zcmZuwT~pIg5IvWE+z^7&@?}6V2x6g>qM~R)P!JTMpj4T`x3rC&V47sw6!9nc6ZjYS z($2_?^6ZcCSzpk-X@Ls7?9J|;yZ7v#&Cla+-vLZvQ${~VWCU=BBgQc*VN6C4aS)8B!f~Utp(XJitSaX&Ie(B+O$GNy+HLjD%SUPdMf{<{84X zrfqt241w6_7DI5+$s2U!bjxBGimkbNsce*zi;i8M89nhbOM7m~D3?vgo?&RuczW(* zT6f>-SXVAjX&d|4`@9IfQw+qS5 zitU+2V`(pExE{U7(0i85cqP*=EL2P@Z6t76x@VH!=iEw z9hzCzY{%1d&Gx|zvazdM$@I$ly9`zH9Z_q!V(04YqbH4@jgTQ^S1il*HF(d^9a}r! z;*8KHeyT?E{4di)pu@WB8g`x`aap+wFEoZoa{hp=nOA;PF)9vuGmE& zRSXvlZ&4?KdMJOf{}V)>5WGG}nuSD{wsfmP+eoXqLOU5-5q*Vnw2CeUX_fowuK`-X z#F~*EATL5Eqcb#C1N$oS|Up literal 0 HcmV?d00001 diff --git a/src/eval/MINUS.java b/src/eval/MINUS.java new file mode 100644 index 0000000..a913624 --- /dev/null +++ b/src/eval/MINUS.java @@ -0,0 +1,60 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * MINUS 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"); + } + +} diff --git a/src/eval/MULTIPLY.class b/src/eval/MULTIPLY.class new file mode 100644 index 0000000000000000000000000000000000000000..53eab28944fe2596fe5bea9a6a3f531075a6b19c GIT binary patch literal 934 zcmaJ5jv0X zI+|_kZ8OiYfC$GUY%m1Jg)UM{>tl{5*yPAzlfgg1h01W`vB43=BF7eF8!_x2qdXtwW8caxso=Jd^O8ArRB;nAvt>B4!SI z*v%4vIB zno|(OVIlE*wi8h_+@VL4Jd_a^%HX4*sxZ2=CfZq%e1v6bW|JY4C{1@sJDa{5H%`g_ z@PAc5)Edrz{e4b*G&_cQB0Qa#GKT-gpo(RBn_+s&pyx@=B0_kTv>-`F(v#|geUf%k zX`y5DN4VjoyXI;SGpFDKxN7b`+-IbF$^_nXDEsLie5Z(~&*93sQ<)xSa~|m#b@!k~ zJp}J%%mDt{0KC@6TMULTIPLY 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"); + } + +} diff --git a/src/eval/NULL.class b/src/eval/NULL.class new file mode 100644 index 0000000000000000000000000000000000000000..c74646b6d2638e4fa43dc007e8f67cd5553d0fef GIT binary patch literal 1145 zcmZuwTT|0e5dIFNO&WsG$VDn@6)%N~6~tQ$DAaP%Qk1sL)E6g|V-2QBY*U1v;*&4V z@G3q~#?I)wKgn^#O-m^P4`)wy^X+%`+q37_-|s&FOkh>U1%zY_V?;z)#BC9y67ICgJ}M)INgt(8$(Y6y5lYcx^wQhKHH*#`T#%bR=bCwj{tazYix`?&h@_p8ZWd-My0Okn1a&Mcs9*sk zQYdQXHmP~bKQaV@TB%Sea?>dX3;HHEgN_w+d82jsa|JIzg#=p6D;3kxi#)NF=e9%g z6f7ZCm$8hO3SMDFL|Q=xSq6VyOHwb}a}_i1q8YkdRE;7T)TXdj(@1+GH<6mpEKpYp z+(~k?;JhP-6FnzQy`khu+L(J;;Unnr3pwkOT(noSZEmhJjGjez>V(7Y(*6F2UtZhb zd51>fWJN8!W^hY%jKViNULL 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()); + } + +} diff --git a/src/eval/PLUS.class b/src/eval/PLUS.class new file mode 100644 index 0000000000000000000000000000000000000000..334668c3f85162ce95838f4aa520fc54903ce550 GIT binary patch literal 930 zcmaJOIV1>cEp_{t1$>2(+stoQ@yQz_A z2*Y4lPL?fUcQiX+YMY&6>X%m5JJvz>sIJ*XhS`cE8XxwB^+wbUO~EQLVo3ZWw6c3* z*;=Qgx6LBQJfa+ru*MJ?7rIC-t&cgLV4b6Yb%wwM7b?S1#2QBo3mhAG%CK-Kjz!)O zW-I@?YdZRowtLdhEQd-lL@$gL$JWi(PFFXYnoW&o3UQ82Y)N>=5RB`cxY>5%B5n?Q z2GeF~^BE89Zj!Fs$K--_dN7dvem=mgbZM z)t^uPp6f&u4R+|!BoAf8gEIIis49#ut%&xuM?S)`G_%Q&OO~fQq7B6ufy8c2svhg-?5_Lx`G?QZQ^rt%qNT)`T=j6 KYWvUVMBh*QR@H(4 literal 0 HcmV?d00001 diff --git a/src/eval/PLUS.java b/src/eval/PLUS.java new file mode 100644 index 0000000..144f46c --- /dev/null +++ b/src/eval/PLUS.java @@ -0,0 +1,34 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 1 + */ + +package eval; + +import parser.*; + +/** + * PLUS 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"); + } + +} diff --git a/src/eval/PRINT.class b/src/eval/PRINT.class new file mode 100644 index 0000000000000000000000000000000000000000..f02a69346136ef4640180583457cf557423d30fc GIT binary patch literal 1115 zcmZuw%Tg0T6g^EQnaMCHgqJ+jAc}z)gNQEzD8%s45Rf2MSyK zx9TFXOqK5aBp2eHgh&D``rdw=KKF6DfB*gQ6TmcHsp!X;irWau7?&|2Bdp+#3NIom zB;1t|RpG~&f=SokQ!u6AzJh6Y^}sa`Wjs<5sN)~|@dPs}VwjaN$DpKMuf1K^Tuw8v zRfdkZZ54%XiEZ61aSx@y7<{vaWr%qOPiTCbL5kbEoLp8nO@`4>($Nb=UWmF^W8;lg zI&t6>c(G{MR*ZPlLeG9!)157S$K;JlqB7<+4CAVdry8DNfkEZ_x*6TrTup5;v^Oym z$H^*vnBTD}vbTnE?=QM0&d|T7@9R-hw{p?6C>U05v1FLLygWvnm^o>Fg?EMeq%;vmZ%LFH*!#S0lP zH6*bnBc)*-8w_2wN|Hv=St?ms7s$|g%2H2|YOKQ&spTySy5n$bmmzWy-MI)SO(Ydt@asE!JS#}>vl*S@6=65Z>a9gQOM|i0gTx?5^e0y3HUvF32Pe zT6)+hVjCmy&`+cHjzL_(K+OYf7^1=4H%j&zop+IEIWu&*?6uUtp)^* zNL2(f15yRuzrtnoq`sk-j`|{BYC%WHPQr7HDM&JI$QWfbK<4H#Wz)RZMtd@D{h`|M E4+v2TjQ{`u literal 0 HcmV?d00001 diff --git a/src/eval/PRINT.java b/src/eval/PRINT.java new file mode 100644 index 0000000..f9fedb5 --- /dev/null +++ b/src/eval/PRINT.java @@ -0,0 +1,40 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; + +/** + * PRINT 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; + } + +} diff --git a/src/eval/QUOTE.class b/src/eval/QUOTE.class new file mode 100644 index 0000000000000000000000000000000000000000..9154e6e16165ada819bc584a7ecd166291ab7135 GIT binary patch literal 1029 zcmZuwOH&g;5dJ3FWS1o%tUTnQ22l(|Tts{k9zqOYRe+KNs^Y~O!Wb8m-K}JT@JGCQ zvC4}Fy(E^Y(z`#&gV-AqiNIEE_jJ$KulZ(v{rUa_zzkM(^kPiMZA4UztC&y`)o@2g z0Fyct+*M)fXv3I>DNo{*bB2z% zW0xeiAeH6$Ji}-t>GEPp6iqKQHr}*Si9@$2 zN+rv&W0W@~dG_r(chh_~FPi5es1s^9;HN zGhb|PrV|Y9Ej1~7!%7_$b{*;|P)B+33!YeH=-=lD+{|-3XQpJ)vUAI2E59d-G=_AX za0pMaMC$^#kEr--@s43A%$xm$bJl^d!_o=Y6VKN1%OS+^jA8IJ^;X%IRzV~Vv%-}$ zcnArsGzK)2R>@r{+gWdeq3bm2q#>HAK43Djv6^0EXv+zi6n0L&A@G?qCZc*H$+H<^ z9y!r}&{hI2BE>@ox$6phk74qnbmuBG4vqNy55Kv)FS3%TKiknMUXxC9%$~@3AY}~F zym3y1^wEBk&z3uc5%}o=(1j#M`_NDN3Ryl3kl*tSksKyZH)%#XFi{2jN((RKDy}uQ z-_v^ukS`tm2H*U!@&Ri#D47}p86#MQ8m-cssG%)Wg>JN05E@oKLNhu(Az*ZpXIyG(dzS&PsQkOYMQUOTE 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/SETF.class b/src/eval/SETF.class new file mode 100644 index 0000000000000000000000000000000000000000..4010526aa1f2472085aa1262f05eb9f4824a64c1 GIT binary patch literal 1898 zcmZ`)TUQ%Z7~Lng8HNENaxqACTD&AgjJEX_C`vIvZJ?D z+XDq3YB2DT40AGE)-aEc7335wC|Fdnq@f2_G^qGQ!Bq`?m{pONP&@FiB|Nna`WT8^^{ZVB{S&YoR$on6cE1mbyX z&n#yO_jWhk@|w9>wx$Ktl^e^q=2jOA0^*85-@NP8Jk#;k&2rre^I9Q+*o^Ji-mE}4 znOYZ!%)46_vt`%asaFJ&$^5ptXJ*Q#Q_2*)s_m4fQ~8Qnty$GfA$PY@wQ4onb$D7| z!840H%Vxzto?Hd`YnGQgNpm=Pnx{OrztjO7N~TUDNv~*@%K{V076o~w?u1$$xvJnB z1*X8DRH$xx)?Bqzm#WqLOW&kUGsUv6f{qj>bxhzD9h)fX*ustXc(=%|>D(i;+twX{ zF~e+;HA?oLo04 zT{9flGfboA6V_3aKu<>c;XE@n$Fa6#NH&ZFAcydh}=KMca7Qb6bK*&vyb@F-9fk zO}b=+>!&p(LJ2y^$JNJf5gXVvw?3DrqojNSlU)V)pOPo~8C-&Wsnpq*R2MzEu}ZDu zEMJ!Af1=07KwmjT-^Ky@ zN*CU+CM#(iBOT<{D50EC-!sHcVSETF 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 symbolName 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 + * false + */ + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/eval/SYMBOL_FUNCTION.class b/src/eval/SYMBOL_FUNCTION.class new file mode 100644 index 0000000000000000000000000000000000000000..4638fb66ca18a5e714777c976ab3627e6c11294b GIT binary patch literal 1474 zcmZuxTT>HB6#g0}>0yitBO*c6QBi~07}s^Z1Q8*GiyOj92yWa9Hc68m4Kt}^g8EZ@ z+Lx{JRbLWIs@Cl`;U^dYL^rmJHrCRE%~G3i>jT`|RRM}zL+r!~wVu3;8a8WNb} znAb3j1r>`b?yC4jMUrEQK}}_r)~8qI(+q5p;b7dhDvq$6HBqd}UaE~T_-~n(>D*@M z4UMlcC~-S4N##Vb$Z$54EQxYOmZPrg#CXd}C!UtdvQjZ^Yl7mY9g%yyBucAdqbOS~ z-rz`aEK?x?oW&T&uL0b{3d5k>7R6{fyEL<$T%XIN;;W0xDTV_bnJ8w{NVWw&p^Ri5BIJRvBkb&FTmav{to15|p!#P8g z3)L-YITfQ|ZcEE>Y-3M~Si|#v0KXy2Fw#!4Qneg&OD3M?WXT~40(gMmsnr1fz@Hp{ zajXaM5Q3_1w3?Znt6Dh^xq%#mFP)iLi75dRt(E_ z3}IB76b&?zCCy5ym5yNTsy%8L^cJ)2GbHjo-$ZJDb%CL;Af2SN3eMjYVb2KA932fM z_lBKtXD9p(+BqNl&5Vooi&9Bid4|Y-;kq(3&y>dPJN)v-Bbjq(GWS;0#;cCq>U}WO z4Wx*E>NhTEUWRDDn;t@NkK|J0nmqW9SFZvhtwCX8Z92(tsA$`ds~zWXVc#CR4vaFX z4esfB(e$*dX?MlZc2bZs$$Q!q%MCaVW$=%dSuF_PzKWq>pz?Yme9dqqF4%XwVz zw%K`lc>J{XG5i`mlcUN%SlEG*-GMKw`|IH0I=vh_=*!lj=?7{Ej4J;^)epXaPd`Ma zewak0hW;7`V#*HmY*4A=$lGuYgDF}+`W)+|hF;@XObIIQaV@C4!|-$T2bKRZ9PSYMBOL_FUNCTION 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"); + } + +} diff --git a/src/eval/SymbolTable.class b/src/eval/SymbolTable.class new file mode 100644 index 0000000000000000000000000000000000000000..6e6dbb76c2d570811b16aa1b05626df1858556ab GIT binary patch literal 921 zcmZva-D}fO7{;H|uFcX$UAuK3&X0A|nWWR)cp+r$Mg+l%LS>?Nr!&-yn3g0R?tk(^ z!L6VmUi(Lh&q+_QEG6*foagmxc;!L2~4bEib_0B)_htV5VTxAc#ILwX& z%C>VXu=I5JffZYJkyYvClVP06FivwM?|Z%l=RNNk1gvG-#Ri>49rD0v%mdDX1B-ao zg~<}H^-ycJQ*713D%Mq46KE9NwQvpBEi}-y;G$z;3kP(kXrF~`JQP^DY8$2hqrd8( z1}7Y#KC|XUaDK&|DdH=4_UFf(>2p?TN#Mx>u*f+@32i<*ix0EJkAp(sM!s9&o-=b@ zrABWUTii9N3#GbZ0`ZM2|Fu!VQ8@DvI!MbIt^_)7mMD6XY+HKs?P=kNfe1%YT HdI$aiW2({X literal 0 HcmV?d00001 diff --git a/src/eval/SymbolTable.java b/src/eval/SymbolTable.java new file mode 100644 index 0000000..aa72b28 --- /dev/null +++ b/src/eval/SymbolTable.java @@ -0,0 +1,90 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; +import java.util.HashMap; + +/** + * A SymbolTable maps symbol names to values. + */ +public class SymbolTable { + + private HashMap 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(); + 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 + * true if the symbol is in this symbol table; + * false 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 symbolName, 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; + } + +} diff --git a/src/eval/UDFunction.class b/src/eval/UDFunction.class new file mode 100644 index 0000000000000000000000000000000000000000..afbca9e4a8ced37facfd96196688eeb4bef64bdd GIT binary patch literal 2291 zcmaJ?YjYD-7=BK>>29|Rg|rllfB_WSlo%DSDWIjK1xy1r1uR~0n=D}=-Na;53tmw1 zeh063sxvmNc1HQ^SO0Bj#Og0G>Ln@Lw0yv^W!BJ^^T*oj{ax|jin2r{I!*K~XA)6<3jN+tRcv4QE zlB1_3{uv#o@T>|`M+XjT7?XWkLq>z8;k1UVG@OymNfow^5RRxgt7ALP$wP827>6U9 zyo!P}KPR~qb(G-BX<5aDisuEi13lRw`e=r zUapPhGv@`?BnoD+WEG?Rd8b5kAZJY$iUKW`Ghr9=&bZ~c@&s$b%tce@$H(%y5pyhO z5vp@1&v&h2NnnHTqwLzbXkW2to=?~%m!Rg9opnsNTqKX~)i8TjlH139O?zy|cJ~QH zyH*0~IM+?Ok2A9Ve1_iEq+Bz7ZpbWnd_9E<%q!Q^W-ceNqpN;rb(V@#0IO88^G+{w zrec!0P(iJV-7$ARaRC3SKqv8ZN1L-M|}o)4*GJ+rT@xWZ+%AXW%YGRlIND z1AHj3ae3DFm+f4}VsaHXpAQ-M2p@AiZaR#u@wCPIX%CsjY+2^K6w2BYmJ@RGA%TXN zhrTSZY3a=2vg6w0R(vvT60!jdhxq}d_Xqv_@uWw0vxQbHMLmn@MD zs}z;A_bk>#Z532AU2Bu*W%;PE)gD(9|#lUzHN z>Z#UCol-}}&RS_+M$OIpqA_3Gwp>a&X*4sLWkLFzd%LSnGqMay_61%PO2W6I#g{dn z92_~w(7aN2vhEpDSQN!8bqQ`V3kA!ekH~65uAsC~cw|a zw=(_orJgZMNo$gdDUR3GtF_>r@fXU(bgvT0eH zuSTuWm;0z$%hEzARqPN5kv+UU)qp2M9dujbmu!xEFia z?xp22G=7W#J3Ips?wLkII5LgK@EnxUIRr*~X3!+ZyCO4C`JaXso<;LCbV6E2XJAZY z&8`a8Ud5L1Pu{S#f^`+FKS68oI+UTQ`9H&Qse-m?wEswF0{hr@pkbao6cvxCcvM9n z|KP_>U_bhOdLqehY!k76_sn9$-pxFw{TfKjC&y_6`H`cVoI?lMYz*E~L8piN9$IkI z6av9pX$fv-BjIwqg-xV_trgrBQ|1sF?Nny4?KcLreUun|20LVY9_8DUk)Lsgz*U4f z*eP%wcgB>S3R+_UiS1N60~K`9AY)BT&Hq7ll5%Ah-Rv4;iiia|6;Gi}vTvP5*tf_X zF=cB0uZYA}y;s0^B!SMr4~tq2K%GZyL90F?m11*Xo-+CR`L+hysO1gp{0AK>;x`bz di8d7jp1Olu2|tKKzP4D;UeJS#LzAxf`xhS^LaqP+ literal 0 HcmV?d00001 diff --git a/src/eval/UDFunction.java b/src/eval/UDFunction.java new file mode 100644 index 0000000..44e02c8 --- /dev/null +++ b/src/eval/UDFunction.java @@ -0,0 +1,122 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter 2 + */ + +package eval; + +import parser.*; +import java.util.ArrayList; + +/** + * A UDFunction 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 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(); + + // 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; + } + +} diff --git a/src/eval/package.html b/src/eval/package.html new file mode 100644 index 0000000..e9c971d --- /dev/null +++ b/src/eval/package.html @@ -0,0 +1,4 @@ + + Provides functions and forms to be used during the evaluation of an + S-expression. + diff --git a/src/main/LispInterpreter.class b/src/main/LispInterpreter.class new file mode 100644 index 0000000000000000000000000000000000000000..3b4d901f05cac7a9948b1c884b771c8b0b1de605 GIT binary patch literal 1689 zcmZ`(ZBrXn6n<{rcC#$Bq$S8p+o073Dg-FLK%h!7U^H*CG#XIr0+)1YvKu!W28Y2< zjx+uQ`oRy5Gx_M04}q~`e}KQmU!ab7?k0td#4q>UbMJY%&vVW_zyI^=3ji~yDG1{& z32#eyM}ZgbD)3-d!kmHt;u7W+$XE#CKHih@zL1L&9>`cy@BtEHS(dRP8=8bQ1;ZlpLj^YxSCGf2GCpIFS5^~=wPa?6A(YzH_w-mv zH;XaNu?@2rXXswC%&McCPF^q7I71+}noZ}{7?j0~mVC6D&=Tj02$dm|dBZfE`wZUb zXr95hWNnk9udEv;LpZu|IgK#u)*OB7Nm{S0>6;}kq2RJJM=z&GGjwrVukxI2l`9Sf zi>{C6RYWn$&|A^%Dz{@Pqgu(iTZVoYiDAW-jS^3qm6}6tfkpxY2Htv7BYA zW^O0;w|K=dEK|kj_<}g$wr$z5gjmzMsTaAe;!8Y|@RbT3n+!qio2tXh69&0#VVmK) z0P4ObX*%4l*ql~|aqVHI5Xo6ibz3h-#A73E_mS~Pp4(MQ9GRM!oS2fpRqTkj?g)&Y zZzC#-LVXNF#V(#u;)BV%V=|hIA7nRFy?(!|7$Un4kZ@Mg@q@oNW-Z!){Nvfry zg0EHF!wkdVh1+V)bc`}T$Io!>B|pjR`KbhgUj>C{GFfyeB|~4dbAiWN=Tw!pio`n` zD@E?4d9_M}6Qj}5%U0AeMQ&18INYs{XsyduNzqzu>@7?YMtnoqid?(GvR=>Vq(WX?3i7LLjN?6gSBC z^inL5UrbT4#GZjD>tOmn{>`3u_`VZsF}G~lWu1@&c3PX+4h*%|u-QBDj%>G+=ne;p zTjFNXdF+BrVuS`wn5LT#gLoCMf#Ei39`um@dYj&h0ld+s50HMRP4B09$i&yCb&MkP zl4KI?jaaKRhu*9yMz zQ@o-T{GkEu6oYfV;ZqEe&w!62)G?e9I_0|IcXO#C?=6vc_~`7Hm$B<-KR+X&L7K)R zgrI=$@dHh0A&=;c<^^H81?h~gy%HuQ#E1q7lU=v>Bur%`Ov^n`#6NBkF-u%~$m!LispInterpreter 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: + *
    + *
  • args[0] - file name (optional)
  • + *
+ */ + 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"); + } + } + } + +} diff --git a/src/main/LispParserDriver.class b/src/main/LispParserDriver.class new file mode 100644 index 0000000000000000000000000000000000000000..521f57ca922b0c77f3c8b7c8046d51fbd14d8721 GIT binary patch literal 1026 zcmZuw+foxj5IvKSOtLIWfB+(hcq0jyDB=Z!phD0{0%$Btw0u}#Ol?edw>BFJf5iu1 z^9&Eck}5vHM?b(1@FR>pn`pKq`_Mhxeflz|d%pkvb_!q~>k0;Oh2tv6H3fcLSKz}9 zj!6YU#5m##LP&%$h3ODxq;pn^q_o_Wv9}b=;Wo#-f`|;bqo7~vyBzlzf{VJLJ4+1y zSo}3Z*NV9(NR>6+U>Jy@@s5*+v4{wApi zNgaHcV&DtQvdi zgI!@cx@o9LVUeLv*tTgW(^BR%Ln{bd#X~G{EUS2g#|+{8r-~!WvpR)5!HSAiq*bip zsfuS<k9nZa1ZGB(Z4884Cn>$6Z>rjFY z1TsWpooP+9>_m`o~R4R0LhJjf8EQ;n-5QeZdN4P}Efu2QW
    GH+f_5 z$qk4$@&7eM+ak;l?#{er2vH;X^npbT3{o4dvAY&(k7kx4q**04+S#^fm0GhWZ^$v5 z%jIF*gJ9s6#Fq?AAWADOKObnFFii3S{Y6MK(t*S=*rD_zj1gRHxew{B_{mme*~IA= zOrF5EeFFb>!asM6E>{M!HH_w_>)^q!2-nanF-K7Px{ndaPSv4)#tf;R+!4+Z?0g-) zwZ<rji2&7;6^uo98x`wQH)dNWo+ODwJ7y_dVGxRz!-uJa{D;OI4*&4jCZSV MI4-YqOmqW(0AHT@!~g&Q literal 0 HcmV?d00001 diff --git a/src/main/LispParserDriver.java b/src/main/LispParserDriver.java new file mode 100644 index 0000000..d0ffc46 --- /dev/null +++ b/src/main/LispParserDriver.java @@ -0,0 +1,65 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Parser + */ + +package main; + +import parser.*; +import error.ErrorManager; +import java.io.*; + +/** + * LispParserDriver 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: + *
      + *
    • args[0] - file name (optional)
    • + *
    + */ + 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); + } + } + } + +} diff --git a/src/main/LispScannerDriver.class b/src/main/LispScannerDriver.class new file mode 100644 index 0000000000000000000000000000000000000000..23a6959dab0e4d9ce69a54ab852b3d6244a81432 GIT binary patch literal 1452 zcmZux%W@M(6g@3jZfO{TEikX}NB{>}*j8|G9>^giMgoDxB8+*6S2C6xWk8xyX+|!y z$S$9e$|8$+lMPA0T2!OVm5Q)kJ^ zH5{*=v%|LQ)$WrM=^7LSoAyIVqv+aTA}NECd#k`(yHC|+qr_4 zmg6~f)iyDQio{J5-{Y1*%6=Y%syXTMh>dv@x54a3Mkmfs2cr{H6w{0PPs?wfc3%fv%Gl6Y+52mENl!6Oq3uq0|G7D3XEZXdtZ@j|z$wh|^4n+26B zTdNXJOw{ociPn5aS-R48msFd_c4+|V-{f`Pf2P={k<9LG%J$dEb%f{q?qH*?LQ4e! zX%sk+8G9eaz;(rTI-%-vt_S3OR7np=gvwqE1Y&xkMtb;n5@Mq~wH)@V8D{Jq1?D-O zekY8czR6MSj}3PvQ=fm{(u3PmW=W6TY{Llx73ehI@pwkVHV-m#&qdkw=zjutUXPNSnLPqf2Ql%GC=4pYoz)^Bv0tTjoyIOjC!bF2H2ym|Lpx(d3R*@ebv z<9pMX?}sFL5jPB)-oaM4HkMJS6xqj}O!n%=$2i6ZNB?5rUBd~=ll&T{7SxICI>ZaT zj}$&4ytn-yU!wu8{VK}Y*T3QHE5xd=5U*zAQ|lP$%0zhu$E@)+$ibILtzbxFR$-*~ ztRqnt*10v9)++XweQI?%Nwtr2?-2k)-n@Z7{2 z4kx;fO>H05LB{{t_>-WaReboz#_uoqd`gyglDS?)2g`i+wEl(9p1>()e;RUw+cAmL i5@#SJM)#QiYyHX35@&BnWRiqd2{ot-d_?bEKJpgQS8F@~ literal 0 HcmV?d00001 diff --git a/src/main/LispScannerDriver.java b/src/main/LispScannerDriver.java new file mode 100644 index 0000000..13447c3 --- /dev/null +++ b/src/main/LispScannerDriver.java @@ -0,0 +1,69 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis + */ + +package main; + +import scanner.*; +import error.ErrorManager; +import java.io.*; + +/** + * LispScannerDriver 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: + *
      + *
    • args[0] - file name (optional)
    • + *
    + */ + 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)); + } + +} diff --git a/src/main/package.html b/src/main/package.html new file mode 100644 index 0000000..bfdbdab --- /dev/null +++ b/src/main/package.html @@ -0,0 +1,3 @@ + + Provides test drivers for the various stages of the Lisp Interpreter. + diff --git a/src/parser/Atom.class b/src/parser/Atom.class new file mode 100644 index 0000000000000000000000000000000000000000..e3eb78ff2278c777f92d46d31b2ef4e2941169e2 GIT binary patch literal 310 zcmZXPKa0XZ5XIkY5~DHd`M19=iA5T_6G09;JHf(k!5|S$Lb8Y-%0fXAuJ8l+q2xy0 z&Sq!c{N_Do?~lJ5fC1VLOw=nd(6I4kqe(DTv{!`IbS-x>+{k1V&Qu;Js~nB z5xU+d_UCN=O_veDk}BP11jF+egtAKC351U4e;QrbXt}UZB2+V(7f~LLIe?GQYBt$t zc~lf}n!G~i_~w&M{sKWfjocaB+bHu}Vb$Zg;OYcdP|&|XoLD{g9aQyBoh$K7m

    V P)HG{qW(8-6;|t>-ef&2P literal 0 HcmV?d00001 diff --git a/src/parser/Atom.java b/src/parser/Atom.java new file mode 100644 index 0000000..465de81 --- /dev/null +++ b/src/parser/Atom.java @@ -0,0 +1,46 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Parser + */ + +package parser; + +/** + * This class represents an ATOM in the PL-Lisp implementation. + */ +public class Atom extends SExpression { + + private String text; + + /** + * Create a new ATOM with the specified text. + * + * @param text + * the text representing this ATOM + */ + public Atom(String text) { + this.text = text; + } + + /** + * Test if this S-expression is an ATOM. + * + * @return + * true + */ + public boolean atomp() { + return true; + } + + /** + * Returns a string representation of this ATOM. + * + * @return + * a string representation of this ATOM + */ + public String toString() { + return text; + } + +} diff --git a/src/parser/Cons.class b/src/parser/Cons.class new file mode 100644 index 0000000000000000000000000000000000000000..7d5d2c6bebd5d07d9d4f0847cc091a4aa030c23c GIT binary patch literal 991 zcmZuvO>fgs5S(WxvFo}`}r6~>IIBip)dKqNxND;>?di%u8OV)L53@KJU)%%&h(A?~h*q_VL(43Dr3iaZ?_*4BWPmL)C;U zW6fgHlefAAZd=$v-NdeZX_(kEaL2@51NQ{5zmLm0t>CwZ-02@CvW`2D6nw}`!*ab z+gQP}K>6Z;7sD{>1f&(Njr(|D;|4ZuROImx8wMV+RI_m%8@yCVr}o*TN{X!PGUv?h zc&uOA@{=TpI|4iItoT_!N)B!1<6#tW4NK>WUmqR??G&5*1xox`G(L1TzR?_`2|>fF zJj;ArV_jz~dS?(`{S=zFeG2^>Qy}Crt|(xMQ81VHzC-(}%2zYX`n0@;YpUBB3jqpa zis|(A?D~Ip?o;(IDt0aRMNxD4strue + */ + 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() + ")"); + } + +} diff --git a/src/parser/LispNumber.class b/src/parser/LispNumber.class new file mode 100644 index 0000000000000000000000000000000000000000..6f452924622d9855d6fab07420f0bdf643bfd393 GIT binary patch literal 914 zcmZ`%O>fgc5Ph33JFXj=v?0&{aY_Lvp`?@og_NR#s1&K?QdFrNkhaOnGB~#7I2Heh z3ztfeR8)dHKMI(QEd`Nqncbavnm7C2{QULpJAh5>s4!GiHLT#KhCEg^+`{cF7H~&_ zsi3Byt|5zt40lzm$@88DH9|HOtSh+BkUr(kKrpa2LuT7{?Qn;oXzst~r@ZNK*J>Vy zf$dtY+7UzQrPn3w{9(vD9}c+xhMzcM+-ZYIscyC}7O_Gx*8SeYS?J}&*7@#&q7c0~vhR};dV^}h$frKcM>r)L{sM0RxX;&E% z(oMRh=uRe6yi6}n@1)%2dZWM!i6N3Br0R`xq`xBb36+BjsK*z`9*>|khL|hp6o!}| zA@}2qdPw(5v_9k=by-B>H(e46t|+()reL`|rjt?9Ez=kYI&<~%IW9@6GVz>IMviz5 d*JE6cPFhPOQlI164OHStext 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 + * true + */ + public boolean numberp() { + return true; + } + + /** + * Retrieve the integer value of this NUMBER. + * + * @return + * the integer value of this NUMBER + */ + public int getValue() { + return value; + } + +} diff --git a/src/parser/LispParser$1.class b/src/parser/LispParser$1.class new file mode 100644 index 0000000000000000000000000000000000000000..349ebeadd49d1e8ce600871719f25582eb124a20 GIT binary patch literal 874 zcmZvaYfsZ)6vzM1R@QD5DHr9UC~B1rFY^L;jd8LL8@6tC1z+$2OV_YM(=Khn_|C-m zS$wS~#u&o~@Ix8TGmM>qruqM$U!U__&guE}`^OQ0B|I)*8Z&u}U^Y*q^BgaTnB#Df z%Ox)JTrP9D!sRL#Rm3$B3k-8=`>mHa-G<#$W5*5xH&U%|-wjmjUC(96Z0QWrQ^)rL zFL}n0EtWPJgw?P^lOyfKcJ^thW$*Yd9n3JQ1&$xaUa;G6lWy1%Q53N#<0fv&7=DD~g?`TmJMl$a4u=`w=xGZy7;qrjXLzEdNdUh1M zQMvBLy;gsy(yp@3lUVibICf(OB|W6Mv*$Vq!`O*+A|5e}|INQVn7?pbhTNg;AMov_ zilwdk$-pNJIb);oLNggAPoEdVsN)5;->)GRwV+ou!_sRyUn7}XTQfJcD(%y@Ox;+c zfL9w$OWST#%yojgRQ&XIwCSl4nFFPMW!WhQM zCkW^kGy*<;2Rr&%_=?OI{${^H5SpJLtoJcTIFzDDm`hP26jRI-N+}iym4WDC&I92x z=i~U#bhSJtF@+)Cptw%HKpn75zJdy>r6Mf>8CTwo#W#$+R4U+nAj zOaDOo1L{oc2kI#4lum8Gv@`uJ{SBQycQ+(q<&|IEAkb zByd*8IRi}?ji4Xr)iS1*3u<{w9lWh$+`vV=6G0l6bWG@&G!*x2d#UDr5rjpg_cttKO8mBprda znvO5vX?srQtu>h&Tg}RXXS-DDN-tV>tW@4|=2JB>RoiNgGM-zMIRSA)pk>H*Z10Rf zqA#$s-PE{KD0>;ND6Qqe24|Gm&ir8iH34nZ%}IffbmzGC_0v&n#3&80v);?pV1&YL)mC4t>L)J7e> zVqyR%Or-FliIaHA#LGCP*gS1^D1(k=6AlVGZks5AR|Z-t>B(9o0zGxxt7XTtmu2nH z#G4p4;h}8e4psy@s(GolO_Y~sWzobc)>L?RS(dG=*Oq5pM%Abt6jWeWRcF+7R1vOB zPfm^L_{hY^_(Zw+)Wise1@_jX3QW(H?R-vw=ZIvLgPO)?<-F~b;w!ed5I@#`EIts= z+m4KzxQEY7e2x{h`-0txXWe{x+2P5TO86Dl1P)0jH{i|<%-MMvmrmAY_L5-P@*;4c z>=b3zop3`nBQf;;RIuxb;I~F@i_$yuo#7U)BMp93>Iy4;1>U{Zg*)U2*wGtDyLI=G}JNE6e9Cu2dEX|%YHSUQnZ_K(o~H=08a z)Mf+5L+ttix^^F0=mCA{*oz)SxO;=%3}`oW3`W~W_+nxR!@NTUTBzQ3olaW*!f8eR zg!vs}YWD}sv>$8oNpR3wJ7{eQu%D4{lt${#=pJ~AWW)SFkJo8q&N9}!|z*uzipypCNPdwuzP(I zoprX0?4CNicfBEC6=-@B-80G}wy%ON#Uy`0PX+t=w@!rvv~Q)t!I=u4iyhiPJhu!P7Lk%|y9H(83cP2^E9_D{07vYZV F`yT*MB0c~B literal 0 HcmV?d00001 diff --git a/src/parser/LispParser.java b/src/parser/LispParser.java new file mode 100644 index 0000000..9a7733f --- /dev/null +++ b/src/parser/LispParser.java @@ -0,0 +1,192 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Parser + */ + +package parser; + +import scanner.*; +import java.io.*; + +/** + * A LispParser converts a stream of bytes into internal + * representations of Lisp S-expressions. When the end of stream has been + * reached the eof 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 LispParser that produces S-expressions from + * the specified input stream. + * + * @param in + * the input stream to obtain S-expressions from (must not be + * null) + * @param fileName + * the name of the file that in 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 + * true if this parser has reached the end of its underlying + * input stream; false 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); + } + } + +} diff --git a/src/parser/LispString.class b/src/parser/LispString.class new file mode 100644 index 0000000000000000000000000000000000000000..49a710fb780aa65177dbc59f1beccc463e70df4b GIT binary patch literal 190 zcmX^0Z`VEs1_l!b9xeuE22OScE_McPMg}&U%)HDJJ4Oak4WF#UvPAuy#JqI<;F6-u zymV{LFh&Lz=lqmZMh5m`uuuUb1G9!^6b}On11lqgU_oM0acYsiPiAoeL<=JWH&o2A zBtMryk%0+l83-^j0F7c`1(Iw)o)D1F1fG$T-qiDeB~ GjsXBi)gZwD literal 0 HcmV?d00001 diff --git a/src/parser/LispString.java b/src/parser/LispString.java new file mode 100644 index 0000000..66b56a3 --- /dev/null +++ b/src/parser/LispString.java @@ -0,0 +1,34 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Parser + */ + +package parser; + +/** + * This class represents a STRING in the PL-Lisp implementation. + */ +public class LispString extends Atom { + + /** + * Create a new STRING with the specified text. + * + * @param text + * the text representing this STRING + */ + public LispString(String text) { + super(text); + } + + /** + * Test if this S-expression is a STRING. + * + * @return + * true + */ + public boolean stringp() { + return true; + } + +} diff --git a/src/parser/Nil.class b/src/parser/Nil.class new file mode 100644 index 0000000000000000000000000000000000000000..73def308c914e0f0bd96520700b19c88129171b8 GIT binary patch literal 695 zcmaJ-O;5r=5PeHaTS`Si1iw&G4}b?Q-XLCx2NJ@CXri|Y4XG(xY>UzVvi6;I4 zf0S{y6pVs4>CDc&w{PFf$LH%ifMXmcpkPafhHViFBJ60`Rk5cNQdF_ekQ#COW@I(F zADFyrF&M3(>G_sdZQD+bA>FrvvtN`{sr-{9H{2dwRq8gkgA)d+R6b{j^O55W!|IYM zGjIn~#k(%|DXaed;K~)a;#)z(^ceD`sch%;Zs=LQZ@auEq(VxMC|cll0?+1shAg?b zHgC zhaxRgqm7fSc#=*cCt*-$iK-RK;*+1j9>Y^iycwYdNFkoCFg8Z4QW--ML4FFUjIO66 zYKpRuipdWVmiY%;oyVl9UBoO1`{r&Onfq}hRxZu R`A`r@zCpPdLw%Ww;|nt^Z-W2; literal 0 HcmV?d00001 diff --git a/src/parser/Nil.java b/src/parser/Nil.java new file mode 100644 index 0000000..5344053 --- /dev/null +++ b/src/parser/Nil.java @@ -0,0 +1,104 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Parser + */ + +package parser; + +/** + * This class represents NIL in the PL-Lisp implementation. + */ +public class Nil extends Cons { + + private static Nil uniqueInstance = new Nil(); + + /** + * Retrieve the single unique instance of NIL. + * + * @return + * the single unique instance of NIL + */ + public static Nil getUniqueInstance() { + return uniqueInstance; + } + + // We are using the Singleton pattern, so the constructor for 'Nil' is + // private. + private Nil() { + super(null, null); + + // the car and cdr of NIL both refer to NIL + super.setCar(this); + super.setCdr(this); + } + + /** + * Test if this S-expression is NULL. + * + * @return + * true + */ + public boolean nullp() { + return true; + } + + /** + * Test if this S-expression is an ATOM. + * + * @return + * true + */ + public boolean atomp() { + return true; + } + + /** + * Test if this S-expression is a CONS cell. + * + * @return + * false + */ + public boolean consp() { + return false; + } + + /** + * Test if this S-expression is a SYMBOL. + * + * @return + * true + */ + 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"; + } + +} diff --git a/src/parser/SExpression.class b/src/parser/SExpression.class new file mode 100644 index 0000000000000000000000000000000000000000..2c11139f14793688c0ad1349a796e638216c2258 GIT binary patch literal 632 zcmaJ-%TB^T6g|@xN}(Vi;sYOXhm8pvm&TYFm&66e1-ogfq)^(X9gKd8{(u`dCW?s* zKfsSN-oerhkII%SV^G^iHw@ZEIB*#XUeZm6h^H|lam9ks+I=~i3#Psw5poeuBsyV`Nc6o#5SDv_ zJL4{ouDR_~rXEZuwi}b8Cl3=llwRX@8aToWgE=c=FBnE93=~c1D43|DY@&)XLp|bg z;>Mlc<$V;pNkSfm>WJU*j?aT(=gJjTVE z-=Vxx2h?DqoX*q;SExpression is marked. + * + * @return + * true if this SExpression is marked; + * false 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 + * false + */ + public boolean nullp() { + return false; + } + + /** + * Test if this S-expression is an ATOM. + * + * @return + * false + */ + public boolean atomp() { + return false; + } + + /** + * Test if this S-expression is a CONS cell. + * + * @return + * false + */ + public boolean consp() { + return false; + } + + /** + * Test if this S-expression is a LIST. + * + * @return + * the value of (consp() || nullp()) + */ + public boolean listp() { + return (consp() || nullp()); + } + + /** + * Test if this S-expression is a NUMBER. + * + * @return + * false + */ + public boolean numberp() { + return false; + } + + /** + * Test if this S-expression is a SYMBOL. + * + * @return + * false + */ + public boolean symbolp() { + return false; + } + + /** + * Test if this S-expression is a FUNCTION. + * + * @return + * false + */ + public boolean functionp() { + return false; + } + + /** + * Test if this S-expression is a STRING. + * + * @return + * false + */ + public boolean stringp() { + return false; + } + +} diff --git a/src/parser/Symbol.class b/src/parser/Symbol.class new file mode 100644 index 0000000000000000000000000000000000000000..0b28c989eddf87aa31b7efcbb1dcdcfedd7e223d GIT binary patch literal 362 zcmZXP%}T>i5QV>KV)N6~*8Zq<=dRU7Htt#k>9)ISL3dF@sia9rgV1+!BZ375AHata zCp8=OUYI*`=FB;FKEK{RfHRI<_Gr0Sv@JR|wu?dA(a^Qn7vxfCOwu4*g_%EHFK?4* zC{#y_c#)qA-Tveucntg~i0A$^&ld4~IG73MIJpl6Yqgz71*1Q>5$w@jR8A@|vpDcL zr03yM6Y9TgJZv1HR)QCKvJ{$s-IS0gS7{n%<6xzZo&Mnek2uzSEZtY=6{?yUnyaZs zPpd8!z2Kajz9Jhc&sr4pI=dyMctx>_`LylXG-#H+p2`)c{*H0oGB@nJQ2mkM8-XQ2 AkN^Mx literal 0 HcmV?d00001 diff --git a/src/parser/Symbol.java b/src/parser/Symbol.java new file mode 100644 index 0000000..96f1a96 --- /dev/null +++ b/src/parser/Symbol.java @@ -0,0 +1,37 @@ +/* + * 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 + * true + */ + public boolean symbolp() { + return true; + } + +} diff --git a/src/parser/package.html b/src/parser/package.html new file mode 100644 index 0000000..ed4dbdd --- /dev/null +++ b/src/parser/package.html @@ -0,0 +1,4 @@ + + Provides the classes necessary for creating an internal representation of + the Lisp programming language. + diff --git a/src/scanner/LispFilterStream.class b/src/scanner/LispFilterStream.class new file mode 100644 index 0000000000000000000000000000000000000000..4abccba6e8c81f79a275432bc128c9a7379d1d2f GIT binary patch literal 682 zcmYjNJ#W)c6g}_x;}JJ0X@b)P$Ev~5aQD$Bd~oqO&%=e_TLzkUO-fw}>KN)9?!Wmh$* zs|wTvt_oNTB8qp9duhnP9y93eD2~z_4Ath&^WbIBih3yg9Hl0Td>aE@Z z(NzKt7?h^tGZgmHpnLcrNcMwgMKPddKu_+(6*gTpAH(%g2o z^DwZK$0g+QC}5ePd|~_WLV)57xOY1p47VyOLJn86Ea(V({q`UM6q z9jH^OCqp{(bXz5yQ(bb`&%j*eGx$fk$_2_oBT0HaC*60?ptP;x<_Na?3H%)@R?!$@ z!{S4aI}r*;VEL}lxyexfr|d$Vuqb^Gai z=owaK^lb9uy2zlI>X^hmv~hE4BSV#;{ej8YIXJWL36y_Rip4BfV9v96G|_0q&UMyu jZ%g2xMFoMpS5pHFZpN$VhV35iJoJ7^?f*Sq-L`!wu literal 0 HcmV?d00001 diff --git a/src/scanner/LispFilterStream.java b/src/scanner/LispFilterStream.java new file mode 100644 index 0000000..d9838dc --- /dev/null +++ b/src/scanner/LispFilterStream.java @@ -0,0 +1,160 @@ +/* + * 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 LispFilterStream 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 LispFilterStream with the specified underlying + * InputStream. + * + * @param in + * the underlying input stream (must not be null) + */ + 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 int in the range 0 to + * 255. If no byte is available because the end of the stream + * has been reached, the value -1 is returned. + * + * @return + * the next byte of data, or -1 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 + * -1 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 + * null) + * @param off + * the start offset in b at which the data is written (must + * be >= 0 and < b.length) + * @param len + * the maximum number of bytes to read into b (len + + * off must be < b.length) + * @return + * the total number of bytes read into the buffer, or -1 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 b + * for some reason other than reaching the end of the stream. + * @throws IndexOutOfBoundsException + * Indicates that this method attempted to access an index in + * b that was either negative or greater than or equal to + * b.length as a result of the given parameters. + * @throws NullPointerException + * Indicates that b is null. + */ + @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 0. 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; + } + +} diff --git a/src/scanner/LispScanner.class b/src/scanner/LispScanner.class new file mode 100644 index 0000000000000000000000000000000000000000..fc19894fe43c0c43088801ee9a9cbecc1e1838b0 GIT binary patch literal 2966 zcmai0X?GJ>61^=;YN^vsWP!lYb|MTJ%fjH0#aUPa7#SLDDUnTx0|XkmZ5qq6qJ@xs znaM)-VKS4DS@h9oX7a(A6Weo!b7sEJ56OQBIfUHm)?%Yd%WkSUZVVuON5Ke1o$BQyK z6T(^Ptq{(MW=_K-Y!Op3ofdIkgrnkuiWv=E$b^uWepW;wggNPpA-p7gNrQp1n5=|Q zRdG>60vQo6%i<*&l|pz$B6?NCYqI>hh&NQcsp2gKA*V1_DcRPng3Tl4oK+~;rGXKr zTpV`t6}#l^?N$)ZRZFGuxf#2l;J&7!yTIMhl#{p9)~u}{IfXbt48!t?-7JB4ZP z`}0nLdy1(bn48O2XK5w4$0<0KeF~BZ?}#%uU>1tiO5NvbJAKd5($L%_E$P#CWvCTV zN1|_4OyPoksZx(vOI^y@#fmdmD64o|K}X4EX!b=r-O_0vt5~_2QL8v^oy*h3y$u}? z1(79&ZujD{cyWbpx;lH#E>X8}*qpQr6=%wk#dfDWVozInb8_gs#krpbU(m4^?j;F9&#~u+W9MJJw{Ep5W4qQr9 zyr<(sT;`o5#KuQDK6Yn)IzDj+y*du#h>A~je1^1+&qW-=5gns48o?1}OzWz%Rl=OL zn>;Jn*xK|MJXm$|lfuI~C!ZG{;yKb_<(Ou1diw&u7jcET)*IgumyC(a!XKDkaW82& z{}O+cc>koMDq*&zGQ$cstac?#$?30jd@YJSjL$C3It8m@PsU%W&Pi8x^RwmbD!$S2 zXS}21FSxAZuX1o*gEuLPF|R-rL|Ps*=PuZ}3KiWYN#e{37TOY$wVi9HxSP-{zDWW} z^qEYXhBNn)wvE41WFq>#PB*1Chw@grY?l>iBdOu>GtV5zrqT-5-hG5A$wjt3S z1o#lMUODnf$+|tO*6mriZqM3f9|Ers`zW90>D2<e~mo?Q@-MVlUh6NqV_Q z3^vttXwht(UFJmS7VPeQc-XY*@~EDCY6)HMCFs3-?Cvqni+0m`z(oWWn3$h(_1mSQlM? z`$n>B8L@?~e`CW{1m|xa8;<$4?;(H&3Ht0771O3Jlk|#KI$sY{*YM6-yuMDa!{`+I9=)_dH z2bgR=Ho1t+Y;qC(s|b(B0+CZSZ1S*d?_Z)0neUD<*&+)ubuci0^V5~|>>v}}4N7AE z79lk6f$m1&CVyIjDojPiQAJ^%-N4f%q3b$Rdu4j@GgC*uK=eVH_+$loZC?vC9qnv_ z_Y-_N=D#u+hy~nB-Pj)sxb!r0aUMOM`hbV*p$0OphPwruY>U4uf)s;B-k*wqRu8xD8HE;2*I5IAdWGvw3>8bJ8T z=Pk-Bbe@1DeKH0M=o^?uq^E`WSMr3yls(&8-wr`uEsPO%S(f#sDeZWPH{Ym~ozrTOeFJ!B)?*IS* literal 0 HcmV?d00001 diff --git a/src/scanner/LispScanner.java b/src/scanner/LispScanner.java new file mode 100644 index 0000000..df6df9b --- /dev/null +++ b/src/scanner/LispScanner.java @@ -0,0 +1,320 @@ +/* + * 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 LispScanner 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 + * Token.Type.EOF is returned from the nextToken + * 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 LispScanner that produces Lisp tokens from the + * specified input stream. + * + * @param in + * the input stream to obtain Lisp tokens from (must not be + * null) + * @param fileName + * the name of the file that in 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 + * nextToken method of this scanner. In the case that no calls + * to nextToken have been made yet, this method returns + * null. + * + * @return + * the last Lisp token returned from this scanner or null (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 != ';')); + } + +} diff --git a/src/scanner/Token$Type.class b/src/scanner/Token$Type.class new file mode 100644 index 0000000000000000000000000000000000000000..6f4aff263d8fa1464f4dd9ed068309aece69dea8 GIT binary patch literal 1095 zcmZ`(YflqF6g|^!yVGTXQl3TLFI!M6Dx$Vx3tezyX?3@dZ2UmhT1l}kh87Zkkl$rV z#Aq~p_D31-ObM0hGSCTQ;sQtD;(1TpQ*?)Xa!@vyz??=8AS%A{OMzr zK{q|Gdazb^8;xp%p|8-WxFVA(@4v5lGeVSR=&;O<=NC)EcG)tE8&vSsR;g_4Z04*N z4B_I|=Bi;aaLcd_Yum_^z|0%Pvbk=Ge9$PZGpIA$xx$uVGxWc{x>@+htse?AgNfud z5@l`wEtyxPvhC6aB{N^kb6l_nis=cTp`OYOUs=bmm` zb}_okUDDY_x?B6*fbwk48tiDX_P`3IuIVlq@oK?HNS2|7Gt z1BBwye6X(woFVu{@(7J+{z4OwDlMkWe?#aDN=p+E6GTAP=|zxUK%HM0IYszb7P(C^ zfIHwwQEW9lCIjO6`~!*;Q-i1ACx}R*DUx(ZqK72ul%y*xNw*|XRgxY_VqB75N&2EK zUB6@l=fc4#|4F@qK3y zb*)j$F+I=nsOyK_V%zJQoM?82_m*4dvqzk@o_&TwyKg?3O~-V5%`1OoyFKE>y9;wb zf`Vha1k7NNxC~WkiLk1Fg6aDK z5_%&*Qa=bF=p`Y5sF%b5(mTz7c9yUlZRQCX^+f#xiMNQZU?ql5PUzKGTA0vlSdZBj WUnB92SX!FUb2OHreg2bX&MJS+V}msS literal 0 HcmV?d00001 diff --git a/src/scanner/Token.java b/src/scanner/Token.java new file mode 100644 index 0000000..c410102 --- /dev/null +++ b/src/scanner/Token.java @@ -0,0 +1,126 @@ +/* + * Name: Mike Cifelli + * Course: CIS 443 - Programming Languages + * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis + */ + +package scanner; + +/** + * A Token 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; + } + +} diff --git a/src/scanner/package.html b/src/scanner/package.html new file mode 100644 index 0000000..6be4f13 --- /dev/null +++ b/src/scanner/package.html @@ -0,0 +1,4 @@ + + Provides the classes necessary to perform a lexical analysis of the Lisp + programming language. + diff --git a/test/scanner/LispFilterStreamTester.java b/test/scanner/LispFilterStreamTester.java new file mode 100644 index 0000000..3de7dc6 --- /dev/null +++ b/test/scanner/LispFilterStreamTester.java @@ -0,0 +1,37 @@ +package scanner; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class LispFilterStreamTester { + + private LispFilterStream lispFilterStream; + + @Before + public void setUp() throws Exception { + lispFilterStream = new LispFilterStream(null); + } + + @Test + public void testRead() { + 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"); + } + +}