# -*-scheme-*-
GODIR=${GODIR-@GODIR@}
GUILEDIR=${GUILEDIR-@GUILEDIR@}
-[ "$GODIR" = @"GODIR"@ ] && GODIR=guile
-[ "$GUILEDIR" = @"GUILEDIR"@ ] && GUILEDIR=guile
+[ "$GODIR" = @"GODIR"@ ] && GODIR=$(dirname $0)
+[ "$GUILEDIR" = @"GUILEDIR"@ ] && GUILEDIR=$(dirname $0)
export GUILE_AUTO_COMPILE=${GUILE_AUTO_COMPILE-0}
exec ${GUILE-guile} -L $GUILEDIR -C $GODIR -e '(mescc)' -s "$0" "$@"
!#
(define-module (mescc)
#:use-module (language c99 compiler)
- #:use-module (ice-9 rdelim)
- #:use-module (ice-9 pretty-print)
+ #:use-module (ice-9 getopt-long)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
#:export (main))
(define %prefix (if (string-prefix? "@PREFIX" "@PREFIX@") "" "@PREFIX@"))
(module-define! (resolve-module '(language c99 compiler)) '%prefix %prefix)
(module-define! (resolve-module '(language c99 compiler)) '%version %version)
-(define (main arguments)
- (let* ((files (cdr arguments))
- (file (if (null? files) (string-append %docdir "examples/main.c")
- (car files))))
- (cond ((equal? file "--help")
- (format (current-error-port) "Usage: mescc.scm [--help|--version|FILE] > a.out\n")
- (exit 0))
- ((equal? file "--version")
- (format (current-error-port) "mescc.scm (mes) ~a\n" %version)
- (exit 0)))
- (format (current-error-port) "input: ~a\n" file)
+(define (parse-opts args)
+ (let* ((option-spec
+ '((c (single-char #\c))
+ (D (single-char #\D) (value #t))
+ (help (single-char #\h))
+ (I (single-char #\I) (value #t))
+ (o (single-char #\o) (value #t))
+ (version (single-char #\V) (value #t))))
+ (options (getopt-long args option-spec))
+ (help? (option-ref options 'help #f))
+ (files (option-ref options '() '()))
+ (usage? (and (not help?) (null? files)))
+ (version? (option-ref options 'version #f)))
+ (or
+ (and version?
+ (format (current-output-port) "mescc.scm (mes) ~a\n" %version))
+ (and (or help? usage?)
+ (format (or (and usage? (current-error-port)) (current-output-port)) "\
+Usage: mescc [OPTION]... FILE...
+ -c compile and assemble, but do not link
+ -D DEFINE define DEFINE
+ -h, --help display this help and exit
+ -I DIR append DIR to include path
+ -o FILE write output to FILE
+ -v, --version display version and exit
+")
+ (exit (or (and usage? 2) 0)))
+ options)))
+
+(define (object->info file)
+ (let* ((string (with-input-from-file file read-string))
+ (module (resolve-module '(language c99 compiler))))
+ (eval-string string module)))
+
+(define (object->info file)
+ (let* ((lst (with-input-from-file file read))
+ (module (resolve-module '(language c99 compiler))))
+ (eval lst module)))
+
+(define (source->info defines includes)
+ (lambda (file)
(with-input-from-file file
- c99-input->elf)))
+ (lambda ()
+ ((c99-input->info #:defines defines #:includes includes))))))
-(format (current-error-port) "compiler loaded\n")
-(format (current-error-port) "calling ~s\n" (cons 'main (command-line)))
+(define (main args)
+ (let* ((options (parse-opts args))
+ (files (option-ref options '() '()))
+ (file (if (null? files) (string-append %docdir "examples/main.c")
+ (car files)))
+ (compile? (option-ref options 'c #f))
+ (sources (filter (cut string-suffix? ".c" <>) files))
+ (objects (filter (negate (cut string-suffix? ".c" <>)) files))
+ (base (substring file (1+ (or (string-rindex file #\/) -1)) (- (string-length file) 2)))
+ (out (option-ref options 'o (if compile? (string-append base ".o") "a.out")))
+ (multi-opt (lambda (option) (lambda (o) (and (eq? (car o) option) (cdr o)))))
+ (defines (reverse (filter-map (multi-opt 'D) options)))
+ (includes (reverse (filter-map (multi-opt 'I) options))))
+ (when (getenv "MES_DEBUG") (format (current-error-port) "options=~s\n" options)
+ (format (current-error-port) "output: ~a\n" out))
+ (if (and (pair? sources) (pair? objects)) (error "cannot mix source and object files:" files))
+ (format (current-error-port) "inputs: ~a\n" files)
+ (with-output-to-file out
+ (lambda ()
+ (set-port-encoding! (current-output-port) "ISO-8859-1")
+ (if (pair? objects) (let ((infos (map object->info objects)))
+ (if compile? (infos->object infos)
+ (infos->elf infos)))
+ (let ((infos (map (source->info defines includes) sources)))
+ (if compile? (infos->object infos)
+ (infos->elf infos))))))
+ (if (not compile?)
+ (chmod out #o755))))