diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/gscc | 39 | ||||
-rw-r--r-- | src/modules/ast/assembly-tree.scm | 29 | ||||
-rw-r--r-- | src/modules/ast/syntax-tree.scm | 47 | ||||
-rw-r--r-- | src/modules/generator/generator.scm | 24 | ||||
-rw-r--r-- | src/modules/parser/parser.scm | 17 | ||||
-rw-r--r-- | src/modules/tuple-generator/tuple-generator.scm | 36 | ||||
-rw-r--r-- | src/modules/utils/t-factory.scm | 24 | ||||
-rw-r--r-- | src/unit-tests/lexer/lexer.test.scm | 89 | ||||
-rw-r--r-- | src/unit-tests/parser/parser.test.scm | 30 | ||||
-rw-r--r-- | src/unit-tests/utils/t-factory.test.scm | 19 |
10 files changed, 281 insertions, 73 deletions
@@ -5,9 +5,11 @@ (use-modules (ice-9 getopt-long) (ice-9 popen) + (ice-9 pretty-print) (modules lexer lexer) (modules parser parser) (modules generator generator) + (modules tuple-generator tuple-generator) (modules emitter emitter)) @@ -23,14 +25,15 @@ Options: --debug, -d: turn on verbose output --lex, -l: run the lexer, but stop before assembly generation --parse, -p: run the lexer and parser, but stop before assembly generation - --codegen, -c: perform lexing, parsing, and assembly generation, but stop before code emission\n"))) + --tacky, -t: run the tacky generation stage, but stop before assembly generation + --codegen, -c: perform lexing, parsing, tacky, and assembly generation, but stop before code emission\n"))) (exit #f)) (define (c-extension? file) (let ((extension (string-drop file (- (string-length file) 2)))) (string=? extension ".c"))) -(define (process file parse? generate? write? dest) +(define (process file parse? tack? generate? write? dest) "Driver for lexing, parsing, and assembly generation." (let* ((port (preprocess file)) (tokens (begin (set-current-input-port port) @@ -38,18 +41,21 @@ Options: (close-input-port port) (when parse? (let ((c-ast (p-program tokens))) - (when generate? - (let ((assembly-ast (g-program c-ast))) - (when write? - (let ((program (e-program assembly-ast)) - (a-file (string-append dest ".s"))) - (when (file-exists? a-file) - (delete-file a-file)) - (let ((port (open-output-file a-file))) - (display program port) - (close-port port)) - (when (postprocess a-file dest) - (display (string-concatenate `("Postprocess reported success (wrote " ,dest ").\n")))))))))))) + (when tack? + (let ((tacky-ast (t-program c-ast))) + (when generate? + (let ((assembly-ast (g-program tacky-ast))) + (display tacky-ast) + (when write? + (let ((program (e-program assembly-ast)) + (a-file (string-append dest ".s"))) + (when (file-exists? a-file) + (delete-file a-file)) + (let ((port (open-output-file a-file))) + (display program port) + (close-port port)) + (when (postprocess a-file dest) + (display (string-concatenate `("Postprocess reported success (wrote " ,dest ").\n")))))))))))))) (define (preprocess file) "Returns an input port containing FILE processed with gcc." @@ -67,6 +73,7 @@ Returns #f on a failure, #t on a success." (debug (single-char #\d) (value #f)) (lex (single-char #\l) (value #f)) (parse (single-char #\p) (value #f)) + (tacky (single-char #\t) (value #f)) (codegen (single-char #\c) (value #f)))) (options (getopt-long args option-spec)) (rest (option-ref options '() #f)) @@ -81,10 +88,12 @@ Returns #f on a failure, #t on a success." (not (c-extension? file))) (error "The file could not be read, or it is not a C source code file.")) (#t (let ((parse? (not (option-ref options 'lex #f))) - (generate? (not (option-ref options 'parse #f))) + (tack? (not (option-ref options 'parse #f))) + (generate? (not (option-ref options 'tacky #f))) (write? (not (option-ref options 'codegen #f)))) (process file parse? + tack? generate? write? (string-drop-right file 2))))))) diff --git a/src/modules/ast/assembly-tree.scm b/src/modules/ast/assembly-tree.scm index ee3e116..3f0f1b1 100644 --- a/src/modules/ast/assembly-tree.scm +++ b/src/modules/ast/assembly-tree.scm @@ -4,22 +4,37 @@ subroutine? subroutine-label subroutine-instructions + subroutine-frame-size make-instruction instruction? + instruction-destination + set-instruction-destination instruction-operator - instruction-operand-1 - instruction-operand-2)) + instruction-src-1 + instruction-src-2 + + make-register + register? + register-name + )) (define-record-type <subroutine> - (make-subroutine label instrs) + (make-subroutine label instrs f-size) subroutine? (label subroutine-label) - (instrs subroutine-instructions)) + (instrs subroutine-instructions) + (f-size subroutine-frame-size)) (define-record-type <instruction> - (make-instruction op oper1 oper2) + (make-instruction dest op src1 src2) instruction? + (dest instruction-destination set-instruction-destination) (op instruction-operator) - (oper1 instruction-operand-1) - (oper2 instruction-operand-2)) + (src1 instruction-src-1) + (src2 instruction-src-2)) + +(define-record-type <register> + (make-register name) + register? + (name register-name)) diff --git a/src/modules/ast/syntax-tree.scm b/src/modules/ast/syntax-tree.scm index b7db8dd..e2ca8da 100644 --- a/src/modules/ast/syntax-tree.scm +++ b/src/modules/ast/syntax-tree.scm @@ -1,34 +1,30 @@ (define-module (modules ast syntax-tree) #:use-module (srfi srfi-9) #:export (make-program - program? - program-function + program? + program-function - make-function - function? - function-id - function-stmt + make-function + function? + function-id + function-stmt - make-stmt - stmt? - stmt-expr + make-stmt + stmt? + stmt-expr - make-expr - expr? - expr-type + make-unary + unary? + unary-operator + unary-expr - make-unary - unary? - unary-operator - unary-expr + make-const + const? + const-int - make-const - const? - const-int - - make-id - id? - id-symbol)) + make-id + id? + id-symbol)) (define-record-type <program> (make-program func) @@ -46,11 +42,6 @@ stmt? (expr stmt-expr)) -(define-record-type <expr> - (make-expr type) - expr? - (type expr-type)) - (define-record-type <unary> (make-unary op expr) unary? diff --git a/src/modules/generator/generator.scm b/src/modules/generator/generator.scm index 4a36b92..ed00de5 100644 --- a/src/modules/generator/generator.scm +++ b/src/modules/generator/generator.scm @@ -1,23 +1,19 @@ (define-module (modules generator generator) + #:use-module (srfi srfi-9 gnu) #:use-module (modules ast syntax-tree) #:use-module (modules ast assembly-tree) #:export (g-program)) (define (g-program p) - (make-program (g-function (program-function p)))) + (g-subroutine (program-function p))) -(define (g-function f) - (make-subroutine (g-id (function-id f)) - (g-stmt (function-stmt f)))) +(define (g-subroutine s) + (g-instructions (subroutine-instructions s))) -(define (g-stmt s) - (g-expr (stmt-expr s))) - -(define (g-expr e) - ;; for now, we assume only 'return'! - (list (make-instruction "movl" (string-append/shared "$" (number->string (const-int (expr-type e)))) "%eax") - (make-instruction "ret" #f #f))) - -(define (g-id i) - (id-symbol i)) +(define (g-instructions lst) + (define (g-instruction i) + (set-instruction-destination i "foo")) + (unless (null? lst) + (begin (g-instruction (car lst)) + (g-instructions (cdr lst))))) diff --git a/src/modules/parser/parser.scm b/src/modules/parser/parser.scm index fa9202d..cab690c 100644 --- a/src/modules/parser/parser.scm +++ b/src/modules/parser/parser.scm @@ -26,12 +26,11 @@ (_ (die)))) (define (p-expr tokens) - (make-expr - (match tokens - (((? integer? int)) - (make-const int)) - (((or 'sub 'complement) expr ...) - (make-unary (car tokens) (p-expr expr))) - (('left-paren expr ... 'right-paren) - (p-expr expr)) - (_ (die))))) + (match tokens + (((? integer? int)) + (make-const int)) + (((or 'sub 'complement) expr ...) + (make-unary (car tokens) (p-expr expr))) + (('left-paren expr ... 'right-paren) + (p-expr expr)) + (_ (die)))) diff --git a/src/modules/tuple-generator/tuple-generator.scm b/src/modules/tuple-generator/tuple-generator.scm new file mode 100644 index 0000000..a2dde2d --- /dev/null +++ b/src/modules/tuple-generator/tuple-generator.scm @@ -0,0 +1,36 @@ +(define-module (modules tuple-generator tuple-generator) + #:use-module (ice-9 receive) + #:use-module (modules utils t-factory) + #:use-module (modules ast syntax-tree) + #:use-module (modules ast assembly-tree) + #:export (t-program)) + + +(define (t-program p) + (make-program (t-function (program-function p)))) + +(define (t-function f) + (make-subroutine (t-id (function-id f)) + (t-stmt (function-stmt f)) + #f)) + +(define (t-stmt s) + (receive (src instrs) (t-expr (stmt-expr s)) + (append instrs + (list (make-instruction (make-register 'eax) 'mov src #f) + (make-instruction #f 'ret #f #f))))) + +(define (t-expr e) + (cond + ((unary? e) + (receive (src instrs) (t-expr (unary-expr e)) + (let ((dest (make-temporary))) + (values dest + (append instrs + (list (make-instruction dest 'mov src #f) + (make-instruction dest (unary-operator e) #f #f))))))) + (#t (values e '())))) + + +(define (t-id i) + (id-symbol i)) diff --git a/src/modules/utils/t-factory.scm b/src/modules/utils/t-factory.scm new file mode 100644 index 0000000..cad7c24 --- /dev/null +++ b/src/modules/utils/t-factory.scm @@ -0,0 +1,24 @@ +(define-module (modules utils t-factory) + #:use-module (srfi srfi-9) + #:export (temporary? + temporary-name + temporary-register + set-temporary-register! + make-temporary + )) + + +(define-record-type <temporary> + (make--temporary name register) + temporary? + (name temporary-name) + (register temporary-register set-temporary-register!)) + +(define make-temporary) +(let ((count 100)) + (set! make-temporary + (lambda () + (set! count (1+ count)) + (make--temporary (string->symbol + (format #f "t.~a" count)) + #f)))) diff --git a/src/unit-tests/lexer/lexer.test.scm b/src/unit-tests/lexer/lexer.test.scm new file mode 100644 index 0000000..807dbec --- /dev/null +++ b/src/unit-tests/lexer/lexer.test.scm @@ -0,0 +1,89 @@ +;; -*- compile-command: "guile -L ./src ./src/unit-tests/lexer/lexer.test.scm"; -*- +(use-modules (srfi srfi-64) + (modules lexer lexer)) + +(define (read-this str) + (set-current-input-port + (open-input-string str)) + str) + + +(test-begin "lexer-harness") + + +(test-equal (read-this "") + '() + (read-tokens)) + +(test-equal (read-this "(") + '(left-paren) + (read-tokens)) + +(test-equal (read-this "((") + '(left-paren left-paren) + (read-tokens)) + +(test-equal (read-this "( )") + '(left-paren right-paren) + (read-tokens)) + +(test-equal (read-this "( {;} {((};})") + '(left-paren open-brace semi-colon close-brace open-brace left-paren left-paren close-brace semi-colon close-brace right-paren) + (read-tokens)) + +(test-equal (read-this "1") + '(1) + (read-tokens)) + +(test-equal (read-this "~+-") + '(complement add sub) + (read-tokens)) + +(test-equal (read-this "---") + '(decrement sub) + (read-tokens)) + +(test-equal (read-this "+--") + '(add decrement) + (read-tokens)) + +(test-equal (read-this "0") + '(0) + (read-tokens)) + +(test-equal (read-this "0011001") + '(11001) + (read-tokens)) + +(test-equal (read-this "12 {34") + '(12 open-brace 34) + (read-tokens)) + +(test-equal (read-this "34;") + '(34 semi-colon) + (read-tokens)) + +(test-error (read-this "3.4") + (read-tokens)) + +(test-equal (read-this "a") + '("a") + (read-tokens)) + +(test-equal (read-this "a_2") + '("a_2") + (read-tokens)) + +(test-error (read-this "1foo") + (read-tokens)) + +(test-equal (read-this "void") + '(void) + (read-tokens)) + +(test-equal (read-this "int main(void) {return 2;}") + '(int "main" left-paren void right-paren open-brace return 2 semi-colon close-brace) + (read-tokens)) + + +(test-end "lexer-harness") diff --git a/src/unit-tests/parser/parser.test.scm b/src/unit-tests/parser/parser.test.scm new file mode 100644 index 0000000..b3573d0 --- /dev/null +++ b/src/unit-tests/parser/parser.test.scm @@ -0,0 +1,30 @@ +;; -*- compile-command: "guile -L ./src ./src/unit-tests/parser/parser.test.scm"; -*- +(use-modules (srfi srfi-64) + (modules parser parser)) + + +(test-begin "parser-harness") + + +(test-equal "trivial function main 2" + '(program (function (identifier "main") (return (constant 2)))) + (p-program '(int "main" left-paren void right-paren open-brace return 2 semi-colon close-brace))) + +(test-equal "trivial function foo 4" + '(program (function (identifier "foo") (return (constant 4)))) + (p-program '(int "foo" left-paren void right-paren open-brace return 4 semi-colon close-brace))) + +(test-error "trivial function bad double return" + (p-program '(int "foo" left-paren void right-paren open-brace return return 4 semi-colon close-brace))) + +(test-error "trivial function bad parens" + (p-program '(int "foo" right-paren void left-paren open-brace return 4 semi-colon close-brace))) + +(test-error "trivial function bad int parameter" + (p-program '(int "foo" left-paren int right-paren open-brace return 4 semi-colon close-brace))) + +(test-error "trivial function incomplete function" + (p-program '(int "foo" left-paren void right-paren open-brace return))) + + +(test-end "parser-harness") diff --git a/src/unit-tests/utils/t-factory.test.scm b/src/unit-tests/utils/t-factory.test.scm new file mode 100644 index 0000000..eda983b --- /dev/null +++ b/src/unit-tests/utils/t-factory.test.scm @@ -0,0 +1,19 @@ +;; -*- compile-command: "guile -L ./src ./src/unit-tests/utils/t-factory.test.scm"; -*- +(use-modules (srfi srfi-64) + (modules ast assembly-tree) + (modules utils t-factory)) + + +(test-begin "t-factory-harness") + + +(test-equal "make first temporary" + 't.101 + (temporary-name (make-t))) + +(test-equal "make second temporary" + 't.102 + (temporary-name (make-t))) + + +(test-end "t-factory-harness") |