diff --git a/Makefile b/Makefile index aa59c4f4..a95fe6d7 100644 --- a/Makefile +++ b/Makefile @@ -4,53 +4,36 @@ include Makefile.config +CYCLONE = cyclone TESTSCM = unit-tests TESTFILES = $(addprefix tests/, $(addsuffix .scm, $(TESTSCM))) BOOTSTRAP_DIR = ../cyclone-bootstrap +SMODULES = \ + scheme/base \ + scheme/char \ + scheme/eval \ + scheme/file \ + scheme/read \ + scheme/write \ + scheme/cyclone/cgen \ + scheme/cyclone/common \ + scheme/cyclone/libraries \ + scheme/cyclone/transforms \ + scheme/cyclone/util +SLDFILES = $(addsuffix .sld, $(SMODULES)) +COBJECTS=$(SLDFILES:.sld=.o) + all: cyclone icyc -scheme/base.o: cyclone scheme/base.sld - ./cyclone scheme/base.sld +%.o: %.sld + $(CYCLONE) $< -scheme/char.o: cyclone scheme/char.sld - ./cyclone scheme/char.sld +cyclone: $(COBJECTS) libcyclone.a cyclone-self.scm + $(CYCLONE) cyclone-self.scm -scheme/eval.o: cyclone scheme/eval.sld scheme/eval.scm - ./cyclone scheme/eval.sld - -scheme/file.o: cyclone scheme/file.sld - ./cyclone scheme/file.sld - -scheme/read.o: cyclone scheme/read.sld scheme/parser.scm - ./cyclone scheme/read.sld - -scheme/write.o: cyclone scheme/write.sld - ./cyclone scheme/write.sld - -scheme/cyclone/common.o: scheme/cyclone/common.sld - ./cyclone scheme/cyclone/common.sld - -scheme/cyclone/util.o: scheme/cyclone/util.sld - ./cyclone scheme/cyclone/util.sld - -scheme/cyclone/common.so: scheme/cyclone/common.scm - csc -s scheme/cyclone/common.scm - -scheme/cyclone/util.so: scheme/cyclone/util.scm - csc -s scheme/cyclone/util.scm - -scheme/cyclone/transforms.so: scheme/cyclone/transforms.scm - csc -s scheme/cyclone/transforms.scm - -scheme/cyclone/cgen.so: scheme/cyclone/cgen.scm - csc -s scheme/cyclone/cgen.scm - -scheme/cyclone/libraries.so: scheme/cyclone/libraries.scm - csc -s scheme/cyclone/libraries.scm - -scheme/cyclone/parser.so: scheme/parser.scm - csc -s scheme/parser.scm +icyc: $(COBJECTS) libcyclone.a icyc.scm + $(CYCLONE) icyc.scm libcyclone.so.1: runtime.c include/cyclone/runtime.h gcc -g -c -fPIC runtime.c -o runtime.o @@ -65,52 +48,8 @@ libcyclone.a: runtime.c include/cyclone/runtime.h dispatch.c #gcc -static main.c -L. -lmean -o statically_linked #Note: the first three letters (the lib) must not be specified, as well as the suffix (.a) -# debug compilation using static lib -.PHONY: debug -debug: - gcc test.c -L. -lcyclone -I. -g -o test -.PHONY: debug2 -debug2: libcyclone.so.1 - gcc test.c -L. -lcyclone -I. -g -o test - -cyclone: cyclone.scm scheme/cyclone/transforms.so scheme/cyclone/util.so scheme/cyclone/cgen.so scheme/cyclone/libraries.so scheme/cyclone/parser.so scheme/cyclone/common.so libcyclone.a - csc cyclone.scm - -#scheme/cyclone/util.o: cyclone scheme/cyclone/util.sld -.PHONY: self -self: - ./cyclone scheme/cyclone/common.sld - ./cyclone scheme/cyclone/libraries.sld - ./cyclone scheme/cyclone/transforms.sld - ./cyclone scheme/cyclone/cgen.sld - ./cyclone scheme/cyclone/util.sld - ./cyclone cyclone-self.scm - -.PHONY: self2 -self2: - ./cyclone-self scheme/base.sld - ./cyclone-self scheme/read.sld - ./cyclone-self scheme/write.sld - ./cyclone-self scheme/char.sld - ./cyclone-self scheme/eval.sld - ./cyclone-self scheme/file.sld - ./cyclone-self scheme/cyclone/common.sld - ./cyclone-self icyc.scm - ./cyclone-self scheme/cyclone/libraries.sld - ./cyclone-self scheme/cyclone/transforms.sld - ./cyclone-self scheme/cyclone/cgen.sld - ./cyclone-self scheme/cyclone/util.sld - ./cyclone-self cyclone-self.scm - -# TODO: this is ugly and needs lots of work yet... -# would also need to call this after self2 -# TODO: also need to take all the .sld files (??), and will need to configure. -# or not, is it OK to assume bootstrap will only generate cyclone and (maybe) icyc?? -# install location (although maybe that is a 'make install' issue rather than bootstrap, -# which can be done from a fixed location) .PHONY: bootstrap bootstrap: -# $(MAKE) self2 # rm -rf $(BOOTSTRAP_DIR) mkdir -p $(BOOTSTRAP_DIR)/scheme/cyclone mkdir -p $(BOOTSTRAP_DIR)/include/cyclone @@ -142,34 +81,9 @@ bootstrap: .PHONY: test -test: $(TESTFILES) cyclone +test: $(TESTFILES) $(CYCLONE) $(foreach f,$(TESTSCM), echo tests/$(f) ; ./cyclone tests/$(f).scm && tests/$(f) && rm -rf tests/$(f);) -############################### -## Temporary testing directives -.PHONY: test2 -test2: examples/hello-library/int-test/hello.c libcyclone.a - cd examples/hello-library ; ../../cyclone libs/lib1.sld - cd examples/hello-library ; ../../cyclone libs/lib2.sld - cd examples/hello-library ; ../../cyclone hello.scm -## gcc examples/hello-library/int-test/lib2.c -I. -g -c -o lib2.o -## gcc examples/hello-library/int-test/hello.c -I. -g -c -o hello.o -## gcc hello.o lib2.o -L. -lcyclone -lm -o hello -## gcc examples/hello-library/hello.c -L. -lcyclone -lm -I. -g -o hello -## TODO: will need to manually compile hello example. need to manually add the entry points to hello, and there is an issue in the libs with Cyc_global_vars not being assigned. but this still leads to a tag error so there must be other issues... -#.PHONY: test3 -#test3: -# gcc examples/hello-library/int-test/scheme/base.c -I/home/justin/Documents/cyclone/ -g -c -o scheme/base.o -# cd examples/hello-library ; gcc int-test/libs/lib1.c -I/home/justin/Documents/cyclone/ -g -c -o libs/lib1.o -# cd examples/hello-library ; gcc int-test/libs/lib2.c -I/home/justin/Documents/cyclone/ -g -c -o libs/lib2.o -# cd examples/hello-library ; gcc int-test/hello.c -I/home/justin/Documents/cyclone/ -g -c -o hello.o -# cd examples/hello-library ; gcc hello.o libs/lib1.o /home/justin/Documents/cyclone/scheme/base.o libs/lib2.o -L/home/justin/Documents/cyclone/ -lcyclone -lm -I/home/justin/Documents/cyclone/ -g -o hello -## END temporary directives -########################### - -icyc: cyclone icyc.scm scheme/eval.scm scheme/cyclone/libraries.scm scheme/parser.scm include/cyclone/runtime.h scheme/base.o scheme/read.o scheme/write.o scheme/char.o scheme/eval.o scheme/file.o scheme/cyclone/util.o scheme/cyclone/common.o scheme/cyclone/util.o - ./cyclone icyc.scm - .PHONY: tags tags: ctags -R * @@ -208,6 +122,3 @@ uninstall: $(RMDIR) $(DESTDIR)$(DATADIR)/scheme $(RMDIR) $(DESTDIR)$(DATADIR) -testing: - make PREFIX="." libcyclone.a && make && make test && make self && make self2 && make bootstrap - diff --git a/cyclone-self.scm b/cyclone-self.scm deleted file mode 100644 index 85b033d3..00000000 --- a/cyclone-self.scm +++ /dev/null @@ -1,329 +0,0 @@ -;; Cyclone Scheme -;; Copyright (c) 2014, Justin Ethier -;; All rights reserved. -;; -;; This module contains a front-end for the compiler itself. -;; - -; TODO: -(import (scheme base) - (scheme file) - (scheme read) - (scheme write) - (scheme cyclone common) - (scheme cyclone util) - (scheme cyclone cgen) - (scheme cyclone transforms) - (scheme cyclone libraries)) - -(cond-expand - (chicken - (define (Cyc-installation-dir . opt) - (if (equal? '(inc) opt) - "/home/justin/Documents/cyclone/include" - ;; Ignore opt and always assume current dir for chicken, since it is just dev - "/home/justin/Documents/cyclone")) - (require-extension extras) ;; pretty-print - (require-extension chicken-syntax) ;; when - (require-extension srfi-1) ;; every - (load (string-append (Cyc-installation-dir) "/scheme/cyclone/common.so")) - (load (string-append (Cyc-installation-dir) "/scheme/parser.so")) - (load (string-append (Cyc-installation-dir) "/scheme/cyclone/util.so")) - (load (string-append (Cyc-installation-dir) "/scheme/cyclone/libraries.so")) - (load (string-append (Cyc-installation-dir) "/scheme/cyclone/transforms.so")) - (load (string-append (Cyc-installation-dir) "/scheme/cyclone/cgen.so"))) - (else #f)) - -;; Code emission. - -; c-compile-and-emit : (string -> A) exp -> void -(define (c-compile-and-emit input-program lib-deps src-file) - (call/cc - (lambda (return) - (define globals '()) - (define module-globals '()) ;; Globals defined by this module - (define program? #t) ;; Are we building a program or a library? - (define imports '()) - (define imported-vars '()) - (define lib-name '()) - (define lib-exports '()) - - (emit *c-file-header-comment*) ; Guarantee placement at top of C file - - (trace:info "---------------- input program:") - (trace:info input-program) ;pretty-print - - (cond - ((library? (car input-program)) - (let ((includes (lib:includes (car input-program)))) - (set! program? #f) - (set! lib-name (lib:name (car input-program))) - (set! lib-exports - (cons - (lib:name->symbol lib-name) - (lib:exports (car input-program)))) - (set! imports (lib:imports (car input-program))) - (set! input-program (lib:body (car input-program))) - ;; Prepend any included files into the begin section - (if (not (null? includes)) - (for-each - (lambda (include) - (set! input-program - (append (read-file (string-append - (lib:import->path lib-name) - include)) - input-program))) - includes)))) - ((tagged-list? 'import (car input-program)) - (set! imports (cdar input-program)) - (set! input-program (cdr input-program)) - ;(error (list 'imports (cdar input-program))) - )) - - ;; Process library imports - ;; TODO: this may not be good enough, may need to tag library - ;; imports uniquely to reduce issues when the same variable - ;; is used by multiple libraries, and to allow renaming of imports. - ;; As of now, that will have to be dealt with later. - (trace:info "imports:") - (trace:info imports) - (set! imported-vars (lib:resolve-imports imports)) - (trace:info "resolved imports:") - (trace:info imported-vars) - - ;; TODO: how to handle stdlib when compiling a library?? - ;; either need to keep track of what was actually used, - ;; or just assume all imports were used and include them - ;; in final compiled program - ;(set! input-program (add-libs input-program)) - - (set! input-program (expand input-program)) - (trace:info "---------------- after macro expansion:") - (trace:info input-program) ;pretty-print - - ;; Separate global definitions from the rest of the top-level code - (set! input-program - (isolate-globals input-program program? lib-name)) - - ;; Optimize-out unused global variables - ;; For now, do not do this if eval is used. - ;; TODO: do not have to be so aggressive, unless (eval (read)) or such - (if (not (has-global? input-program 'eval)) - (set! input-program - (filter-unused-variables input-program lib-exports))) - - (trace:info "---------------- after processing globals") - (trace:info input-program) ;pretty-print - - ; Note alpha-conversion is overloaded to convert internal defines to - ; set!'s below, since all remaining phases operate on set!, not define. - ; - ; TODO: consider moving some of this alpha-conv logic below back into trans? - (set! module-globals (global-vars input-program)) - (set! globals (append imported-vars module-globals)) - (set! input-program - (map - (lambda (expr) - (alpha-convert expr globals return)) - input-program)) - (trace:info "---------------- after alpha conversion:") - (trace:info input-program) ;pretty-print - - (let ((cps (map - (lambda (expr) - (cps-convert expr)) - input-program))) - (cond - ((and library? (equal? lib-name '(scheme base))) - (set! globals (append '(call-with-values call/cc) globals)) - (set! module-globals (append '(call-with-values call/cc) module-globals)) - (set! input-program - (cons - ;; Experimental version of call-with-values, - ;; seems OK in compiler but not in eval. - '(define call-with-values - (lambda (k producer consumer) - (producer - (lambda (result) - (consumer k result))))) - ;; multiple args requires more than just this. - ;; may want to look at: - ;; http://stackoverflow.com/questions/16674214/how-to-implement-call-with-values-to-match-the-values-example-in-r5rs - ;; (lambda vals - ;; (apply k consumer vals))))) - (cons - ;; call/cc must be written in CPS form, so it is added here - ;; TODO: prevents this from being optimized-out - ;; TODO: will this cause issues if another var is assigned to call/cc? - '(define call/cc - (lambda (k f) (f k (lambda (_ result) (k result))))) - cps)))) - (else - ;; No need for call/cc yet - (set! input-program cps)))) - (trace:info "---------------- after CPS:") - (trace:info input-program) ;pretty-print - - - ;; TODO: do not run this if eval is in play, or (better) only do opts that are safe in that case (will be much more limited) - ;; because of this, programs such as icyc can only be so optimized. it would be much more beneficial if modules like - ;; eval.scm could be compiled separately and then linked to by a program such as icyc.scm. that would save a *lot* of compile - ;; time. in fact, it might be more beneficial than adding these optimizations. - ;; - ;; TODO: run CPS optimization (not all of these phases may apply) - ;; phase 1 - constant folding, function-argument expansion, beta-contraction of functions called once, - ;; and other "contractions". some of this is already done in previous phases. we will leave - ;; that alone for now -; (set! input-program (cps-opt:contractions input-program)) - ;; phase 2 - beta expansion - ;; phase 3 - eta reduction - ;; phase 4 - hoisting - ;; phase 5 - common subexpression elimination - ;; TODO: re-run phases again until program is stable (less than n opts made, more than r rounds performed, etc) - ;; END CPS optimization - - - (set! input-program - (map - (lambda (expr) - (clear-mutables) - (analyze-mutable-variables expr) - (wrap-mutables expr globals)) - input-program)) - (trace:info "---------------- after wrap-mutables:") - (trace:info input-program) ;pretty-print - - (set! input-program - (map - (lambda (expr) - (if (define? expr) - ;; Global - `(define ,(define->var expr) - ,@(caddr (closure-convert (define->exp expr) globals))) - (caddr ;; Strip off superfluous lambda - (closure-convert expr globals)))) - input-program)) - ; (caddr ;; Strip off superfluous lambda - ; (closure-convert input-program))) - (trace:info "---------------- after closure-convert:") - (trace:info input-program) ;pretty-print - - (if (not *do-code-gen*) - (begin - (trace:error "DEBUG, existing program") - (exit 0))) - - (trace:info "---------------- C code:") - (mta:code-gen input-program - program? - lib-name - lib-exports - imported-vars - module-globals - lib-deps - src-file) - (return '())))) ;; No codes to return - -;; TODO: longer-term, will be used to find where cyclone's data is installed -(define (get-data-path) - ".") - -(define (get-lib filename) - (string-append (get-data-path) "/" filename)) - -(define (read-file filename) - (call-with-input-file filename - (lambda (port) - (read-all port)))) - -;; Compile and emit: -(define (run-compiler args cc?) - (let* ((in-file (car args)) - (in-prog (read-file in-file)) - (program? (not (library? (car in-prog)))) - (lib-deps - (if (and program? - (tagged-list? 'import (car in-prog))) - (lib:get-all-import-deps (cdar in-prog)) - '())) - (exec-file (basename in-file)) - (src-file (string-append exec-file ".c")) - (create-c-file - (lambda (program) - (with-output-to-file - src-file - (lambda () - (c-compile-and-emit program lib-deps src-file))))) - (result (create-c-file in-prog))) - - ;; Compile the generated C file - (cond - (program? - (letrec ((objs-str - (apply - string-append - (map - (lambda (i) - (string-append " " (lib:import->filename i ".o") " ")) - lib-deps))) - (comp-prog-cmd - (string-append "gcc " src-file " -g -c -o " exec-file ".o")) - (comp-objs-cmd - (string-append "gcc " exec-file ".o " objs-str " -lcyclone -lm -g -o " exec-file))) - ;(write `(DEBUG all imports ,lib-deps objs ,objs-str)) - ;(write `(DEBUG ,(lib:get-all-import-deps (cdar in-prog)))) - (cond - (cc? - (if (equal? 0 (system comp-prog-cmd)) - (system comp-objs-cmd))) - (else - (write comp-prog-cmd) - (write comp-objs-cmd))))) - (else - (let ((comp-lib-cmd - (string-append "gcc " src-file " -g -c -o " exec-file ".o"))) - (cond - (cc? - (system comp-lib-cmd)) - (else - (write comp-lib-cmd)))))))) - - -;; Handle command line arguments -(let* ((args (command-line-arguments)) ;; TODO: port (command-line-arguments) to husk?? - (non-opts (filter - (lambda (arg) - (not (and (> (string-length arg) 1) - (equal? #\- (string-ref arg 0))))) - args)) - (compile? #t)) - (if (member "-t" args) - (set! *trace-level* 4)) ;; Show all trace output - (if (member "-d" args) - (set! compile? #f)) ;; Debug, do not run GCC - (cond - ((< (length args) 1) - (display "cyclone: no input file") - (newline)) - ((or (member "-h" args) - (member "--help" args)) - (display " - -t Show intermediate trace output in generated C files - -d Only generate intermediate C files, do not compile them - -h, --help Display usage information - -v Display version information - --autogen Cyclone developer use only, create autogen.out file -") - (newline)) - ((member "-v" args) - (display *version-banner*)) - ((member "--autogen" args) - (autogen "autogen.out") - (newline)) - ((member "-v" args) - (display *version-banner*)) - ((member "--autogen" args) - (autogen "autogen.out")) - (else - (run-compiler non-opts compile?)))) - diff --git a/cyclone.scm b/cyclone.scm index 68cd6bb1..4d5d30c7 100644 --- a/cyclone.scm +++ b/cyclone.scm @@ -4,17 +4,15 @@ ;; ;; This module contains a front-end for the compiler itself. ;; - -; TODO: -;(import (scheme base) -; (scheme file) -; (scheme read) -; (scheme write) -; (scheme cyclone common) -; (scheme cyclone util) -; (scheme cyclone cgen) -; (scheme cyclone transforms) -; (scheme cyclone libraries)) +(import (scheme base) + (scheme file) + (scheme read) + (scheme write) + (scheme cyclone common) + (scheme cyclone util) + (scheme cyclone cgen) + (scheme cyclone transforms) + (scheme cyclone libraries)) (cond-expand (chicken @@ -257,10 +255,6 @@ (result (create-c-file in-prog))) ;; Compile the generated C file -;; TODO: -I is a hack, real answer is to use 'make install' to place .h file -;; TODO: real answer is to get rid of -I and -L below, and assume header and libs are -;; already installed on the system. this is OK since we are going to have a place -;; to bootstrap cyclone from, so it will always be installed. (cond (program? (letrec ((objs-str @@ -271,9 +265,9 @@ (string-append " " (lib:import->filename i ".o") " ")) lib-deps))) (comp-prog-cmd - (string-append "gcc " src-file " -I" (Cyc-installation-dir 'inc) " -g -c -o " exec-file ".o")) + (string-append "gcc " src-file " -g -c -o " exec-file ".o")) (comp-objs-cmd - (string-append "gcc " exec-file ".o " objs-str " -L" (Cyc-installation-dir 'lib) " -lcyclone -lm -I" (Cyc-installation-dir 'inc) " -g -o " exec-file))) + (string-append "gcc " exec-file ".o " objs-str " -lcyclone -lm -g -o " exec-file))) ;(write `(DEBUG all imports ,lib-deps objs ,objs-str)) ;(write `(DEBUG ,(lib:get-all-import-deps (cdar in-prog)))) (cond @@ -285,7 +279,7 @@ (write comp-objs-cmd))))) (else (let ((comp-lib-cmd - (string-append "gcc " src-file " -I" (Cyc-installation-dir 'inc) " -g -c -o " exec-file ".o"))) + (string-append "gcc " src-file " -g -c -o " exec-file ".o"))) (cond (cc? (system comp-lib-cmd))