(***** lisp.m: LISP interpreter *****) (***** INSTRUCTIONS FOR USING THIS LISP INTERPRETER ***** To run the lisp.m interpreter, first enter Mathematica using the command math. To load the interpreter, enter << lisp.m To run a LISP program xyz.l and produce xyz.r, enter run @ "xyz" To run several programs, enter run /@ {"xxx","yyy","zzz"} To run the eight LISP programs in the course, enter runall Type Exit to exit from Mathematica. Here is how to run the programs that compute the halting probability Omega in the limit from below: math << lisp.m run /@ {"omega","omega2"} run @ "omega3" Exit Reference: Wolfram, Mathematica, 2nd Ed., Addison-Wesley, 1991. *****) getbit[] := Block[ {x}, trouble = False; (* Mma bug bypass *) If[ atom@ tape, (trouble = True; Throw@ "out-of-data")]; x = car@ tape; tape = cdr@ tape; If[ x === 0, 0, 1 ] ] getchar[] := FromCharacterCode[ 128*getbit[] + 64*getbit[] + 32*getbit[] + 16*getbit[] + 8*getbit[] + 4*getbit[] + 2*getbit[] + getbit[] ] getrecord[] := Block[ { c, line = "", str }, inputbuffer2 = {}; While[ "\n" =!= (c = getchar[]), line = line <> c ]; If[ trouble, Throw@ "out-of-data"]; (* Mma bug bypass *) (* keep only printable ASCII codes *) line = FromCharacterCode@ Cases[ ToCharacterCode@ line, n_Integer /; 32 <= n < 127 ]; str = StringToStream@ line; inputbuffer2 = ReadList[str, Word, TokenWords->{"(", ")"}]; Close@ str; (* convert strings of digits to integers *) inputbuffer2 = If[DigitQ@#, ToExpression@#, #]& /@ inputbuffer2 ; ] getexp[rparenokay_:False] := Block[ { w, d, l = {} }, (* supply unlimited number of )'s if tokens run out *) If[ inputbuffer2 == {}, w = ")", w = First@ inputbuffer2; inputbuffer2 = Rest@ inputbuffer2 ]; Switch[ w, ")", Return@ If[rparenokay,")",{}], "(", (While[ ")" =!= (d = getexp[True]), AppendTo[l,d] ]; Return@ l ), _, w ] ] atom[x_] := MatchQ[ x, {}|_String|_Integer ] car[x_] := If[ atom@ x, x, First@ x ] cdr[x_] := If[ atom@ x, x, Rest@ x ] cons[x_,y_] := If[ MatchQ[y,_String|_Integer], x, Prepend[y,x] ] eval[e2_,a_,d2_] := Block[ {e = e2, d = d2, f, args, x, y, z}, If[ MatchQ[e,_Integer], Return@ e ]; If[ atom@ e, Block[ {names,values,pos}, {names,values} = a; pos = Position[names,e,{1}]; Return@ If[ pos == {}, e, values[[pos[[1,1]]]] ] ]]; f = eval[car@ e,a,d]; e = cdr@ e; Switch[ f, "'", Return@ car@ e, "if", Return@ If[ eval[car@ e,a,d] =!= "false", eval[car@cdr@ e,a,d], eval[car@cdr@cdr@ e,a,d] ] ]; args = eval[#,a,d]& /@ e; x = car@ args; y = car@cdr@ args; z = car@cdr@cdr@ args; Switch[ f, "read-bit", Return@ getbit[], "read-exp", Return@ (getrecord[]; getexp[]), "bits", Return@ Flatten[ ( Rest@ IntegerDigits[256 + #, 2] )& /@ ToCharacterCode[ output@x <> "\n" ] ], "car", Return@ car@ x, "cdr", Return@ cdr@ x, "cons", Return@ cons[x,y], "size", Return@ StringLength@ output@ x, "length", Return@ Length@ x, "+", Return@ (nmb@x + nmb@y), "-", Return@ If[ nmb@x < nmb@y, 0, nmb@x - nmb@y ], "*", Return@ (nmb@x * nmb@y), "^", Return@ (nmb@x ^ nmb@y), "<", Return@ If[nmb@x < nmb@y, "true", "false"], ">", Return@ If[nmb@x > nmb@y, "true", "false"], ">=", Return@ If[nmb@x >= nmb@y, "true", "false"], "<=", Return@ If[nmb@x <= nmb@y, "true", "false"], "base10-to-2", Return@ IntegerDigits[nmb@x, 2], "base2-to-10", Return@ Fold[ (2 #1 + If[#2===0,0,1])&, 0, x ], "append", Return@ Join[ If[atom@x,{},x], If[atom@y,{},y] ], "atom", Return@ If[ atom@ x, "true", "false" ], "=", Return@ If[ x === y, "true", "false" ], "display", Return@ (AppendTo[out,x]; If[ display, print[ "display", output@ x ] ]; x), "debug", Return@ (print[ "debug", output@ x ]; x) ]; If[ d == 0, Throw@ "out-of-time" ]; d--; Switch[ f, "eval", Return@ eval[x,Null,d], "try", Return@ Block[ {out = {}, tape = z, display = False, xx}, If[ x === "no-time-limit", xx = Infinity, xx = nmb@ x ]; If[ xx < d, Catch@ {"success",eval[y,Null,xx],out} // If[ # === "out-of-time", {"failure",#,out}, # ] & , Catch@ {"success",eval[y,Null,d],out} // If[ # === "out-of-time", Throw@ #, # ] & ] // If[ # === "out-of-data", {"failure",#,out}, # ] & ] (* end block *) ]; (* end switch *) f = cdr@ f; eval[ car@cdr@ f, bind[car@ f,args,a], d ] ] nmb[n_Integer] := n nmb[_] := 0 bind[vars_?atom,args_,a_] := a bind[vars_,args_,a_] := Block[ {names,values,pos}, {names,values} = bind[ cdr@ vars, cdr@ args, a ]; pos = Position[names, car@ vars, {1}]; {Prepend[Delete[names,pos], car@ vars], Prepend[Delete[values,pos], car@ args]} ] eval[e_] := ( out = tape = {}; display = True; print[ "expression", output@ e ]; Catch[ eval[ e, {names,defs}, Infinity ] ] ) eval[e_,Null,d_] := eval[e,{{"nil"},{{}}},d] run[fn_] := run[fn, "lisp.m", ".r"] word2[]:= Block[ {w,line,str}, While[ inputbuffer == {}, line = Read[i,Record]; If[ line == EndOfFile, Abort[] ]; Print@ line; WriteString[o,line,"\n"]; (* keep only printable ASCII codes *) line = FromCharacterCode@ Cases[ ToCharacterCode@ line, n_Integer /; 32 <= n < 127 ]; str = StringToStream@ line; inputbuffer = ReadList[str, Word, TokenWords->{"(", ")", "[", "]", "'", "\""}]; Close@ str ]; w = First@ inputbuffer; inputbuffer = Rest@ inputbuffer; If[DigitQ@w, ToExpression@w, w] (* convert string of digits to integer *) ] word[] := Block[ {w}, While[ True, w = word2[]; If[ w =!= "[", Return@ w ]; While[ word[] =!= "]" ] ] ] get[sexp_:False,rparenokay_:False] := Block[ {w = word[], d, l ={}, name, def, body, varlist}, Switch[ w, ")", Return@ If[rparenokay,")",{}], "(", While[ ")" =!= (d = get[sexp,True]), AppendTo[l,d] ]; Return@ l ]; If[ sexp, Return@ w ]; Switch[ w, "\"", get[True], "cadr", {"car",{"cdr",get[]}}, "caddr", {"car",{"cdr",{"cdr",get[]}}}, "let", {name,def,body} = {get[],get[],get[]}; If[ !MatchQ[name,{}|_String|_Integer], varlist = Rest@ name; name = First@ name; def = {"'",{"lambda",varlist,def}} ]; {{"'",{"lambda",{name},body}},def}, "read-bit"|"read-exp", {w}, "car"|"cdr"|"atom"|"'"|"display"|"eval"|"bits"|"debug"| "length"|"size"|"base2-to-10"|"base10-to-2", {w,get[]}, "cons"|"="|"lambda"|"append"|"define"|"+"|"-"|"*"|"^"|"<"|">"|"<="|">=", {w,get[],get[]}, "if"|"let"|"try", {w,get[],get[],get[]}, _, w ] ] (* output S-exp *) output2[x_String] := x<>" " output2[x_Integer] := ToString[x]<>" " output2[{x___}] := Block[ {s}, s = StringJoin["(", output2 /@ {x}]; If[ StringTake[s,-1] == " ", s = StringDrop[s,-1] ]; s <> ") " ] output[x_] := StringDrop[ output2@x ,-1 ] blanks = StringJoin@ Table[" ",{12}] print[x_,y_] := (print2[x,StringTake[y,50]]; print["",StringDrop[y,50]]) /; StringLength[y] > 50 print[x_,y_] := print2[x,y] print2[x_,y_] := print3[StringTake[x<>blanks,12]<>y] print3[x_] := (Print[x]; WriteString[o,x,"\n"]) let[n_,d_] := ( print[ "define", output@ n ]; print[ "value", output@ d ]; PrependTo[names,n]; PrependTo[defs,d]; ) run[fn_,whoami_,outputsuffix_] := ( inputbuffer = {}; names = {"nil"}; defs = {{}}; t0 = SessionTime[]; o = OpenWrite[fn<>outputsuffix]; i = OpenRead[fn<>".l"]; print3["LISP Interpreter Run"]; print3@ ""; CheckAbort[ While[True, (print3@ ""; Replace[#,{ {"define",{func_,vars___},def_} :> let[func,{"lambda",{vars},def}], {"define",var_,def_} :> let[var,def], _ :> print[ "value", output@ eval@ # ] }] )& @ get[]; print3@ "" ],Null ]; print3@ "End of LISP Run"; print3@ ""; print3@ StringForm[ "Elapsed time is `` seconds.", Round[SessionTime[]-t0] ]; Close@ i; Close@ o ) runall := run /@ {"examples","godel","utm","godel2", "omega","omega2","omega3","godel3"} $RecursionLimit = $IterationLimit = Infinity SetOptions[$Output,PageWidth->Infinity];