Skip to content

Commit 85c837f

Browse files
committed
Start on iniquity notes.
1 parent c12408a commit 85c837f

11 files changed

Lines changed: 1719 additions & 0 deletions

File tree

www/notes/iniquity.scrbl

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#lang scribble/manual
2+
3+
@(require (for-label (except-in racket ...)))
4+
@(require redex/pict
5+
racket/runtime-path
6+
scribble/examples
7+
"hustle/semantics.rkt"
8+
"utils.rkt"
9+
"ev.rkt"
10+
"../utils.rkt")
11+
12+
@(define codeblock-include (make-codeblock-include #'h))
13+
14+
@(for-each (λ (f) (ev `(require (file ,(path->string (build-path notes "iniquity" f))))))
15+
'() #;'("interp.rkt" "compile.rkt" "asm/interp.rkt" "asm/printer.rkt"))
16+
17+
@title[#:tag "Iniquity"]{Iniquity: function definitions and calls}
18+
19+
@table-of-contents[]
20+
21+
@section[#:tag-prefix "iniquity"]{Functions}
22+
23+
Our programming languages so far have been impoverished in the
24+
following sense: in order to process arbitrarily large data, the
25+
programs themselves must be proportionally as large. Want to compute
26+
something over a billion element list? You'll need a billion
27+
expressions. Consequently, the expressiveness of our language is
28+
severely restricted.
29+
30+
Let's now remove that restriction by incorporating @bold{functions},
31+
and in particular, @bold{recursive functions}, which will allow us to
32+
compute over arbitrarily large data with finite-sized programs.
33+
34+
Let's call it @bold{Iniquity}.
35+
36+
We will extend the syntax by introducing a new syntactic category of
37+
programs, which have the shape:
38+
39+
@racketblock[
40+
(begin
41+
(define (_f0 _x0 ...) _e0)
42+
(define (_f1 _x1 ...) _e1)
43+
...
44+
_e)]
45+
46+
And the syntax of expressions will be extended to include function calls:
47+
48+
@racketblock[
49+
(_fi _e0 ...)
50+
]
51+
52+
where @racket[_fi] is one of the function names defined in the program.
53+
54+
Note that functions can have any number of parameters and,
55+
symmetrically, calls can have any number of arguments. A program
56+
consists of zero or more function definitions followed by an
57+
expression.
58+
59+
60+
@section[#:tag-prefix "iniquity"]{An Interpreter for Functions}
61+
62+
Writing an interpreter for Inquity is not too hard. The main idea is
63+
that the interpretation of expression is now parameterized by a set of
64+
function definitions from the program. It serves as a second kind of
65+
environment that gets passed around and is used to resolve function
66+
definitions when interpreting function calls.
67+
68+
The way a function call is interpreted is to first interpret all of
69+
the arguments, building up a list of results. Then the definition of
70+
the function being called is looked up. If the function has the same
71+
number of parameters as there are arguments in the call, the body of
72+
the function is interpreted in an enviorment that maps each parameter
73+
to to the corresponding argument. That's it.
74+
75+
@codeblock-include["iniquity/interp.rkt"]
76+
77+
A couple of things to note:
78+
79+
@itemlist[
80+
81+
@item{since the function definition environment is passed along even
82+
when interpreting the body of function definitions, this
83+
interpretation supports recursion, and even mutual recursion.}
84+
85+
@item{functions are @emph{not} values (yet). We cannot bind a
86+
variable to a function. We cannot make a list of functions. We
87+
cannot compute a function. The first position of a function call is a
88+
function @emph{name}, not an arbitrary expression. Nevertheless, we
89+
have significantly increased the expressivity of our language.}
90+
91+
]
92+

www/notes/iniquity/Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
UNAME := $(shell uname)
2+
.PHONY: test
3+
4+
ifeq ($(UNAME), Darwin)
5+
format=macho64
6+
else ifeq ($(UNAME), Linux)
7+
format=elf64
8+
else
9+
format=win64
10+
endif
11+
12+
%.run: %.o main.o char.o
13+
gcc main.o char.o $< -o $@
14+
15+
main.o: main.c types.h
16+
gcc -c main.c -o main.o
17+
18+
char.o: char.c types.h
19+
gcc -c char.c -o char.o
20+
21+
%.o: %.s
22+
nasm -f $(format) -o $@ $<
23+
24+
%.s: %.rkt
25+
racket -t compile-file.rkt -m $< > $@
26+
27+
clean:
28+
rm *.o *.s *.run
29+
30+
test: 42.run
31+
@test "$(shell ./42.run)" = "42"

www/notes/iniquity/asm/ast.rkt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#lang racket
2+
3+
;; type Asm = [Listof Instruction]
4+
5+
;; type Instruction =
6+
;; | `ret
7+
;; | `(mov ,Arg ,Arg)
8+
;; | `(add ,Arg ,Arg)
9+
;; | `(sub ,Arg ,Arg)
10+
;; | `(cmp ,Arg ,Arg)
11+
;; | `(jmp ,Label)
12+
;; | `(je ,Label)
13+
;; | `(jne ,Label)
14+
;; | `(neg ,Arg)
15+
;; | `(cmovl ,Arg Arg)
16+
;; | Label
17+
18+
;; type Label = Symbol
19+
20+
;; type Arg =
21+
;; | Reg
22+
;; | Integer
23+
24+
;; type Reg =
25+
;; | `rax
26+
;; | `rbx

www/notes/iniquity/asm/interp.rkt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#lang racket
2+
(provide (all-defined-out))
3+
(require "printer.rkt" racket/runtime-path)
4+
(define-runtime-path dir "..")
5+
6+
;; Asm -> Integer
7+
;; Interpret (by assemblying, linking, and exec'ing) x86-64 code
8+
;; Assume: starts with entry point run-time expects
9+
(define (asm-interp a)
10+
(let* ((t.s (make-temporary-file "nasm~a.s"))
11+
(t.run (path-replace-extension t.s #".run")))
12+
(with-output-to-file t.s
13+
#:exists 'truncate
14+
(λ ()
15+
(asm-display a)))
16+
(system (format "(cd ~a && make -s ~a) 2>&1 >/dev/null" dir t.run))
17+
(delete-file t.s)
18+
(with-input-from-string
19+
(with-output-to-string
20+
(λ ()
21+
(system (path->string t.run))
22+
(delete-file t.run)))
23+
read)))

www/notes/iniquity/asm/printer.rkt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#lang racket
2+
(provide (all-defined-out))
3+
4+
;; Asm -> String
5+
(define (asm->string a)
6+
(foldr (λ (i s) (string-append (instr->string i) s)) "" a))
7+
8+
;; Instruction -> String
9+
(define (instr->string i)
10+
(match i
11+
[`(,(? opcode2? o) ,a1 ,a2)
12+
(string-append "\t"
13+
(symbol->string o) " "
14+
(arg->string a1) ", "
15+
(arg->string a2) "\n")]
16+
[`(jmp ,l)
17+
(string-append "\tjmp " (arg->string l) "\n")]
18+
[`(je ,l)
19+
(string-append "\tje " (label->string l) "\n")]
20+
[`(jle ,l)
21+
(string-append "\tjle " (label->string l) "\n")]
22+
[`(jl ,l)
23+
(string-append "\tjl " (label->string l) "\n")]
24+
[`(jg ,l)
25+
(string-append "\tjg " (label->string l) "\n")]
26+
[`(jge ,l)
27+
(string-append "\tjge " (label->string l) "\n")]
28+
[`(jne ,l)
29+
(string-append "\tjne " (label->string l) "\n")]
30+
[`ret "\tret\n"]
31+
[`(neg ,a1)
32+
(string-append "\tneg " (arg->string a1) "\n")]
33+
[`(call ,l)
34+
(string-append "\tcall " (label->string l) "\n")]
35+
[`(push ,r)
36+
(string-append "\tpush " (reg->string r) "\n")]
37+
[l (string-append (label->string l) ":\n")]))
38+
39+
(define (opcode2? x)
40+
(memq x '(mov add sub cmp and cmovl xor or sal sar lea)))
41+
42+
;; Arg -> String
43+
(define (arg->string a)
44+
(match a
45+
[(? reg?) (reg->string a)]
46+
[`(offset ,r)
47+
(string-append "[" (arg->string r) "]")]
48+
[`(offset ,r ,i)
49+
(string-append "[" (arg->string r) " + " (number->string (* i 8)) "]")]
50+
[(? integer?) (number->string a)]
51+
[(? symbol?) (label->string a)]))
52+
53+
;; Any -> Boolean
54+
(define (reg? x)
55+
(and (symbol? x)
56+
(memq x '(rax rbx rcx rsp rdi rip))))
57+
58+
;; Reg -> String
59+
(define (reg->string r)
60+
(symbol->string r))
61+
62+
;; Label -> String
63+
;; prefix with _ for Mac
64+
(define label->string
65+
(match (system-type 'os)
66+
['macosx
67+
(λ (s) (string-append "_" (symbol->string s)))]
68+
[_ symbol->string]))
69+
70+
;; Asm -> Void
71+
(define (asm-display a)
72+
;; entry point will be first label
73+
(let ((g (findf symbol? a)))
74+
(display
75+
(string-append "\tglobal " (label->string g) "\n"
76+
"\tdefault rel\n"
77+
"\textern " (label->string 'error) "\n"
78+
"\tsection .text\n"
79+
(asm->string a)))))

0 commit comments

Comments
 (0)