Untitled


SUBMITTED BY: Guest

DATE: Nov. 26, 2013, 6:24 p.m.

FORMAT: Text only

SIZE: 22.2 kB

HITS: 7085

  1. (***********************************************************)
  2. (* LISP Interpreter *)
  3. (* *)
  4. (* Your Name Here *)
  5. (* Reference Skeleton, CSCI 350 *)
  6. (* *)
  7. (***********************************************************)
  8. open Printf;;
  9. open Stream;;
  10. exception ParseError of string;;
  11. exception ParseFailure of string;;
  12. exception ParseOK;;
  13. exception ParseEOF;;
  14. exception EvalError of string;;
  15. exception UnboundVar;;
  16. exception ParameterMismatch;;
  17. (***********************************************************)
  18. (* type declarations *)
  19. (***********************************************************)
  20. type sign =
  21. Plus
  22. | Minus
  23. ;;
  24. type atom =
  25. T
  26. | NIL
  27. | Int of int
  28. | Ident of string
  29. ;;
  30. type token =
  31. Lparen
  32. | Rparen
  33. | Dot
  34. | Sign of sign
  35. | Atom of atom
  36. ;;
  37. type sexp =
  38. AtomExp of atom
  39. | Sexp of sexp * sexp
  40. ;;
  41. (***********************************************************)
  42. (* globals *)
  43. (***********************************************************)
  44. let lineno = ref 1;;
  45. let top_level = ref true;;
  46. let dlist = ref (AtomExp(NIL));;
  47. (***********************************************************)
  48. (* printing functions *)
  49. (***********************************************************)
  50. (* function: print_tokens - prints out a token stream *)
  51. let rec print_tokens ts =
  52. match ts with parser
  53. [< 'Lparen; _ >] -> printf("Lparen "); print_tokens ts
  54. | [< 'Rparen; _ >] -> printf("Rparen "); print_tokens ts
  55. | [< 'Dot; _ >] -> printf("Dot "); print_tokens ts
  56. | [< 'Sign s; _ >] -> (match s with
  57. Plus -> printf("Plus "); print_tokens ts
  58. | Minus -> printf("Minus "); print_tokens ts)
  59. | [< 'Atom a; _ >] -> (match a with
  60. T -> printf("Atom(T) "); print_tokens ts
  61. | NIL -> printf("Atom(NIL) "); print_tokens ts
  62. | Int n -> printf("Atom(Int(%d)) ") n; print_tokens ts
  63. | Ident s -> printf("Atom(Ident(%s)) ") s; print_tokens ts)
  64. | [< >] -> printf("\n")
  65. ;;
  66. (* function: string_of_op - converts an operator token to a string *)
  67. let string_of_op o =
  68. match o with
  69. Plus -> "+"
  70. | Minus -> "-"
  71. ;;
  72. (* function: is_list - predicate function returning true if s-expression is a list *)
  73. let rec is_list s =
  74. match s with
  75. Sexp(h, AtomExp(NIL)) -> true
  76. | Sexp(h, t) -> is_list t
  77. | _ -> false
  78. ;;
  79. (* function: string_of_atom - converts a primitive atom to a string *)
  80. let string_of_atom a =
  81. match a with
  82. T -> "t"
  83. | NIL -> "nil"
  84. | Int(i) -> string_of_int i
  85. | Ident(i) -> i
  86. ;;
  87. (* function: string_of_token - converts a lexer token to a string *)
  88. let string_of_token t =
  89. match t with
  90. Lparen -> "("
  91. | Rparen -> ")"
  92. | Dot -> "."
  93. | Sign(o) -> string_of_op o
  94. | Atom(a) -> string_of_atom a
  95. ;;
  96. (* function: print_list - prints an s-expression in list format *)
  97. let rec print_list s =
  98. match s with
  99. AtomExp(NIL) -> ()
  100. | AtomExp(a) -> printf("%s") (string_of_atom a)
  101. | Sexp(h,AtomExp(NIL)) -> print_sexp h
  102. | Sexp(h,t) ->
  103. (print_sexp h;
  104. printf(" ");
  105. print_list t)
  106. (* function: print_sexp - prints an s-expression in either dotted or list format *)
  107. and print_sexp s =
  108. if (is_list s) then
  109. (printf("(");
  110. print_list s;
  111. printf(")");)
  112. else
  113. (match s with
  114. AtomExp(a) -> printf("%s") (string_of_atom a)
  115. | Sexp(h,t) ->
  116. (printf("(");
  117. print_sexp h;
  118. printf(" . ");
  119. print_sexp t;
  120. printf(")")))
  121. ;;
  122. (***********************************************************)
  123. (* lexer implementation *)
  124. (***********************************************************)
  125. let rec spaces s =
  126. match s with parser
  127. [< '' '|'\t'; _ >] -> spaces s
  128. | [< ''\n' ; _ >] -> incr lineno; spaces s
  129. | [< >] -> ()
  130. ;;
  131. let rec lexid str s =
  132. match s with parser
  133. [< ''a'..'z'|'A'..'Z'|'0'..'9' as c ; _ >] -> lexid (str ^ (Char.escaped c)) s
  134. | [< >] -> str
  135. ;;
  136. let rec lexint v s =
  137. match s with parser
  138. [< ''0'..'9' as n; _ >] -> lexint ((10*v)+(int_of_string (Char.escaped n))) s
  139. | [< >] -> v
  140. ;;
  141. let rec lexer s =
  142. match s with parser
  143. [< ''(' ; _ >] -> [< 'Lparen ; lexer s >]
  144. | [< '')' ; _ >] -> [< 'Rparen ; lexer s >]
  145. | [< ''.' ; _ >] -> [< 'Dot ; lexer s >]
  146. | [< ''-' ; _ >] -> [< 'Sign(Minus) ; lexer s >]
  147. | [< ''+' ; _ >] -> [< 'Sign(Plus) ; lexer s >]
  148. | [< ''a'..'z'|'A'..'Z' as c; _ >] -> [< 'Atom(Ident(lexid (Char.escaped c) s)); lexer s >]
  149. | [< ''0'..'9' as n; _ >] -> [< 'Atom(Int(lexint (int_of_string (Char.escaped n)) s)); lexer s >]
  150. | [< '' '|'\t' ; _ >] -> spaces s; [< lexer s >]
  151. | [< ''\n' ; _ >] -> incr lineno; spaces s; [< lexer s >]
  152. | [< 'c >] -> printf("ERROR: Illegal character on line %d: %c\n") !lineno c; lexer s
  153. ;;
  154. (***********************************************************)
  155. (* parser implementation *)
  156. (***********************************************************)
  157. (* function: eat - consumes next value in token stream *)
  158. let eat ts = try next ts; () with Stream.Failure -> ();;
  159. (* function: check_sign - both validates and combines sign and integer token pairs *)
  160. let check_sign s ts =
  161. let lookahead = peek ts in
  162. match lookahead with
  163. Some t ->
  164. (match t with
  165. Atom a ->
  166. (match a with
  167. Int a ->
  168. if (s=Minus) then
  169. (eat ts; AtomExp(Int(-a)))
  170. else
  171. (eat ts; AtomExp(Int(a)))
  172. | _ -> raise (ParseError("+/- sign may only be used with integer literals")))
  173. | _ -> raise (ParseError("+/- sign may only be used with integer literals")))
  174. | None -> raise (ParseError("EOF found before complete parsing of integer literal"))
  175. ;;
  176. (* function: check_atom - converts identifiers to internal primitives, nested defun check *)
  177. let check_atom a =
  178. match a with
  179. Ident i -> (
  180. match i with
  181. "T" | "t" -> AtomExp(T)
  182. | "NIL" | "nil" -> AtomExp(NIL)
  183. | "DEFUN" | "defun" ->
  184. if !top_level = true then
  185. AtomExp(a)
  186. else
  187. raise (ParseError("DEFUN used outside of top-level"))
  188. | _ -> AtomExp(a))
  189. | _ -> AtomExp(a)
  190. ;;
  191. (* function: parse_sexp - top-level parser: takes stream of tokens, returns sexp-tree *)
  192. (* S ::= E *)
  193. let rec parse_sexp ts =
  194. try
  195. top_level := true;
  196. let lookahead = (peek ts) in
  197. match lookahead with
  198. Some cur -> parse_exp ts
  199. | None -> raise ParseOK
  200. with
  201. Stream.Failure -> raise ParseOK
  202. | ParseFailure msg -> raise (ParseError(msg))
  203. | ParseEOF -> raise (ParseError("found EOF before complete s-expression parsing"))
  204. (* E ::= atom | '(' X *)
  205. and parse_exp ts =
  206. try
  207. let lookahead = (peek ts) in
  208. match lookahead with
  209. Some cur ->
  210. (match cur with
  211. Lparen -> eat ts; parse_x ts
  212. | Sign(s) -> eat ts; check_sign s ts
  213. | Atom(a) -> eat ts; check_atom a
  214. | _ -> raise (ParseFailure("parser expected '(' or an atom expression")))
  215. | None -> raise (ParseFailure("parse ended expecting '(' or an atom expression"))
  216. with
  217. Stream.Failure -> raise (ParseFailure("found EOF before complete s-expression parsing"))
  218. (* X ::= E Y | ')' *)
  219. and parse_x ts =
  220. try
  221. let lookahead = (peek ts) in
  222. match lookahead with
  223. Some cur ->
  224. (match cur with
  225. Rparen -> eat ts; AtomExp(NIL) (* handle '()' *)
  226. | _ -> let e = parse_exp ts in
  227. let y = parse_y ts in
  228. Sexp(e,y))
  229. | None -> raise (ParseFailure("parser ended expecting ')' or an s-expression"))
  230. with
  231. Stream.Failure -> raise (ParseFailure("found EOF before complete s-expression parsing"))
  232. (* Y ::= '.' E ')' | R ')' *)
  233. and parse_y ts =
  234. try
  235. let lookahead = (peek ts) in
  236. match lookahead with
  237. Some cur ->
  238. (match cur with
  239. Dot ->
  240. eat ts;
  241. let e = parse_exp ts in
  242. parse_rparen ts; e
  243. | _ -> let r = parse_r ts in
  244. parse_rparen ts; r)
  245. | None -> raise (ParseFailure("parser ended expecting '.' or an s-expression"))
  246. with
  247. Stream.Failure -> raise (ParseFailure("found EOF before complete s-expression parsing"))
  248. (* R ::= E R | empty *)
  249. and parse_r ts =
  250. let lookahead = (peek ts) in
  251. match lookahead with
  252. Some cur ->
  253. (match cur with
  254. Lparen|Sign(_)|Atom(_) ->
  255. let e = parse_exp ts in
  256. let r = parse_r ts in
  257. Sexp(e,r)
  258. | _ -> AtomExp(NIL))
  259. | None -> raise (ParseFailure("parser ended expecting ')' or an s-expression"))
  260. (* convenience production for right parens *)
  261. and parse_rparen ts =
  262. try
  263. let lookahead = (peek ts) in
  264. match lookahead with
  265. Some cur ->
  266. (match cur with
  267. Rparen -> eat ts;
  268. | _ -> raise (ParseFailure("expected ')'")))
  269. | None -> raise (ParseFailure("parser ended expecting ')'"))
  270. with
  271. Stream.Failure -> raise (ParseFailure("found EOF before complete s-expression parsing"))
  272. ;;
  273. (*****************************************)
  274. (* interpretation functions *)
  275. (*****************************************)
  276. (* function: bound - checks that referenced variables are bound in a-list *)
  277. (* returns true if found, false otherwise x is a string *)
  278. let rec bound x alist =
  279. match alist with
  280. Sexp(AtomExp(Ident(group)),threst) ->
  281. if x == group then true else bound x threst
  282. |_ -> false
  283. ;;
  284. (* function: getval - returns the value of a variable from the a-list & d-list name is a string*)
  285. let rec getval name alist =
  286. match alist with
  287. Sexp(Sexp(AtomExp(Ident(group)), var),threst) ->
  288. if (name == group) then var else (getval name threst)
  289. |_-> raise(EvalError("Dick jones says I know."))
  290. ;;
  291. (* function: eval_defun - checks defun usage and adds function def to the global d-list *)
  292. (* returns unit *)
  293. let eval_defun s a d =
  294. (* modifies !d / d:= Sexp() *)
  295. match s with
  296. Sexp(AtomExp(Ident(name)),Sexp(AtomExp(Ident(formals)),Sexp(AtomExp(Ident(body)),AtomExp(NIL)))) ->
  297. Sexp(Sexp(AtomExp(Ident(name)),Sexp(AtomExp(Ident(formals)),AtomExp(Ident(body)))),!d)
  298. |_ -> AtomExp(NIL)
  299. ;;
  300. (* function: check_formal - checks function parameters from matching T or NIL *)
  301. let check_formal x =
  302. match x with
  303. AtomExp(T) -> raise (EvalError("Formal parameters may not be 'T'"))
  304. | AtomExp(NIL) -> raise (EvalError("Formal parameters may not be 'NIL'"))
  305. | _ -> ()
  306. ;;
  307. (* function: addpairs - checks function parameters and binds formals to actuals *)
  308. (* returns an s-expression *)
  309. let rec addpairs xlist ylist z =
  310. (* calls check_formal *)
  311. match xlist with
  312. Sexp(Sexp(AtomExp(xy), t), Sexp(AtomExp(yl), v)) -> addpairs t v (Sexp(z,(Sexp(AtomExp(xy), AtomExp(yl)))))
  313. |_-> z
  314. ;;
  315. (* function: eval - top-level s-expression evaluation loop *)
  316. (* returns an s-expression *)
  317. let rec eval exp a d =
  318. match exp with
  319. AtomExp(T) -> AtomExp(T)
  320. |AtomExp(NIL) -> AtomExp(NIL)
  321. |AtomExp(Int(_)) -> exp
  322. |AtomExp(Ident(s)) -> if ((bound s a) ==true) then (getval s a) else raise (EvalError ("You done goof'd"))
  323. |_-> (match exp with
  324. Sexp(AtomExp(Ident("QUOTE")), Sexp(h,r)) -> if (r <> AtomExp(NIL))
  325. then (raise (EvalError("Honey badger says you can't quote"))) else h
  326. |Sexp(AtomExp(Ident("COND")), r) -> evcon r a d
  327. |Sexp(AtomExp(Ident("DEFUN")), r) -> eval_defun r a d
  328. |Sexp(h, t) -> apply h (evlist t a d) a d
  329. |_ -> raise(EvalError("Hide your kids, Hide your wives")))
  330. (* function: evcon - evaluates a COND statement *)
  331. (* returns an s-expression *)
  332. and evcon x a d =
  333. match x with
  334. AtomExp(NIL) -> raise(EvalError("Nyan cat does not approve"))
  335. |Sexp(Sexp(h,j), Sexp(q, t))-> Sexp((eval h a d), (eval q a d))
  336. |Sexp(h, t) -> evcon t a d
  337. |_-> raise(EvalError("Y u No Cons Right?"))
  338. (* function: evlist - evaluates a list of expressions and returns a list of results *)
  339. (* returns an s-expression *)
  340. and evlist sexp a d =
  341. match sexp with
  342. Sexp(h,t) -> Sexp((eval h a d),(evlist t a d))
  343. |_ -> raise(EvalError("No can do mon"))
  344. (* function: apply - performs function application, handles built-ins *)
  345. (* returns an s-expression
  346. Takes a car of an sexp, an sexp, a-list, d-list *)
  347. and apply f x a d =
  348. match f with
  349. Sexp(AtomExp(Ident("CAR")),_) ->
  350. match x with
  351. Sexp(Sexp(fh,ft),Sexp(sh,st)) -> fh
  352. |_-> raise(EvalError("Stars Wars Kid can code better than this"))
  353. |Sexp(AtomExp(Ident("CDR")),_) ->
  354. match x with
  355. Sexp(Sexp(fh,ft),Sexp(sh,st)) -> ft
  356. |_-> raise(EvalError("Professor Oak says your not a girl or boy"))
  357. |Sexp(AtomExp(Ident("CONS")),_) ->
  358. match x with
  359. Sexp(car,Sexp(sh,st)) -> Sexp(car,sh)
  360. |_-> raise(EvalError("Change major while you still can"))
  361. |Sexp(AtomExp(Ident("ATOM")),_) ->
  362. match x with
  363. Sexp(car, cdr) -> car
  364. |_-> raise(EvalError("Ash Ketchum GO STD'S"))
  365. |Sexp(AtomExp(Ident("EQ")), _) ->
  366. match x with
  367. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) ->
  368. if first <> sec then AtomExp(NIL) else AtomExp(T)
  369. |_-> raise(EvalError("Epic Baby FAIL"))
  370. |Sexp(AtomExp(Ident("INT")),_) ->
  371. match x with
  372. Sexp(AtomExp(Ident(first)),AtomExp(NIL)) -> AtomExp(NIL)
  373. |Sexp(AtomExp(Int(first)),AtomExp(NIL)) -> AtomExp(T)
  374. |_-> raise(EvalError("Awkward Penguin 0_o"))
  375. |Sexp(AtomExp(Ident("NULL")),_) ->
  376. match x with
  377. Sexp(AtomExp(NIL), AtomExp(NIL)) -> AtomExp(T)
  378. |Sexp(AtomExp(_),AtomExp(NIL)) -> AtomExp(NIL)
  379. |_ -> raise(EvalError("You can't nill, null, nor read instructions son"))
  380. |Sexp(AtomExp(Ident("PLUS")),_)->
  381. match x with
  382. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> AtomExp(Int(first+sec))
  383. |_-> raise(EvalError("Trololol"))
  384. |Sexp(AtomExp(Ident("MINUS")),_)->
  385. match x with
  386. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> AtomExp(Int(first-sec))
  387. |_-> raise(EvalError("Tech Something Mother FAIL"))
  388. |Sexp(AtomExp(Ident("TIMES")),_)->
  389. match x with
  390. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> AtomExp(Int(first*sec))
  391. |_-> raise(EvalError("Music Obvious Eighth Grader says B flat"))
  392. |Sexp(AtomExp(Ident("QUOTIENT")),_)->
  393. match x with
  394. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> if sec == 0 then raise(EvalError("YOU BLEW UP THE WORLD"))
  395. else AtomExp(Int(first/sec))
  396. |_-> raise(EvalError("Pickup Line Panda says Hi"))
  397. |Sexp(AtomExp(Ident("REMAINDER")),_) ->
  398. match x with
  399. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> AtomExp(Int((first mod sec)))
  400. |_-> raise(EvalError("Forever Alone"))
  401. |Sexp(AtomExp(Ident("LESS")),_) ->
  402. match x with
  403. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> if first < sec then
  404. AtomExp(T) else AtomExp(NIL)
  405. |_-> raise(EvalError("Lesser Soul Crystal Needed"))
  406. |Sexp(AtomExp(Ident("GREATER")),_) ->
  407. match x with
  408. Sexp(AtomExp(Int(first)), AtomExp(Int(sec))) -> if first > sec then
  409. AtomExp(T) else AtomExp(NIL)
  410. |_-> raise(EvalError("Nothings is Greater than Chuck Norris"))
  411. |_ -> match f with
  412. Sexp(AtomExp(Ident(fname)), _) -> if ((bound fname !d) == true)
  413. then
  414. let
  415. stuffz = (getval fname !d)
  416. in
  417. match stuffz with
  418. Sexp(h,t) -> (eval t (addpairs h x a) d)
  419. |_-> raise(EvalError("Hey stop that!"))
  420. else raise(EvalError("Nope! Chuck Testa."))
  421. |_-> raise(EvalError("Don't look at me"))
  422. ;;
  423. (*****************************************)
  424. (* helper routines *)
  425. (*****************************************)
  426. (* function: get_sexp - wrapper function around parser to catch stream failures *)
  427. let get_sexp s =
  428. try
  429. let sexplist = parse_sexp s in
  430. sexplist
  431. with
  432. Stream.Failure -> AtomExp(NIL)
  433. ;;
  434. (* function: next_sexp - recursive function which tries to evaluate as much as possible *)
  435. let rec next_sexp ts =
  436. try
  437. let e = (eval (get_sexp ts) (AtomExp(NIL)) dlist) in
  438. print_sexp e; printf("\n"); next_sexp ts
  439. with
  440. ParseError e -> printf("Parse Error: %s\n") e
  441. | EvalError e -> printf("Evaluation Error: %s\n") e; next_sexp ts
  442. | ParseOK -> exit 0
  443. ;;
  444. (*****************************************)
  445. (* main *)
  446. (*****************************************)
  447. let ts = lexer (Stream.of_channel stdin) in
  448. try
  449. (* read/evaluate/print loop *)
  450. (print_sexp(eval (get_sexp ts) (AtomExp(NIL)) dlist);
  451. printf("\n");
  452. next_sexp ts)
  453. with
  454. ParseError e -> printf("Parse Error: %s\n") e
  455. | EvalError e -> printf("Evaluation Error: %s\n") e; next_sexp ts
  456. | ParseOK -> exit 0
  457. ;;

comments powered by Disqus