Skip to content

Instantly share code, notes, and snippets.

@swatson555
Created October 12, 2025 17:52
Show Gist options
  • Select an option

  • Save swatson555/698f8b97581c2199ec4ea3fd60c19f06 to your computer and use it in GitHub Desktop.

Select an option

Save swatson555/698f8b97581c2199ec4ea3fd60c19f06 to your computer and use it in GitHub Desktop.
/* A tiger program that evaluates a lisp program.
*/
let type tokens = { head: string, tail: tokens }
function stridx (input: string, i: int): string =
substring (input,i,1)
function numeric (s : string): int =
ord (s) >= ord ("0") & ord (s) <= ord ("9") | ord (s) = ord ("-")
function atoi (str: string): int =
let var start := stridx (str, 0) = "-"
var val := 0
in for i := start to size (str)-1
do val := val * 10 + ord(stridx (str, i)) - ord("0");
if start = 1
then -val
else val
end
function analyze (input: string): tokens =
let function loop (i: int): tokens =
if i = size(input)
then nil
else if stridx (input, i) = " "
then loop (i+1)
else if stridx (input, i) = "("
then tokens { head="(", tail=loop(i+1) }
else if stridx (input, i) = ")"
then tokens { head=")", tail=loop(i+1) }
else let var n := i
in while size(input) <> i &
stridx (input, i) <> "(" &
stridx (input, i) <> ")" &
stridx (input, i) <> " "
do i := i+1;
tokens { head=substring (input,n,i-n), tail=loop(i) }
end
in loop (0)
end
type list = { head: exp, tail: list }
type exp = { id: string, pair: list }
function read (program: tokens): exp =
let var begin := program
function eat (): string =
let var token := begin.head
in begin := begin.tail;
token
end
function peek (): string =
begin.head
function exp (): exp =
let var tok := eat ()
in if tok = "("
then exp { id="", pair=list () }
else exp { id=tok, pair=nil }
end
function list (): list =
let var tok := peek ()
in if tok = ")"
then (eat (); nil)
else list { head=exp (), tail=list () }
end
in exp ()
end
function readin (): string =
let var buffer := getchar ()
var text := ""
in while buffer<>"\n"
do (text := concat (text, buffer);
buffer := getchar ());
text
end
function display (i: int) =
let function f (i: int) =
if i > 0
then (f( i/10); print (chr (i-i/10*10+ord ("0"))))
in if i < 0
then (print ("-"); f (-i))
else if i > 0
then f (i)
else print ("0")
end
type env = { entry: binding, tail: env }
type binding = { id: string, value: int }
var top: env := nil
function put (id: string, val: int) =
top := env { entry=binding { id=id, value=val }, tail=top }
function get (id: string): int =
let function search (env: env): int =
if env.entry.id = id
then env.entry.value
else search (env.tail)
in search (top)
end
function eval (e: exp): int =
if numeric (e.id)
then atoi (e.id)
else if e.id <> ""
then get (e.id)
else if e.pair.head.id = "+"
then eval (e.pair.tail.head) + eval (e.pair.tail.tail.head)
else if e.pair.head.id = "-"
then eval (e.pair.tail.head) - eval (e.pair.tail.tail.head)
else if e.pair.head.id = "*"
then eval (e.pair.tail.head) * eval (e.pair.tail.tail.head)
else if e.pair.head.id = "/"
then eval (e.pair.tail.head) / eval (e.pair.tail.tail.head)
else if e.pair.head.id = "set!"
then (put (e.pair.tail.head.id, eval (e.pair.tail.tail.head)); 1)
else 0
function repl () =
(print (">> ");
display (eval (read (analyze (readin ()))));
print ("\n"))
in while 1
do repl ()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment