2294 lines
99 KiB
Scheme
2294 lines
99 KiB
Scheme
;;; -*-scheme-*-
|
||
|
||
;;; Mes --- Maxwell Equations of Software
|
||
;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
|
||
;;;
|
||
;;; This file is part of Mes.
|
||
;;;
|
||
;;; Mes is free software; you can redistribute it and/or modify it
|
||
;;; under the terms of the GNU General Public License as published by
|
||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||
;;; your option) any later version.
|
||
;;;
|
||
;;; Mes is distributed in the hope that it will be useful, but
|
||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;;; GNU General Public License for more details.
|
||
;;;
|
||
;;; You should have received a copy of the GNU General Public License
|
||
;;; along with Mes. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;;; compiler.mes produces an i386 binary from the C produced by
|
||
;;; Nyacc c99.
|
||
|
||
;;; Code:
|
||
|
||
(cond-expand
|
||
(guile-2)
|
||
(guile)
|
||
(mes
|
||
(mes-use-module (srfi srfi-1))
|
||
(mes-use-module (srfi srfi-26))
|
||
(mes-use-module (mes pmatch))
|
||
(mes-use-module (nyacc lang c99 parser))
|
||
(mes-use-module (nyacc lang c99 pprint))
|
||
(mes-use-module (mes as))
|
||
(mes-use-module (mes as-i386))
|
||
(mes-use-module (mes M1))
|
||
(mes-use-module (mes optargs))
|
||
(mes-use-module (language c99 info))))
|
||
|
||
(define (logf port string . rest)
|
||
(apply format (cons* port string rest))
|
||
(force-output port)
|
||
#t)
|
||
|
||
(define (stderr string . rest)
|
||
(apply logf (cons* (current-error-port) string rest)))
|
||
|
||
(define (pke . stuff)
|
||
(newline (current-error-port))
|
||
(display ";;; " (current-error-port))
|
||
(write stuff (current-error-port))
|
||
(newline (current-error-port))
|
||
(car (last-pair stuff)))
|
||
|
||
(define %prefix (if (string-prefix? "@PREFIX" "@PREFIX@") (or (getenv "PREFIX") "") "@PREFIX@"))
|
||
|
||
(define mes? (pair? (current-module)))
|
||
|
||
(define %int-size 4)
|
||
(define %pointer-size %int-size)
|
||
|
||
(define* (c99-input->full-ast #:key (defines '()) (includes '()))
|
||
(let ((sys-include (if (equal? %prefix "") "include" (string-append %prefix "/share/include"))))
|
||
(parse-c99
|
||
#:inc-dirs (append includes (cons* sys-include "include" "lib" (or (and=> (getenv "C_INCLUDE_PATH") (cut string-split <> #\:)) '())))
|
||
#:cpp-defs `(
|
||
"NULL=0"
|
||
"__linux__=1"
|
||
"__i386__=1"
|
||
"POSIX=0"
|
||
"_POSIX_SOURCE=0"
|
||
"__MESC__=1"
|
||
,(if mes? "__MESC_MES__=1" "__MESC_MES__=0")
|
||
,@defines)
|
||
#:mode 'code)))
|
||
|
||
(define (ast-strip-comment o)
|
||
(pmatch o
|
||
((comment . ,comment) #f)
|
||
(((comment . ,comment) . ,t) (filter-map ast-strip-comment t))
|
||
(((comment . ,comment) . ,cdr) cdr)
|
||
((,car . (comment . ,comment)) car)
|
||
((,h . ,t) (if (list? o) (filter-map ast-strip-comment o)
|
||
(cons (ast-strip-comment h) (ast-strip-comment t))))
|
||
(_ o)))
|
||
|
||
(define (ast-strip-const o)
|
||
(pmatch o
|
||
((type-qual ,qual) (if (equal? qual "const") #f o))
|
||
((pointer (type-qual-list (type-qual ,qual)) . ,rest)
|
||
(if (equal? qual "const") `(pointer ,@rest) o))
|
||
((decl-spec-list (type-qual ,qual))
|
||
(if (equal? qual "const") #f
|
||
`(decl-spec-list (type-qual ,qual))))
|
||
((decl-spec-list (type-qual ,qual) . ,rest)
|
||
(if (equal? qual "const") `(decl-spec-list ,@rest)
|
||
`(decl-spec-list (type-qual ,qual) ,@(map ast-strip-const rest))))
|
||
((decl-spec-list (type-qual-list (type-qual ,qual)) . ,rest)
|
||
(if (equal? qual "const") `(decl-spec-list ,@rest)
|
||
`(decl-spec-list (type-qual-list (type-qual ,qual)) ,@(map ast-strip-const rest))))
|
||
((,h . ,t) (if (list? o) (filter-map ast-strip-const o)
|
||
(cons (ast-strip-const h) (ast-strip-const t))))
|
||
(_ o)))
|
||
|
||
(define (clone o . rest)
|
||
(cond ((info? o)
|
||
(let ((types (.types o))
|
||
(constants (.constants o))
|
||
(functions (.functions o))
|
||
(globals (.globals o))
|
||
(locals (.locals o))
|
||
(statics (.statics o))
|
||
(function (.function o))
|
||
(text (.text o))
|
||
(break (.break o))
|
||
(continue (.continue o)))
|
||
(let-keywords rest
|
||
#f
|
||
((types types)
|
||
(constants constants)
|
||
(functions functions)
|
||
(globals globals)
|
||
(locals locals)
|
||
(statics statics)
|
||
(function function)
|
||
(text text)
|
||
(break break)
|
||
(continue continue))
|
||
(make <info> #:types types #:constants constants #:functions functions #:globals globals #:locals locals #:statics statics #:function function #:text text #:break break #:continue continue))))))
|
||
|
||
(define (ident->constant name value)
|
||
(cons name value))
|
||
|
||
(define (enum->type-entry name fields)
|
||
(cons `("tag" ,name) (make-type 'enum 4 0 fields)))
|
||
|
||
(define (struct->type-entry name fields)
|
||
(cons `("tag" ,name) (make-type 'struct (apply + (map field:size fields)) 0 fields)))
|
||
|
||
(define (union->type-entry name fields)
|
||
(cons `("tag" ,name) (make-type 'union (apply + (map field:size fields)) 0 fields)))
|
||
|
||
(define i386:type-alist
|
||
`(("char" . ,(make-type 'builtin 1 0 #f))
|
||
("short" . ,(make-type 'builtin 2 0 #f))
|
||
("int" . ,(make-type 'builtin 4 0 #f))
|
||
("long" . ,(make-type 'builtin 4 0 #f))
|
||
;;("long long" . ,(make-type 'builtin 8 0 #f))
|
||
;;("long long int" . ,(make-type 'builtin 8 0 #f))
|
||
|
||
("long long" . ,(make-type 'builtin 4 0 #f)) ;; FIXME
|
||
("long long int" . ,(make-type 'builtin 4 0 #f))
|
||
|
||
("void" . ,(make-type 'builtin 1 0 #f))
|
||
;; FIXME sign
|
||
("unsigned char" . ,(make-type 'builtin 1 0 #f))
|
||
("unsigned short" . ,(make-type 'builtin 2 0 #f))
|
||
("unsigned short int" . ,(make-type 'builtin 2 0 #f))
|
||
("unsigned" . ,(make-type 'builtin 4 0 #f))
|
||
("unsigned int" . ,(make-type 'builtin 4 0 #f))
|
||
("unsigned long" . ,(make-type 'builtin 4 0 #f))
|
||
|
||
;; ("unsigned long long" . ,(make-type 'builtin 8 0 #f))
|
||
;; ("unsigned long long int" . ,(make-type 'builtin 8 0 #f))
|
||
("unsigned long long" . ,(make-type 'builtin 4 0 #f)) ;; FIXME
|
||
("unsigned long long int" . ,(make-type 'builtin 4 0 #f))
|
||
|
||
("float" . ,(make-type 'builtin 4 0 #f))
|
||
("double" . ,(make-type 'builtin 8 0 #f))
|
||
("long double" . ,(make-type 'builtin 16 0 #f))))
|
||
|
||
(define (field:name o)
|
||
(pmatch o
|
||
((struct (,name ,type ,size ,pointer) . ,rest) name)
|
||
((union (,name ,type ,size ,pointer) . ,rest) name)
|
||
((,name ,type ,size ,pointer) name)
|
||
(_ (error "field:name not supported:" o))))
|
||
|
||
(define (field:pointer o)
|
||
(pmatch o
|
||
((struct (,name ,type ,size ,pointer) . ,rest) pointer)
|
||
((union (,name ,type ,size ,pointer) . ,rest) pointer)
|
||
((,name ,type ,size ,pointer) pointer)
|
||
(_ (error "field:name not supported:" o))))
|
||
|
||
(define (field:size o)
|
||
(pmatch o
|
||
((struct . ,fields) (apply + (map field:size fields)))
|
||
((union . ,fields) (apply max (map field:size fields)))
|
||
((,name ,type ,size ,pointer) size)
|
||
(_ (error (format #f "field:size: ~s\n" o)))))
|
||
|
||
(define (struct:size o)
|
||
(field:size (cons 'struct (type:description o)))) ;;FIXME
|
||
|
||
(define (field:type o)
|
||
(pmatch o
|
||
((,name ,type ,size ,pointer) type)
|
||
(_ (error (format #f "field:type: ~s\n" o)))))
|
||
|
||
(define (ast->type info o)
|
||
(define (get-type o)
|
||
(let ((t (assoc-ref (.types info) o)))
|
||
(pmatch t
|
||
((typedef ,next) (or (get-type next) o))
|
||
(_ t))))
|
||
(pmatch o
|
||
(,t (guard (type? t)) t)
|
||
((p-expr ,expr) (ast->type info expr))
|
||
((pre-inc ,expr) (ast->type info expr))
|
||
((post-inc ,expr) (ast->type info expr))
|
||
((ident ,name) (ident->type info name))
|
||
((char ,value) (get-type "char"))
|
||
((fixed ,value) (get-type "int"))
|
||
((type-spec (typename ,type))
|
||
(ast->type info type))
|
||
((array-ref ,index ,array)
|
||
(ast->type info array))
|
||
((struct-ref (ident ,type))
|
||
(or (get-type type)
|
||
(let ((struct (if (pair? type) type `("tag" ,type))))
|
||
(ast->type info struct))))
|
||
((union-ref (ident ,type))
|
||
(or (get-type type)
|
||
(let ((struct (if (pair? type) type `("tag" ,type))))
|
||
(ast->type info struct))))
|
||
((struct-def (ident ,name) . _)
|
||
(ast->type info `("tag" ,name)))
|
||
((union-def (ident ,name) . _)
|
||
(ast->type info `("tag" ,name)))
|
||
((struct-def (field-list . ,fields))
|
||
(let ((fields (append-map (struct-field info) fields)))
|
||
(make-type 'struct (apply + (map field:size fields)) 0 fields)))
|
||
((union-def (field-list . ,fields))
|
||
(let ((fields (append-map (struct-field info) fields)))
|
||
(make-type 'union (apply + (map field:size fields)) 0 fields)))
|
||
((void) (ast->type info "void"))
|
||
((fixed-type ,type) (ast->type info type))
|
||
((float-type ,type) (ast->type info type))
|
||
((typename ,type) (ast->type info type))
|
||
((de-ref ,expr)
|
||
(ast->type info expr))
|
||
((d-sel (ident ,field) ,struct)
|
||
(let ((type0 (ast->type info struct)))
|
||
(ast->type info (field-type info type0 field))))
|
||
((i-sel (ident ,field) ,struct)
|
||
(let ((type0 (ast->type info struct)))
|
||
(ast->type info (field-type info type0 field))))
|
||
((ref-to ,expr) (ast->type info expr))
|
||
((pre-inc ,a) (ast->type info a))
|
||
((pre-dec ,a) (ast->type info a))
|
||
((post-inc ,a) (ast->type info a))
|
||
((post-dec ,a) (ast->type info a))
|
||
((add ,a ,b) (ast->type info a))
|
||
((sub ,a ,b) (ast->type info a))
|
||
((bitwise-and ,a ,b) (ast->type info a))
|
||
((bitwise-not ,a) (ast->type info a))
|
||
((bitwise-or ,a ,b) (ast->type info a))
|
||
((bitwise-xor ,a ,b) (ast->type info a))
|
||
((lshift ,a ,b) (ast->type info a))
|
||
((rshift ,a ,b) (ast->type info a))
|
||
((div ,a ,b) (ast->type info a))
|
||
((mod ,a ,b) (ast->type info a))
|
||
((mul ,a ,b) (ast->type info a))
|
||
((not ,a) (ast->type info a))
|
||
((neg ,a) (ast->type info a))
|
||
((eq ,a ,b) (ast->type info a))
|
||
((ge ,a ,b) (ast->type info a))
|
||
((gt ,a ,b) (ast->type info a))
|
||
((ne ,a ,b) (ast->type info a))
|
||
((le ,a ,b) (ast->type info a))
|
||
((lt ,a ,b) (ast->type info a))
|
||
((or ,a ,b) (ast->type info a))
|
||
((and ,a ,b) (ast->type info a))
|
||
((cast (type-name ,type) ,expr) ; FIXME: ignore expr?
|
||
(ast->type info type))
|
||
((cast (type-name ,type (abs-declr ,pointer)) ,expr) ; FIXME: ignore expr?
|
||
(ast->type info type))
|
||
((decl-spec-list (type-spec ,type))
|
||
(ast->type info type))
|
||
((assn-expr ,a ,op ,b)
|
||
(ast->type info a))
|
||
((enum-ref . _) (get-type "int"))
|
||
((sizeof-type . _) (get-type "int"))
|
||
((sizeof-expr . _) (get-type "int"))
|
||
((string _) (get-type "char"))
|
||
((fctn-call (p-expr (ident ,function)) . ,rest)
|
||
(or (and=> (assoc-ref (.functions info) function) function:type)
|
||
(begin
|
||
(stderr "ast->type: no such function: ~s\n" function)
|
||
(get-type "int"))))
|
||
(_ (let ((type (get-type o)))
|
||
(cond ((type? type) type)
|
||
((and (pair? type) (equal? (car type) "tag"))
|
||
(stderr "NO STRUCT YET:~s\n" (.types info))
|
||
type)
|
||
((and (pair? o) (equal? (car o) "tag"))
|
||
(stderr "NO STRUCT YET:~s\n" (.types info))
|
||
o)
|
||
(else
|
||
(stderr "types: ~s\n" (.types info))
|
||
(error "ast->type: not supported: " o)))))))
|
||
|
||
(define (ast-type->description info o)
|
||
((compose type:description (cut ast->type info <>) o)))
|
||
|
||
(define (ast-type->size info o)
|
||
;;((compose type:size (cut ast->type info <>)) o)
|
||
(let ((type (if (type? o) o
|
||
(ast->type info o))))
|
||
(if (not (type? type)) (error "ast-type->size: no such type:" o)
|
||
(type:size type))))
|
||
|
||
(define (field-field info struct field)
|
||
(let* ((xtype (if (type? struct) struct
|
||
(ast->type info struct)))
|
||
(fields (type:description xtype)))
|
||
(let loop ((fields fields))
|
||
(if (null? fields) (error (format #f "no such field: ~a in ~s" field struct))
|
||
(let ((f (car fields)))
|
||
(cond ((equal? (car f) field) f)
|
||
((and (memq (car f) '(struct union))
|
||
(find (lambda (x) (equal? (car x) field)) (cdr f))))
|
||
(else (loop (cdr fields)))))))))
|
||
|
||
(define (field-offset info struct field)
|
||
(let ((xtype (if (type? struct) struct
|
||
(ast->type info struct))))
|
||
(if (eq? (type:type xtype) 'union) 0
|
||
(let ((fields (type:description xtype)))
|
||
(let loop ((fields fields) (offset 0))
|
||
(if (null? fields) (error (format #f "no such field: ~a in ~s" field struct))
|
||
(let ((f (car fields)))
|
||
(cond ((equal? (car f) field) offset)
|
||
((and (eq? (car f) 'struct)
|
||
(find (lambda (x) (equal? (car x) field)) (cdr f))
|
||
(apply + (cons offset
|
||
(map field:size
|
||
(member field (reverse (cdr f))
|
||
(lambda (a b)
|
||
(equal? a (car b) field))))))))
|
||
((and (eq? (car f) 'union)
|
||
(find (lambda (x) (equal? (car x) field)) (cdr f))
|
||
offset))
|
||
(else (loop (cdr fields) (+ offset (field:size f))))))))))))
|
||
|
||
(define (field-pointer info struct field)
|
||
(let ((field (field-field info struct field)))
|
||
(field:pointer field)))
|
||
|
||
(define (field-size info struct field)
|
||
(let ((xtype (if (type? struct) struct
|
||
(ast->type info struct))))
|
||
(if (eq? (type:type xtype) 'union) 0
|
||
(let ((field (field-field info struct field)))
|
||
(field:size field)))))
|
||
|
||
(define (field-type info struct field)
|
||
(let ((field (field-field info struct field)))
|
||
(field:type field)))
|
||
|
||
(define (struct->fields o)
|
||
(pmatch o
|
||
(_ (guard (and (type? o) (eq? (type:type o) 'struct)))
|
||
(append-map struct->fields (type:description o)))
|
||
(_ (guard (and (type? o) (eq? (type:type o) 'union)))
|
||
(struct->fields (car (type:description o))))
|
||
((struct . ,fields)
|
||
(append-map struct->fields fields))
|
||
(_ (list o))))
|
||
|
||
(define (byte->hex.m1 o)
|
||
(string-drop o 2))
|
||
|
||
(define (asm->m1 o)
|
||
(let ((prefix ".byte "))
|
||
(if (not (string-prefix? prefix o)) (map (cut string-split <> #\space) (string-split o #\newline))
|
||
(let ((s (string-drop o (string-length prefix))))
|
||
(list (format #f "'~a'" (string-join (map byte->hex.m1 (cdr (string-split o #\space))) " ")))))))
|
||
|
||
(define (ident->variable info o)
|
||
(or (assoc-ref (.locals info) o)
|
||
(assoc-ref (.globals info) o)
|
||
(assoc-ref (.statics info) o)
|
||
(assoc-ref (.constants info) o)
|
||
(assoc-ref (.functions info) o)
|
||
(begin
|
||
(stderr "info=~s\n" info)
|
||
(error "ident->variable: undefined variabled:" o))))
|
||
|
||
(define (ident->type info o)
|
||
(let ((var (ident->variable info o)))
|
||
(cond ((global? var) (global:type var))
|
||
((local? var) (local:type var))
|
||
((assoc-ref (.constants info) o) (assoc-ref (.types info) "int"))
|
||
((pair? var) (car var))
|
||
(else (stderr "ident->type ~s => ~s\n" o var)
|
||
#f))))
|
||
|
||
(define (ident->pointer info o)
|
||
(let ((local (assoc-ref (.locals info) o)))
|
||
(if local (let* ((t ((compose type:pointer local:type) local))
|
||
(v (local:pointer local))
|
||
(p (+ (abs t) (abs v))))
|
||
(if (or (< t 0) (< v 0)) (- p) p))
|
||
(let ((global (assoc-ref (.globals info) o)))
|
||
(if global
|
||
(let* ((t ((compose type:pointer global:type) global))
|
||
;;(global:pointer (ident->variable info o))
|
||
(v (global:pointer global))
|
||
(p (+ (abs t) (abs v))))
|
||
(if (or (< t 0) (< v 0)) (- p) p))
|
||
0)))))
|
||
|
||
(define (ident->size info o)
|
||
((compose type:size (cut ident->type info <>)) o))
|
||
|
||
(define (ptr-inc o)
|
||
(if (< o 0) (1- o)
|
||
(1+ o)))
|
||
|
||
(define (ptr-dec o)
|
||
(if (< o 0) (1+ o)
|
||
(1- o)))
|
||
|
||
(define (pointer->ptr o)
|
||
(pmatch o
|
||
((pointer) 1)
|
||
((pointer ,pointer) (1+ (pointer->ptr pointer)))))
|
||
|
||
(define (expr->pointer info o)
|
||
(pmatch o
|
||
((pointer . _) (pointer->ptr o))
|
||
((p-expr (char ,value)) 0)
|
||
((p-expr (fixed ,value)) 0)
|
||
((ident ,name) (ident->pointer info name))
|
||
((p-expr ,expr) (expr->pointer info expr))
|
||
((de-ref ,expr) (ptr-dec (expr->pointer info expr)))
|
||
((assn-expr ,lhs ,op ,rhs) (expr->pointer info lhs))
|
||
((add ,a ,b) (expr->pointer info a))
|
||
((div ,a ,b) (expr->pointer info a))
|
||
((mod ,a ,b) (expr->pointer info a))
|
||
((mul ,a ,b) (expr->pointer info a))
|
||
((sub ,a ,b) (expr->pointer info a))
|
||
((neg ,a) (expr->pointer info a))
|
||
((pre-inc ,a) (expr->pointer info a))
|
||
((pre-dec ,a) (expr->pointer info a))
|
||
((post-inc ,a) (expr->pointer info a))
|
||
((post-dec ,a) (expr->pointer info a))
|
||
((ref-to ,expr) (ptr-inc (expr->pointer info expr)))
|
||
((array-ref ,index ,array)
|
||
(ptr-dec (abs (expr->pointer info array))))
|
||
|
||
((d-sel (ident ,field) ,struct)
|
||
(let ((type (ast->type info struct)))
|
||
(field-pointer info type field)))
|
||
|
||
((i-sel (ident ,field) ,struct)
|
||
(let ((type (ast->type info struct)))
|
||
(field-pointer info type field)))
|
||
|
||
((cast (type-name ,type) ,expr) ; FIXME: add expr?
|
||
(let* ((type (ast->type info type))
|
||
(pointer (type:pointer type)))
|
||
pointer))
|
||
((cast (type-name ,type (abs-declr ,pointer)) ,expr) ; FIXME: add expr?
|
||
(let* ((type (ast->type info type))
|
||
(pointer0 (type:pointer type))
|
||
(pointer1 (ptr-declr->pointer pointer))
|
||
(pointer2 (expr->pointer info expr)))
|
||
(+ pointer0 pointer1)))
|
||
((type-spec ,type)
|
||
(or (and=> (ast->type info o) type:pointer)
|
||
(begin
|
||
(stderr "expr->pointer: not supported: ~a\n" o)
|
||
0)))
|
||
((fctn-call (p-expr (ident ,function)) . ,rest)
|
||
(or (and=> (and=> (assoc-ref (.functions info) function) function:type)
|
||
(lambda (t)
|
||
(and (type? t) (type:pointer t))))
|
||
(begin
|
||
(stderr "expr->pointer: no such function: ~a\n" function)
|
||
0)))
|
||
|
||
((decl (decl-spec-list (type-spec ,type)) (init-declr-list (init-declr (ptr-declr ,pointer ,init) . ,initzer)))
|
||
(let* ((t (expr->pointer info `(type-spec ,type)))
|
||
(i (expr->pointer info init))
|
||
(p (expr->pointer info pointer))
|
||
(e (+ (abs t) (abs i) (abs p))))
|
||
(if (or (< t 0) (< i 0)) (- e) e)))
|
||
((decl (decl-spec-list (type-spec ,type)) (init-declr-list (init-declr ,init . ,initzer)))
|
||
(let* ((t (expr->pointer info `(type-spec ,type)))
|
||
(i (expr->pointer info init))
|
||
(p (+ (abs t) (abs i))))
|
||
(if (or (< t 0) (< i 0)) (- p) p)))
|
||
((ptr-declr ,pointer (array-of ,array . ,rest))
|
||
(let* ((p (expr->pointer info pointer))
|
||
(a (expr->pointer info array))
|
||
(t (+ (abs p) (abs a) 2)))
|
||
(- t)))
|
||
((ptr-declr ,pointer . ,rest)
|
||
(expr->pointer info pointer))
|
||
((array-of ,array . ,rest)
|
||
(let ((a (abs (expr->pointer info array))))
|
||
(- (+ a 1))))
|
||
(_ (stderr "expr->pointer: not supported: ~s\n" o) 0)))
|
||
|
||
(define (expr->size info o)
|
||
(let ((ptr (expr->pointer info o)))
|
||
(if (or (= ptr -1)
|
||
(= ptr 0))
|
||
(ast-type->size info o)
|
||
%pointer-size)))
|
||
|
||
(define (append-text info text)
|
||
(clone info #:text (append (.text info) text)))
|
||
|
||
(define (push-global info)
|
||
(lambda (o)
|
||
(let ((ptr (ident->pointer info o)))
|
||
(cond ((< ptr 0) (list (i386:push-label `(#:address ,o))))
|
||
(else (list (i386:push-label-mem `(#:address ,o))))))))
|
||
|
||
(define (push-local locals)
|
||
(lambda (o)
|
||
(wrap-as (i386:push-local (local:id o)))))
|
||
|
||
(define (push-global-address info)
|
||
(lambda (o)
|
||
(list (i386:push-label o))))
|
||
|
||
(define (push-local-address locals)
|
||
(lambda (o)
|
||
(wrap-as (i386:push-local-address (local:id o)))))
|
||
|
||
(define push-global-de-ref push-global)
|
||
|
||
(define (push-local-de-ref info)
|
||
(lambda (o)
|
||
(let* ((local o)
|
||
(ptr (local:pointer local))
|
||
(size (if (= ptr 1) (ast-type->size info (local:type o))
|
||
4)))
|
||
(case size
|
||
((1) (wrap-as (i386:push-byte-local-de-ref (local:id o))))
|
||
((2) (wrap-as (i386:push-word-local-de-ref (local:id o))))
|
||
((4) (wrap-as (i386:push-local-de-ref (local:id o))))
|
||
(else (error (format #f "TODO: push size >4: ~a\n" size)))))))
|
||
|
||
(define (push-local-de-de-ref info)
|
||
(lambda (o)
|
||
(let* ((local o)
|
||
(ptr (local:pointer local))
|
||
(size (if (= ptr 2) (ast-type->size info (local:type o));; URG
|
||
4)))
|
||
(if (= size 1)
|
||
(wrap-as (i386:push-byte-local-de-de-ref (local:id o)))
|
||
(error "TODO int-de-de-ref")))))
|
||
|
||
(define (make-global-entry key type pointer array value)
|
||
(cons key (make-global key type pointer array value #f)))
|
||
|
||
(define (string->global-entry string)
|
||
(let ((value (append (string->list string) (list #\nul))))
|
||
(make-global-entry `(#:string ,string) "char" 0 (length value) value)))
|
||
|
||
(define (make-local-entry name type pointer array id)
|
||
(cons name (make-local type pointer array id)))
|
||
|
||
(define* (mescc:trace name #:optional (type ""))
|
||
(format (current-error-port) " :~a~a\n" name type))
|
||
|
||
(define (push-ident info)
|
||
(lambda (o)
|
||
(let ((local (assoc-ref (.locals info) o)))
|
||
(if local
|
||
(begin
|
||
(let* ((ptr (local:pointer local)))
|
||
(if (or (< ptr 0)) ((push-local-address (.locals info)) local)
|
||
((push-local (.locals info)) local))))
|
||
(let ((global (assoc-ref (.globals info) o)))
|
||
(if global
|
||
((push-global info) o) ;; FIXME: char*/int
|
||
(let ((constant (assoc-ref (.constants info) o)))
|
||
(if constant
|
||
(wrap-as (append (i386:value->accu constant)
|
||
(i386:push-accu)))
|
||
((push-global-address #f) `(#:address ,o))))))))))
|
||
|
||
(define (push-ident-address info)
|
||
(lambda (o)
|
||
(let ((local (assoc-ref (.locals info) o)))
|
||
(if local ((push-local-address (.locals info)) local)
|
||
(let ((global (assoc-ref (.globals info) o)))
|
||
(if global
|
||
((push-global-address info) o)
|
||
((push-global-address #f) `(#:address ,o))))))))
|
||
|
||
(define (push-ident-de-ref info)
|
||
(lambda (o)
|
||
(let ((local (assoc-ref (.locals info) o)))
|
||
(if local ((push-local-de-ref info) local)
|
||
((push-global-de-ref info) o)))))
|
||
|
||
(define (push-ident-de-de-ref info)
|
||
(lambda (o)
|
||
(let ((local (assoc-ref (.locals info) o)))
|
||
(if local ((push-local-de-de-ref info) local)
|
||
(error "TODO: global push-local-de-de-ref")))))
|
||
|
||
(define (expr->arg info)
|
||
(lambda (o)
|
||
(pmatch o
|
||
((p-expr (string ,string))
|
||
(let* ((globals ((globals:add-string (.globals info)) string))
|
||
(info (clone info #:globals globals)))
|
||
(append-text info ((push-global-address info) `(#:string ,string)))))
|
||
(_ (let ((info (expr->accu o info)))
|
||
(append-text info (wrap-as (i386:push-accu))))))))
|
||
|
||
(define (globals:add-string globals)
|
||
(lambda (o)
|
||
(let ((string `(#:string ,o)))
|
||
(if (assoc-ref globals string) globals
|
||
(append globals (list (string->global-entry o)))))))
|
||
|
||
(define (local->accu o)
|
||
(let* ((ptr (local:pointer o))
|
||
(type (local:type o))
|
||
(size (if (= ptr 0) (type:size type)
|
||
4)))
|
||
(cond ((< ptr 0) (wrap-as (i386:local-ptr->accu (local:id o))))
|
||
(else (wrap-as (case size
|
||
((1) (i386:byte-local->accu (local:id o)))
|
||
((2) (i386:word-local->accu (local:id o)))
|
||
(else (i386:local->accu (local:id o)))))))))
|
||
|
||
(define (ident->accu info)
|
||
(lambda (o)
|
||
(cond ((assoc-ref (.locals info) o) => local->accu)
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global)
|
||
(let* ((ptr (ident->pointer info o)))
|
||
(cond ((< ptr 0) (list (i386:label->accu `(#:address ,global))))
|
||
(else (list (i386:label-mem->accu `(#:address ,global))))))))
|
||
((assoc-ref (.globals info) o)
|
||
=>
|
||
(lambda (global)
|
||
(let* ((ptr (ident->pointer info o)))
|
||
(cond ((< ptr 0) (list (i386:label->accu `(#:address ,o))))
|
||
(else (list (i386:label-mem->accu `(#:address ,o))))))))
|
||
((assoc-ref (.constants info) o)
|
||
=>
|
||
(lambda (constant) (wrap-as (i386:value->accu constant))))
|
||
(else (list (i386:label->accu `(#:address ,o)))))))
|
||
|
||
(define (ident-address->accu info)
|
||
(lambda (o)
|
||
(cond ((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (wrap-as (i386:local-ptr->accu (local:id local)))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (list (i386:label->accu `(#:address ,global)))))
|
||
((assoc-ref (.globals info) o)
|
||
=>
|
||
(lambda (global) (list (i386:label->accu `(#:address ,global)))))
|
||
(else (list (i386:label->accu `(#:address ,o)))))))
|
||
|
||
(define (ident-address->base info)
|
||
(lambda (o)
|
||
(cond
|
||
((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (wrap-as (i386:local-ptr->base (local:id local)))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (list (i386:label->base `(#:address ,global)))))
|
||
((assoc-ref (.globals info) o)
|
||
=>
|
||
(lambda (global) (list (i386:label->base `(#:address ,global)))))
|
||
(else (list (i386:label->base `(#:address ,o)))))))
|
||
|
||
(define (value->accu v)
|
||
(wrap-as (i386:value->accu v)))
|
||
|
||
(define (accu->local+n-text local n)
|
||
(let* ((type (local:type local))
|
||
(ptr (local:pointer local))
|
||
(size (if (= ptr -1) ((compose type:size local:type) local)
|
||
4))
|
||
(id (local:id local)))
|
||
(wrap-as (case size
|
||
((1) (i386:byte-accu->local+n id n))
|
||
((2) (i386:word-accu->local+n id n))
|
||
(else (i386:accu->local+n id n))))))
|
||
|
||
(define (accu->ident info)
|
||
(lambda (o)
|
||
(cond ((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (let ((size (->size local)))
|
||
(if (<= size 4) (wrap-as (i386:accu->local (local:id local)))
|
||
(wrap-as (i386:accu*n->local (local:id local) size))))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (let ((size (->size global)))
|
||
(if (<= size 4) (wrap-as (i386:accu->label global))
|
||
(wrap-as (i386:accu*n->label global size))))))
|
||
((assoc-ref (filter (negate static-global?) (.globals info)) o)
|
||
=>
|
||
(lambda (global) (let ((size (->size global)))
|
||
(if (<= size 4) (wrap-as (i386:accu->label global))
|
||
(wrap-as (i386:accu*n->label global size)))))))))
|
||
|
||
(define (value->ident info)
|
||
(lambda (o value)
|
||
(cond ((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (wrap-as (i386:value->local (local:id local) value))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (list (i386:value->label `(#:address ,global) value))))
|
||
((assoc-ref (filter (negate static-global?) (.globals info)) o)
|
||
=>
|
||
(lambda (global) (list (i386:value->label `(#:address ,global) value)))))))
|
||
|
||
(define (ident-add info)
|
||
(lambda (o n)
|
||
(cond ((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (wrap-as (i386:local-add (local:id local) n))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (list (i386:label-mem-add `(#:address ,o) n))))
|
||
((assoc-ref (filter (negate static-global?) (.globals info)) o)
|
||
=>
|
||
(lambda (global) (list (i386:label-mem-add `(#:address ,global) n)))))))
|
||
|
||
(define (expr-add info)
|
||
(lambda (o n)
|
||
(let* ((info (expr->accu* o info))
|
||
(info (append-text info (wrap-as (i386:accu-mem-add n)))))
|
||
info)))
|
||
|
||
(define (ident-address-add info)
|
||
(lambda (o n)
|
||
(cond ((assoc-ref (.locals info) o)
|
||
=>
|
||
(lambda (local) (wrap-as (append (i386:push-accu)
|
||
(i386:local->accu (local:id local))
|
||
(i386:accu-mem-add n)
|
||
(i386:pop-accu)))))
|
||
((assoc-ref (.statics info) o)
|
||
=>
|
||
(lambda (global) (list (wrap-as (append (i386:push-accu)
|
||
(i386:label->accu `(#:address ,global))
|
||
(i386:accu-mem-add n)
|
||
(i386:pop-accu))))))
|
||
((assoc-ref (filter (negate static-global?) (.globals info)) o)
|
||
=>
|
||
(lambda (global) (list (wrap-as (append (i386:push-accu)
|
||
(i386:label->accu `(#:address ,global))
|
||
(i386:accu-mem-add n)
|
||
(i386:pop-accu)))))))))
|
||
|
||
(define (binop->accu info)
|
||
(lambda (a b c)
|
||
(let* ((info (expr->accu a info))
|
||
(info (expr->base b info)))
|
||
(append-text info (wrap-as c)))))
|
||
|
||
(define (wrap-as o . annotation)
|
||
`(,@annotation ,o))
|
||
|
||
(define (make-comment o)
|
||
(wrap-as `((#:comment ,o))))
|
||
|
||
(define (ast->comment o)
|
||
(if mes? '()
|
||
(begin
|
||
(pmatch o
|
||
;; Nyacc 0.80.42: missing (enum-ref (ident "fred"))
|
||
((decl (decl-spec-list (type-spec (enum-ref . _))) . _)
|
||
'())
|
||
(_ (let ((source (with-output-to-string (lambda () (pretty-print-c99 o)))))
|
||
(make-comment (string-join (string-split source #\newline) " "))))))))
|
||
|
||
(define (accu*n info n)
|
||
(append-text info (wrap-as (case n
|
||
((1) (i386:accu->base))
|
||
((2) (i386:accu+accu))
|
||
((3) (append (i386:accu->base)
|
||
(i386:accu+accu)
|
||
(i386:accu+base)))
|
||
((4) (i386:accu-shl 2))
|
||
((8) (append (i386:accu+accu)
|
||
(i386:accu-shl 2)))
|
||
((12) (append (i386:accu->base)
|
||
(i386:accu+accu)
|
||
(i386:accu+base)
|
||
(i386:accu-shl 2)))
|
||
((16) (i386:accu-shl 4))
|
||
(else (append (i386:value->base n)
|
||
(i386:accu*base)))))))
|
||
|
||
(define (accu->base-mem*n- info n)
|
||
(wrap-as
|
||
(case n
|
||
((1) (i386:byte-accu->base-mem))
|
||
((2) (i386:word-accu->base-mem))
|
||
((4) (i386:accu->base-mem))
|
||
(else (append (let loop ((i 0))
|
||
(if (>= i n) '()
|
||
(append (if (= i 0) '()
|
||
(append (i386:accu+value 4)
|
||
(i386:base+value 4)))
|
||
(case (- n i)
|
||
((1) (append (i386:accu+value -3)
|
||
(i386:base+value -3)
|
||
(i386:accu-mem->base-mem)))
|
||
((2) (append (i386:accu+value -2)
|
||
(i386:base+value -2)
|
||
(i386:accu-mem->base-mem)))
|
||
((3) (append (i386:accu+value -1)
|
||
(i386:base+value -1)
|
||
(i386:accu-mem->base-mem)))
|
||
(else (i386:accu-mem->base-mem)))
|
||
(loop (+ i 4))))))))))
|
||
|
||
(define (accu->base-mem*n info n)
|
||
(append-text info (accu->base-mem*n- info n)))
|
||
|
||
(define (expr->accu* o info)
|
||
(pmatch o
|
||
|
||
((p-expr (ident ,name))
|
||
(append-text info ((ident-address->accu info) name)))
|
||
|
||
((de-ref ,expr)
|
||
(expr->accu expr info))
|
||
|
||
((d-sel (ident ,field) ,struct)
|
||
(let* ((type (ast->type info struct))
|
||
(offset (field-offset info type field))
|
||
(info (expr->accu* struct info)))
|
||
(append-text info (wrap-as (i386:accu+value offset)))))
|
||
|
||
((i-sel (ident ,field) (fctn-call (p-expr (ident ,function)) . ,rest))
|
||
(let* ((type (ast->type info `(fctn-call (p-expr (ident ,function)) ,@rest)))
|
||
(offset (field-offset info type field))
|
||
(info (expr->accu `(fctn-call (p-expr (ident ,function)) ,@rest) info)))
|
||
(append-text info (wrap-as (i386:accu+value offset)))))
|
||
|
||
((i-sel (ident ,field) ,struct)
|
||
(let* ((type (ast->type info struct))
|
||
(offset (field-offset info type field))
|
||
(info (expr->accu* struct info)))
|
||
(append-text info (append (wrap-as (i386:mem->accu))
|
||
(wrap-as (i386:accu+value offset))))))
|
||
|
||
((array-ref ,index ,array)
|
||
(let* ((info (expr->accu index info))
|
||
(ptr (expr->pointer info array))
|
||
(size (expr->size info o))
|
||
(info (accu*n info size))
|
||
(info (expr->base array info)))
|
||
(append-text info (wrap-as (i386:accu+base)))))
|
||
|
||
(_ (error "expr->accu*: not supported: " o))))
|
||
|
||
(define (expr->accu o info)
|
||
(let ((locals (.locals info))
|
||
(constants (.constants info))
|
||
(text (.text info))
|
||
(globals (.globals info)))
|
||
(pmatch o
|
||
((expr) info)
|
||
|
||
((comma-expr) info)
|
||
|
||
((comma-expr ,a . ,rest)
|
||
(let ((info (expr->accu a info)))
|
||
(expr->accu `(comma-expr ,@rest) info)))
|
||
|
||
((p-expr (string ,string))
|
||
(let* ((globals ((globals:add-string globals) string))
|
||
(info (clone info #:globals globals)))
|
||
(append-text info (list (i386:label->accu `(#:string ,string))))))
|
||
|
||
((p-expr (fixed ,value))
|
||
(let ((value (cstring->number value)))
|
||
(append-text info (wrap-as (i386:value->accu value)))))
|
||
|
||
((neg (p-expr (fixed ,value)))
|
||
(let ((value (- (cstring->number value))))
|
||
(append-text info (wrap-as (i386:value->accu value)))))
|
||
|
||
((p-expr (char ,char))
|
||
(let ((char (char->integer (car (string->list char)))))
|
||
(append-text info (wrap-as (i386:value->accu char)))))
|
||
|
||
((p-expr (string . ,strings))
|
||
(append-text info (list (i386:label->accu `(#:string ,(apply string-append strings))))))
|
||
|
||
((p-expr (ident ,name))
|
||
(append-text info ((ident->accu info) name)))
|
||
|
||
((initzer ,initzer)
|
||
(expr->accu initzer info))
|
||
|
||
;; offsetoff
|
||
((ref-to (i-sel (ident ,field) (cast (type-name (decl-spec-list ,struct) (abs-declr (pointer))) (p-expr (fixed ,base)))))
|
||
(let* ((type (ast->type info struct))
|
||
(offset (field-offset info type field))
|
||
(base (cstring->number base)))
|
||
(append-text info (wrap-as (i386:value->accu (+ base offset))))))
|
||
|
||
;; &foo
|
||
((ref-to (p-expr (ident ,name)))
|
||
(append-text info ((ident-address->accu info) name)))
|
||
|
||
;; &*foo
|
||
((ref-to (de-ref ,expr))
|
||
(expr->accu expr info))
|
||
|
||
((ref-to ,expr)
|
||
(expr->accu* expr info))
|
||
|
||
((sizeof-expr ,expr)
|
||
(append-text info (wrap-as (i386:value->accu (expr->size info expr)))))
|
||
|
||
((sizeof-type (type-name (decl-spec-list (type-spec (fixed-type ,name)))))
|
||
(let* ((type name)
|
||
(size (ast-type->size info type)))
|
||
(append-text info (wrap-as (i386:value->accu size)))))
|
||
|
||
((sizeof-type (type-name (decl-spec-list (type-spec (struct-ref (ident ,type))))))
|
||
(let* ((type `("tag" ,type))
|
||
(size (ast-type->size info type)))
|
||
(append-text info (wrap-as (i386:value->accu size)))))
|
||
|
||
((sizeof-type (type-name (decl-spec-list (type-spec (typename ,type)))))
|
||
(let ((size (ast-type->size info type)))
|
||
(append-text info (wrap-as (i386:value->accu size)))))
|
||
|
||
((sizeof-type (type-name (decl-spec-list ,type) (abs-declr (pointer))))
|
||
(let ((size 4))
|
||
(append-text info (wrap-as (i386:value->accu size)))))
|
||
|
||
((array-ref ,index ,array)
|
||
(let* ((info (expr->accu* o info))
|
||
(size (expr->size info o)))
|
||
(append-text info (wrap-as (case size
|
||
((1) (i386:byte-mem->accu))
|
||
((2) (i386:word-mem->accu))
|
||
((4) (i386:mem->accu))
|
||
(else '()))))))
|
||
|
||
((d-sel ,field ,struct)
|
||
(let* ((info (expr->accu* o info))
|
||
(info (append-text info (ast->comment o)))
|
||
(ptr (expr->pointer info o))
|
||
(size (if (= ptr 0) (ast-type->size info o)
|
||
4)))
|
||
(if (or (= -2 ptr) (= -1 ptr)) info
|
||
(append-text info (wrap-as (case size
|
||
((1) (i386:byte-mem->accu))
|
||
((2) (i386:word-mem->accu))
|
||
((4) (i386:mem->accu))
|
||
(else '())))))))
|
||
|
||
((i-sel ,field ,struct)
|
||
(let* ((info (expr->accu* o info))
|
||
(info (append-text info (ast->comment o)))
|
||
(ptr (expr->pointer info o))
|
||
(size (if (= ptr 0) (ast-type->size info o)
|
||
4)))
|
||
(if (or (= -2 ptr) (= ptr -1)) info
|
||
(append-text info (wrap-as (case size
|
||
((1) (i386:byte-mem->accu))
|
||
((2) (i386:word-mem->accu))
|
||
((4) (i386:mem->accu))
|
||
(else '())))))))
|
||
|
||
((de-ref ,expr)
|
||
(let* ((info (expr->accu expr info))
|
||
(size (expr->size info o)))
|
||
(append-text info (wrap-as (case size
|
||
((1) (i386:byte-mem->accu))
|
||
((2) (i386:word-mem->accu))
|
||
((4) (i386:mem->accu))
|
||
(else '()))))))
|
||
|
||
((fctn-call (p-expr (ident ,name)) (expr-list . ,expr-list))
|
||
(if (equal? name "asm") (let ((arg0 (cadr (cadar expr-list)))) ;; FIXME
|
||
(append-text info (wrap-as (asm->m1 arg0))))
|
||
(let* ((text-length (length text))
|
||
(args-info (let loop ((expressions (reverse expr-list)) (info info))
|
||
(if (null? expressions) info
|
||
(loop (cdr expressions) ((expr->arg info) (car expressions))))))
|
||
(n (length expr-list)))
|
||
(if (not (assoc-ref locals name))
|
||
(begin
|
||
(if (and (not (assoc name (.functions info)))
|
||
(not (assoc name globals))
|
||
(not (equal? name (.function info))))
|
||
(stderr "warning: undeclared function: ~a\n" name))
|
||
(append-text args-info (list (i386:call-label name n))))
|
||
(let* ((empty (clone info #:text '()))
|
||
(accu (expr->accu `(p-expr (ident ,name)) empty)))
|
||
(append-text args-info (append (.text accu)
|
||
(list (i386:call-accu n)))))))))
|
||
|
||
((fctn-call ,function (expr-list . ,expr-list))
|
||
(let* ((text-length (length text))
|
||
(args-info (let loop ((expressions (reverse expr-list)) (info info))
|
||
(if (null? expressions) info
|
||
(loop (cdr expressions) ((expr->arg info) (car expressions))))))
|
||
(n (length expr-list))
|
||
(empty (clone info #:text '()))
|
||
(accu (expr->accu function empty)))
|
||
(append-text args-info (append (.text accu)
|
||
(list (i386:call-accu n))))))
|
||
|
||
((cond-expr . ,cond-expr)
|
||
(ast->info `(expr-stmt ,o) info))
|
||
|
||
((post-inc ,expr)
|
||
(let* ((info (append (expr->accu expr info)))
|
||
(info (append-text info (wrap-as (i386:push-accu))))
|
||
(ptr (expr->pointer info expr))
|
||
(size (cond ((= ptr 1) (ast-type->size info expr))
|
||
((> ptr 1) 4)
|
||
(else 1)))
|
||
(info ((expr-add info) expr size))
|
||
(info (append-text info (wrap-as (i386:pop-accu)))))
|
||
info))
|
||
|
||
((post-dec ,expr)
|
||
(let* ((info (append (expr->accu expr info)))
|
||
(info (append-text info (wrap-as (i386:push-accu))))
|
||
(ptr (expr->pointer info expr))
|
||
(size (cond ((= ptr 1) (ast-type->size info expr))
|
||
((> ptr 1) 4)
|
||
(else 1)))
|
||
(info ((expr-add info) expr (- size)))
|
||
(info (append-text info (wrap-as (i386:pop-accu)))))
|
||
info))
|
||
|
||
((pre-inc ,expr)
|
||
(let* ((ptr (expr->pointer info expr))
|
||
(size (cond ((= ptr 1) (ast-type->size info expr))
|
||
((> ptr 1) 4)
|
||
(else 1)))
|
||
(info ((expr-add info) expr size))
|
||
(info (append (expr->accu expr info))))
|
||
info))
|
||
|
||
((pre-dec ,expr)
|
||
(let* ((ptr (expr->pointer info expr))
|
||
(size (cond ((= ptr 1) (ast-type->size info expr))
|
||
((> ptr 1) 4)
|
||
(else 1)))
|
||
(info ((expr-add info) expr (- size)))
|
||
(info (append (expr->accu expr info))))
|
||
info))
|
||
|
||
|
||
|
||
((add ,a (p-expr (fixed ,value)))
|
||
(let* ((ptr (expr->pointer info a))
|
||
(type (ast->type info a))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union))))
|
||
(size (cond ((= ptr 1) (ast-type->size info a))
|
||
((> ptr 1) 4)
|
||
((and struct? (= ptr -2)) 4)
|
||
((and struct? (= ptr 2)) 4)
|
||
(else 1)))
|
||
(info (expr->accu a info))
|
||
(value (cstring->number value))
|
||
(value (* size value)))
|
||
(append-text info (wrap-as (i386:accu+value value)))))
|
||
|
||
((add ,a ,b)
|
||
(let* ((ptr (expr->pointer info a))
|
||
(ptr-b (expr->pointer info b))
|
||
(type (ast->type info a))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union))))
|
||
(size (cond ((= ptr 1) (ast-type->size info a))
|
||
((> ptr 1) 4)
|
||
((and struct? (= ptr -2)) 4)
|
||
((and struct? (= ptr 2)) 4)
|
||
(else 1))))
|
||
(if (or (= size 1)) ((binop->accu info) a b (i386:accu+base))
|
||
(let* ((info (expr->accu b info))
|
||
(info (append-text info (wrap-as (append (i386:value->base size)
|
||
(i386:accu*base)
|
||
(i386:accu->base)))))
|
||
(info (expr->accu a info)))
|
||
(append-text info (wrap-as (i386:accu+base)))))))
|
||
|
||
((sub ,a (p-expr (fixed ,value)))
|
||
(let* ((ptr (expr->pointer info a))
|
||
(type (ast->type info a))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union))))
|
||
(size (cond ((= ptr 1) (ast-type->size info a))
|
||
((> ptr 1) 4)
|
||
((and struct? (= ptr -2)) 4)
|
||
((and struct? (= ptr 2)) 4)
|
||
(else 1)))
|
||
(info (expr->accu a info))
|
||
(value (cstring->number value))
|
||
(value (* size value)))
|
||
(append-text info (wrap-as (i386:accu+value (- value))))))
|
||
|
||
((sub ,a ,b)
|
||
(let* ((ptr (expr->pointer info a))
|
||
(ptr-b (expr->pointer info b))
|
||
(type (ast->type info a))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union))))
|
||
(size (cond ((= ptr 1) (ast-type->size info a))
|
||
((> ptr 1) 4)
|
||
((and struct? (= ptr -2)) 4)
|
||
((and struct? (= ptr 2)) 4)
|
||
(else 1))))
|
||
(if (or (= size 1) (or (= ptr-b -2) (= ptr-b 1)))
|
||
(let ((info ((binop->accu info) a b (i386:accu-base))))
|
||
(if (and (not (= ptr-b -2)) (not (= ptr-b 1))) info
|
||
(append-text info (wrap-as (append (i386:value->base size)
|
||
(i386:accu/base))))))
|
||
(let* ((info (expr->accu b info))
|
||
(info (append-text info (wrap-as (append (i386:value->base size)
|
||
(i386:accu*base)
|
||
(i386:accu->base)))))
|
||
(info (expr->accu a info)))
|
||
(append-text info (wrap-as (i386:accu-base)))))))
|
||
|
||
((bitwise-and ,a ,b) ((binop->accu info) a b (i386:accu-and-base)))
|
||
((bitwise-not ,expr)
|
||
(let ((info (ast->info expr info)))
|
||
(append-text info (wrap-as (i386:accu-not)))))
|
||
((bitwise-or ,a ,b) ((binop->accu info) a b (i386:accu-or-base)))
|
||
((bitwise-xor ,a ,b) ((binop->accu info) a b (i386:accu-xor-base)))
|
||
((lshift ,a ,b) ((binop->accu info) a b (i386:accu<<base)))
|
||
((rshift ,a ,b) ((binop->accu info) a b (i386:accu>>base)))
|
||
((div ,a ,b) ((binop->accu info) a b (i386:accu/base)))
|
||
((mod ,a ,b) ((binop->accu info) a b (i386:accu%base)))
|
||
((mul ,a ,b) ((binop->accu info) a b (i386:accu*base)))
|
||
|
||
((not ,expr)
|
||
(let* ((test-info (ast->info expr info)))
|
||
(clone info #:text
|
||
(append (.text test-info)
|
||
(wrap-as (i386:accu-negate)))
|
||
#:globals (.globals test-info))))
|
||
|
||
((neg ,expr)
|
||
(let ((info (expr->base expr info)))
|
||
(append-text info (append (wrap-as (i386:value->accu 0))
|
||
(wrap-as (i386:sub-base))))))
|
||
|
||
((eq ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:z->accu))))
|
||
((ge ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:ge?->accu))))
|
||
((gt ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:g?->accu) (i386:accu-test))))
|
||
|
||
;; FIXME: set accu *and* flags
|
||
((ne ,a ,b) ((binop->accu info) a b (append (i386:push-accu)
|
||
(i386:sub-base)
|
||
(i386:nz->accu)
|
||
(i386:accu<->stack)
|
||
(i386:sub-base)
|
||
(i386:xor-zf)
|
||
(i386:pop-accu))))
|
||
|
||
((ne ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:xor-zf))))
|
||
((le ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:le?->accu))))
|
||
((lt ,a ,b) ((binop->accu info) a b (append (i386:sub-base) (i386:l?->accu))))
|
||
|
||
((or ,a ,b)
|
||
(let* ((info (expr->accu a info))
|
||
(here (number->string (length (.text info))))
|
||
(skip-b-label (string-append "_" (.function info) "_" here "_or_skip_b"))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (append-text info (wrap-as (i386:jump-nz skip-b-label))))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (expr->accu b info))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (append-text info (wrap-as `((#:label ,skip-b-label))))))
|
||
info))
|
||
|
||
((and ,a ,b)
|
||
(let* ((info (expr->accu a info))
|
||
(here (number->string (length (.text info))))
|
||
(skip-b-label (string-append "_" (.function info) "_" here "_and_skip_b"))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (append-text info (wrap-as (i386:jump-z skip-b-label))))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (expr->accu b info))
|
||
(info (append-text info (wrap-as (i386:accu-test))))
|
||
(info (append-text info (wrap-as `((#:label ,skip-b-label))))))
|
||
info))
|
||
|
||
((cast ,type ,expr)
|
||
(expr->accu expr info))
|
||
|
||
((assn-expr (de-ref (post-inc (p-expr (ident ,name)))) (op ,op) ,b)
|
||
(let* ((info (expr->accu `(assn-expr (de-ref (p-expr (ident ,name))) (op ,op) ,b) info))
|
||
(type (ident->type info name))
|
||
(ptr (ident->pointer info name))
|
||
(size (if (> ptr 1) 4 1)))
|
||
(append-text info ((ident-add info) name size))))
|
||
|
||
((assn-expr (de-ref (post-dec (p-expr (ident ,name)))) (op ,op) ,b)
|
||
(let* ((info (expr->accu `(assn-expr (de-ref (p-expr (ident ,name))) (op ,op) ,b) info))
|
||
(type (ident->type info name))
|
||
(ptr (ident->pointer info name))
|
||
(size (if (> ptr 1) 4 1)))
|
||
(append-text info ((ident-add info) name (- size)))))
|
||
|
||
((assn-expr ,a (op ,op) ,b)
|
||
(let* ((info (append-text info (ast->comment o)))
|
||
(ptr-a (expr->pointer info a))
|
||
(ptr-b (expr->pointer info b))
|
||
(size-a (expr->size info a))
|
||
(size-b (expr->size info b))
|
||
(info (expr->accu b info))
|
||
(info (if (equal? op "=") info
|
||
(let* ((ptr (expr->pointer info a))
|
||
(ptr-b (expr->pointer info b))
|
||
(type (ast->type info a))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union))))
|
||
(size (cond ((= ptr 1) (ast-type->size info a))
|
||
((> ptr 1) 4)
|
||
((and struct? (= ptr -2)) 4)
|
||
((and struct? (= ptr 2)) 4)
|
||
(else 1)))
|
||
(info (if (or (= size 1) (= ptr-b 1)) info
|
||
(let ((info (append-text info (wrap-as (i386:value->base size)))))
|
||
(append-text info (wrap-as (i386:accu*base))))))
|
||
(info (append-text info (wrap-as (i386:push-accu))))
|
||
(info (expr->accu a info))
|
||
(info (append-text info (wrap-as (i386:pop-base))))
|
||
(info (append-text info (cond ((equal? op "+=") (wrap-as (i386:accu+base)))
|
||
((equal? op "-=") (wrap-as (i386:accu-base)))
|
||
((equal? op "*=") (wrap-as (i386:accu*base)))
|
||
((equal? op "/=") (wrap-as (i386:accu/base)))
|
||
((equal? op "%=") (wrap-as (i386:accu%base)))
|
||
((equal? op "&=") (wrap-as (i386:accu-and-base)))
|
||
((equal? op "|=") (wrap-as (i386:accu-or-base)))
|
||
((equal? op "^=") (wrap-as (i386:accu-xor-base)))
|
||
((equal? op ">>=") (wrap-as (i386:accu>>base)))
|
||
((equal? op "<<=") (wrap-as (i386:accu<<base)))
|
||
(else (error (format #f "mescc: op ~a not supported: ~a\n" op o)))))))
|
||
(cond ((not (and (= ptr 1) (= ptr-b 1))) info)
|
||
((equal? op "-=") (append-text info (wrap-as (append (i386:value->base size)
|
||
(i386:accu/base)))))
|
||
(else (error (format #f "invalid operands to binary ~s (have ~s* and ~s*)" op type (ast->type info b)))))))))
|
||
(when (and (equal? op "=")
|
||
(not (= size-a size-b))
|
||
(not (and (or (= size-a 1) (= size-a 2))
|
||
(= size-b 4)))
|
||
(not (and (= size-a 2)
|
||
(= size-b 4)))
|
||
(not (and (= size-a 4)
|
||
(or (= size-b 1) (= size-b 2)))))
|
||
(stderr "ERROR assign: ~a" (with-output-to-string (lambda () (pretty-print-c99 o))))
|
||
(stderr " size[~a]:~a != size[~a]:~a\n" ptr-a size-a ptr-b size-b))
|
||
(pmatch a
|
||
((p-expr (ident ,name))
|
||
(if (or (<= size-a 4) ;; FIXME: long long = int
|
||
(<= size-b 4)) (append-text info ((accu->ident info) name))
|
||
(let ((info (expr->base* a info)))
|
||
(accu->base-mem*n info size-a))))
|
||
(_ (let ((info (expr->base* a info)))
|
||
(accu->base-mem*n info (min size-a (max 4 size-b)))))))) ;; FIXME: long long = int
|
||
|
||
(_ (error "expr->accu: not supported: " o)))))
|
||
|
||
(define (expr->base o info)
|
||
(let* ((info (append-text info (wrap-as (i386:push-accu))))
|
||
(info (expr->accu o info))
|
||
(info (append-text info (wrap-as (append (i386:accu->base) (i386:pop-accu))))))
|
||
info))
|
||
|
||
(define (expr->base* o info)
|
||
(let* ((info (append-text info (wrap-as (i386:push-accu))))
|
||
(info (expr->accu* o info))
|
||
(info (append-text info (wrap-as (i386:accu->base))))
|
||
(info (append-text info (wrap-as (i386:pop-accu)))))
|
||
info))
|
||
|
||
(define (comment? o)
|
||
(and (pair? o) (pair? (car o)) (eq? (caar o) #:comment)))
|
||
|
||
(define (clause->info info i label last?)
|
||
(define clause-label
|
||
(string-append label "clause" (number->string i)))
|
||
(define body-label
|
||
(string-append label "body" (number->string i)))
|
||
(define (jump label)
|
||
(wrap-as (i386:jump label)))
|
||
(define (jump-nz label)
|
||
(wrap-as (i386:jump-nz label)))
|
||
(define (jump-z label)
|
||
(wrap-as (i386:jump-z label)))
|
||
(define (test->text test)
|
||
(let ((value (pmatch test
|
||
(0 0)
|
||
((p-expr (char ,value)) (char->integer (car (string->list value))))
|
||
((p-expr (ident ,constant)) (assoc-ref (.constants info) constant))
|
||
((p-expr (fixed ,value)) (cstring->number value))
|
||
((neg (p-expr (fixed ,value))) (- (cstring->number value)))
|
||
(_ (error "case test: not supported: " test)))))
|
||
(append (wrap-as (i386:accu-cmp-value value))
|
||
(jump-z body-label))))
|
||
(define (cases+jump info cases)
|
||
(let* ((info (append-text info (wrap-as `((#:label ,clause-label)))))
|
||
(next-clause-label (if last? (string-append label "break")
|
||
(string-append label "clause" (number->string (1+ i)))))
|
||
(info (append-text info (apply append cases)))
|
||
(info (if (null? cases) info
|
||
(append-text info (jump next-clause-label))))
|
||
(info (append-text info (wrap-as `((#:label ,body-label))))))
|
||
info))
|
||
|
||
(lambda (o)
|
||
(let loop ((o o) (cases '()) (clause #f))
|
||
(pmatch o
|
||
((case ,test ,statement)
|
||
(loop statement (append cases (list (test->text test))) clause))
|
||
((default ,statement)
|
||
(loop statement cases clause))
|
||
((default . ,statements)
|
||
(loop `(compd-stmt (block-item-list ,@statements)) cases clause))
|
||
((compd-stmt (block-item-list))
|
||
(loop '() cases clause))
|
||
((compd-stmt (block-item-list . ,elements))
|
||
(let ((clause (or clause (cases+jump info cases))))
|
||
(loop `(compd-stmt (block-item-list ,@(cdr elements))) cases
|
||
(ast->info (car elements) clause))))
|
||
(()
|
||
(let ((clause (or clause (cases+jump info cases))))
|
||
(if last? clause
|
||
(let ((next-body-label (string-append label "body"
|
||
(number->string (1+ i)))))
|
||
(append-text clause (wrap-as (i386:jump next-body-label)))))))
|
||
(_
|
||
(let ((clause (or clause (cases+jump info cases))))
|
||
(loop '() cases
|
||
(ast->info o clause))))))))
|
||
|
||
(define (test-jump-label->info info label)
|
||
(define (jump type . test)
|
||
(lambda (o)
|
||
(let* ((info (ast->info o info))
|
||
(info (append-text info (make-comment "jmp test LABEL")))
|
||
(jump-text (wrap-as (type label))))
|
||
(append-text info (append (if (null? test) '() (car test))
|
||
jump-text)))))
|
||
(lambda (o)
|
||
(pmatch o
|
||
((expr) info)
|
||
;; unsigned
|
||
;; ((le ,a ,b) ((jump i386:jump-ncz) o)) ; ja
|
||
;; ((lt ,a ,b) ((jump i386:jump-nc) o)) ; jae
|
||
;; ((ge ,a ,b) ((jump i386:jump-ncz) o))
|
||
;; ((gt ,a ,b) ((jump i386:jump-nc) o))
|
||
|
||
((le ,a ,b) ((jump i386:jump-g) o))
|
||
((lt ,a ,b) ((jump i386:jump-ge) o))
|
||
((ge ,a ,b) ((jump i386:jump-l) o))
|
||
((gt ,a ,b) ((jump i386:jump-le) o))
|
||
|
||
((ne ,a ,b) ((jump i386:jump-nz) o))
|
||
((eq ,a ,b) ((jump i386:jump-nz) o))
|
||
((not _) ((jump i386:jump-z) o))
|
||
|
||
((and ,a ,b)
|
||
(let* ((info ((test-jump-label->info info label) a))
|
||
(info ((test-jump-label->info info label) b)))
|
||
info))
|
||
|
||
((or ,a ,b)
|
||
(let* ((here (number->string (length (if mes? (.text info)
|
||
(filter (negate comment?) (.text info))))))
|
||
(skip-b-label (string-append label "_skip_b_" here))
|
||
(b-label (string-append label "_b_" here))
|
||
(info ((test-jump-label->info info b-label) a))
|
||
(info (append-text info (wrap-as (i386:jump skip-b-label))))
|
||
(info (append-text info (wrap-as `((#:label ,b-label)))))
|
||
(info ((test-jump-label->info info label) b))
|
||
(info (append-text info (wrap-as `((#:label ,skip-b-label))))))
|
||
info))
|
||
|
||
((array-ref ,index ,expr) (let* ((ptr (expr->pointer info expr))
|
||
(size (if (= ptr 1) (ast-type->size info expr)
|
||
4)))
|
||
((jump (if (= size 1) i386:jump-byte-z
|
||
i386:jump-z)
|
||
(wrap-as (i386:accu-zero?))) o)))
|
||
|
||
((de-ref ,expr) (let* ((ptr (expr->pointer info expr))
|
||
(size (if (= ptr 1) (ast-type->size info expr)
|
||
4)))
|
||
((jump (if (= size 1) i386:jump-byte-z
|
||
i386:jump-z)
|
||
(wrap-as (i386:accu-zero?))) o)))
|
||
|
||
((assn-expr (p-expr (ident ,name)) ,op ,expr)
|
||
((jump i386:jump-z
|
||
(append ((ident->accu info) name)
|
||
(wrap-as (i386:accu-zero?)))) o))
|
||
|
||
(_ ((jump i386:jump-z (wrap-as (i386:accu-zero?))) o)))))
|
||
|
||
(define (cstring->number s)
|
||
(let ((s (cond ((string-suffix? "ULL" s) (string-drop-right s 3))
|
||
((string-suffix? "UL" s) (string-drop-right s 2))
|
||
((string-suffix? "LL" s) (string-drop-right s 2))
|
||
((string-suffix? "L" s) (string-drop-right s 1))
|
||
(else s))))
|
||
(cond ((string-prefix? "0x" s) (string->number (string-drop s 2) 16))
|
||
((string-prefix? "0b" s) (string->number (string-drop s 2) 2))
|
||
((string-prefix? "0" s) (string->number s 8))
|
||
(else (string->number s)))))
|
||
|
||
(define (expr->number info o)
|
||
(pmatch o
|
||
((fixed ,a) (cstring->number a))
|
||
((p-expr ,expr) (expr->number info expr))
|
||
((neg ,a)
|
||
(- (expr->number info a)))
|
||
((add ,a ,b)
|
||
(+ (expr->number info a) (expr->number info b)))
|
||
((bitwise-and ,a ,b)
|
||
(logand (expr->number info a) (expr->number info b)))
|
||
((bitwise-not ,a)
|
||
(lognot (expr->number info a)))
|
||
((bitwise-or ,a ,b)
|
||
(logior (expr->number info a) (expr->number info b)))
|
||
((div ,a ,b)
|
||
(quotient (expr->number info a) (expr->number info b)))
|
||
((mul ,a ,b)
|
||
(* (expr->number info a) (expr->number info b)))
|
||
((sub ,a ,b)
|
||
(- (expr->number info a) (expr->number info b)))
|
||
((sizeof-type (type-name (decl-spec-list (type-spec ,type))))
|
||
(ast-type->size info type))
|
||
((sizeof-expr (d-sel (ident ,field) (p-expr (ident ,struct))))
|
||
(let ((type (ident->type info struct)))
|
||
(field-size info type field)))
|
||
((sizeof-expr (i-sel (ident ,field) (p-expr (ident ,struct))))
|
||
(let ((type (ident->type info struct)))
|
||
(field-size info type field)))
|
||
((lshift ,x ,y)
|
||
(ash (expr->number info x) (expr->number info y)))
|
||
((rshift ,x ,y)
|
||
(ash (expr->number info x) (- (expr->number info y))))
|
||
((p-expr (ident ,name))
|
||
(let ((value (assoc-ref (.constants info) name)))
|
||
(or value
|
||
(error (format #f "expr->number: undeclared identifier: ~s\n" o)))))
|
||
((cast ,type ,expr) (expr->number info expr))
|
||
((cond-expr ,test ,then ,else)
|
||
(if (p-expr->bool info test) (expr->number info then) (expr->number info else)))
|
||
(,string (guard (string? string)) (cstring->number string))
|
||
(_ (error (format #f "expr->number: not supported: ~s\n" o)))))
|
||
|
||
(define (p-expr->bool info o)
|
||
(pmatch o
|
||
((eq ,a ,b) (eq? (expr->number info a) (expr->number info b)))))
|
||
|
||
|
||
(define (struct-field info)
|
||
(lambda (o)
|
||
(pmatch o
|
||
((comp-decl (decl-spec-list (type-spec (enum-ref (ident ,type))))
|
||
(comp-declr-list (comp-declr (ident ,name))))
|
||
(list (list name `("tag" ,type) 4 0)))
|
||
((comp-decl (decl-spec-list (type-spec (fixed-type ,type))) (comp-declr-list (comp-declr (ident ,name))))
|
||
(list (list name type (ast-type->size info type) 0)))
|
||
((comp-decl (decl-spec-list (type-spec (typename ,type))) (comp-declr-list (comp-declr (ident ,name))))
|
||
(list (list name type (ast-type->size info type) 0)))
|
||
((comp-decl (decl-spec-list (type-spec (typename ,type))) (comp-declr-list (comp-declr (ptr-declr (pointer (pointer)) (ident ,name)))))
|
||
(list (list name type 4 2)))
|
||
((comp-decl (decl-spec-list (type-spec (fixed-type ,type))) (comp-declr-list (comp-declr (ftn-declr (scope (ptr-declr (pointer) (ident ,name))) (param-list . ,param-list)))))
|
||
(list (list name type 4 1)))
|
||
((comp-decl (decl-spec-list (type-spec (fixed-type ,type))) (comp-declr-list (comp-declr (ptr-declr (pointer) (ident ,name)))))
|
||
(list (list name type 4 1)))
|
||
((comp-decl (decl-spec-list (type-spec (fixed-type ,type))) (comp-declr-list (comp-declr (ptr-declr (pointer (pointer)) (ident ,name)))))
|
||
(list (list name type 4 2)))
|
||
((comp-decl (decl-spec-list (type-spec (void))) (comp-declr-list (comp-declr (ptr-declr (pointer (pointer)) (ident ,name)))))
|
||
(list (list name "void" 4 2)))
|
||
((comp-decl (decl-spec-list (type-spec (void))) (comp-declr-list (comp-declr (ptr-declr (pointer) (ident ,name)))))
|
||
(list (list name "void" 4 1)))
|
||
((comp-decl (decl-spec-list (type-spec (void))) (comp-declr-list (comp-declr (ftn-declr (scope (ptr-declr (pointer) (ident ,name))) (param-list . ,param-list)))))
|
||
(list (list name "void" 4 1)))
|
||
((comp-decl (decl-spec-list (type-spec (typename ,type))) (comp-declr-list (comp-declr (ptr-declr (pointer) (ident ,name)))))
|
||
(list (list name type 4 1)))
|
||
|
||
;; FIXME: array: -1,-2-3, name??
|
||
((comp-decl (decl-spec-list (type-spec (typename ,type))) (comp-declr-list (comp-declr (ptr-declr (pointer) (array-of (ident ,name) ,count)))))
|
||
(let ((size 4)
|
||
(count (expr->number info count)))
|
||
(list (list name type (* count size) -2))))
|
||
|
||
((comp-decl (decl-spec-list (type-spec ,type)) (comp-declr-list (comp-declr (array-of (ident ,name) ,count))))
|
||
(let* ((type (if (type? type) type
|
||
(ast->type info type)))
|
||
(size (ast-type->size info type))
|
||
(count (expr->number info count)))
|
||
(list (list name type (* count size) -1))))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (struct-ref (ident ,type)))) (comp-declr-list (comp-declr (ptr-declr (pointer (pointer)) (ident ,name)))))
|
||
(list (list name `("tag" ,type) 4 2)))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (struct-ref (ident ,type)))) (comp-declr-list (comp-declr (ptr-declr (pointer) (ident ,name)))))
|
||
(list (list name `("tag" ,type) 4 1)))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (struct-ref (ident ,type)))) (comp-declr-list (comp-declr (ident ,name))))
|
||
(let ((size (ast-type->size info `("tag" ,type))))
|
||
(list (list name `("tag" ,type) size 0))))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (struct-def (field-list . ,fields)))))
|
||
(list `(struct ,@(append-map (struct-field info) fields))))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (union-ref (ident ,type)))) (comp-declr-list (comp-declr (ident ,name))))
|
||
(let ((size (ast-type->size info `("tag" ,type))))
|
||
(list (list name `("tag" ,type) size 0))))
|
||
|
||
((comp-decl (decl-spec-list (type-spec (union-def (field-list . ,fields)))))
|
||
(list `(union ,@(append-map (struct-field info) fields))))
|
||
|
||
((comp-decl (decl-spec-list ,type) (comp-declr-list . ,decls)) (guard (pair? (cdr decls)))
|
||
(let loop ((decls decls))
|
||
(if (null? decls) '()
|
||
(append ((struct-field info) `(comp-decl (decl-spec-list ,type) (comp-declr-list ,(car decls))))
|
||
(loop (cdr decls))))))
|
||
|
||
(_ (error "struct-field: not supported: " o)))))
|
||
|
||
(define (local-var? o) ;; formals < 0, locals > 0
|
||
(positive? (local:id o)))
|
||
|
||
(define (ptr-declr->pointer o)
|
||
(pmatch o
|
||
((pointer) 1)
|
||
((pointer (pointer)) 2)
|
||
((pointer (pointer (pointer))) 3)
|
||
(_ (error "ptr-declr->pointer not supported: " o))))
|
||
|
||
(define (statements->clauses statements)
|
||
(let loop ((statements statements) (clauses '()))
|
||
(if (null? statements) clauses
|
||
(let ((s (car statements)))
|
||
(pmatch s
|
||
((case ,test (compd-stmt (block-item-list . _)))
|
||
(loop (cdr statements) (append clauses (list s))))
|
||
((case ,test (break))
|
||
(loop (cdr statements) (append clauses (list s))))
|
||
((case ,test) (loop (cdr statements) (append clauses (list s))))
|
||
|
||
((case ,test ,statement)
|
||
(let loop2 ((statement statement) (heads `((case ,test))))
|
||
(define (heads->case heads statement)
|
||
(if (null? heads) statement
|
||
(append (car heads) (list (heads->case (cdr heads) statement)))))
|
||
(pmatch statement
|
||
((case ,t2 ,s2) (loop2 s2 (append heads `((case ,t2)))))
|
||
((default ,s2) (loop2 s2 (append heads `((default)))))
|
||
((compd-stmt (block-item-list . _)) (loop (cdr statements) (append clauses (list (heads->case heads statement)))))
|
||
(_ (let loop3 ((statements (cdr statements)) (c (list statement)))
|
||
(if (null? statements) (loop statements (append clauses (list (heads->case heads `(compd-stmt (block-item-list ,@c))))))
|
||
(let ((s (car statements)))
|
||
(pmatch s
|
||
((case . _) (loop statements (append clauses (list (heads->case heads `(compd-stmt (block-item-list ,@c)))))))
|
||
((default _) (loop statements (append clauses (list (heads->case heads `(compd-stmt (block-item-list ,@c)))))))
|
||
((break) (loop (cdr statements) (append clauses (list (heads->case heads `(compd-stmt (block-item-list ,@(append c (list s)))))))))
|
||
(_ (loop3 (cdr statements) (append c (list s))))))))))))
|
||
((default (compd-stmt (block-item-list _)))
|
||
(loop (cdr statements) (append clauses (list s))))
|
||
((default . ,statement)
|
||
(let loop2 ((statements (cdr statements)) (c statement))
|
||
(if (null? statements) (loop statements (append clauses (list `(default ,@c))))
|
||
(let ((s (car statements)))
|
||
(pmatch s
|
||
((compd-stmt (block-item-list . _)) (loop (cdr statements) (append clauses (list `(default ,s)))))
|
||
((case . _) (loop statements (append clauses (list `(default (compd-stmt (block-item-list ,@c)))))))
|
||
((default _) (loop statements (append clauses (list `(default (compd-stmt (block-item-list ,@c)))))))
|
||
((break) (loop (cdr statements) (append clauses (list `(default (compd-stmt (block-item-list ,@(append c (list s)))))))))
|
||
|
||
(_ (loop2 (cdr statements) (append c (list s)))))))))
|
||
(_ (error "statements->clauses: not supported:" s)))))))
|
||
|
||
(define (ast->info o info)
|
||
(let ((functions (.functions info))
|
||
(globals (.globals info))
|
||
(locals (.locals info))
|
||
(constants (.constants info))
|
||
(types (.types info))
|
||
(text (.text info)))
|
||
(pmatch o
|
||
(((trans-unit . _) . _) (ast-list->info o info))
|
||
((trans-unit . ,_) (ast-list->info _ info))
|
||
((fctn-defn . ,_) (fctn-defn->info _ info))
|
||
|
||
((cpp-stmt (define (name ,name) (repl ,value)))
|
||
info)
|
||
|
||
((cast (type-name (decl-spec-list (type-spec (void)))) _)
|
||
info)
|
||
|
||
((break)
|
||
(let ((label (car (.break info))))
|
||
(append-text info (wrap-as (i386:jump label)))))
|
||
|
||
((continue)
|
||
(let ((label (car (.continue info))))
|
||
(append-text info (wrap-as (i386:jump label)))))
|
||
|
||
;; FIXME: expr-stmt wrapper?
|
||
(trans-unit info)
|
||
((expr-stmt) info)
|
||
|
||
((compd-stmt (block-item-list . ,_)) (ast-list->info _ info))
|
||
|
||
((asm-expr ,gnuc (,null ,arg0 . string))
|
||
(append-text info (wrap-as (asm->m1 arg0))))
|
||
|
||
((expr-stmt (fctn-call (p-expr (ident ,name)) (expr-list . ,expr-list)))
|
||
(if (equal? name "asm") (let ((arg0 (cadr (cadar expr-list))))
|
||
(append-text info (wrap-as (asm->m1 arg0))))
|
||
(let* ((info (append-text info (ast->comment o)))
|
||
(info (expr->accu `(fctn-call (p-expr (ident ,name)) (expr-list . ,expr-list)) info)))
|
||
(append-text info (wrap-as (i386:accu-zero?))))))
|
||
|
||
((if ,test ,then)
|
||
(let* ((info (append-text info (ast->comment `(if ,test (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(else-label (string-append label "else"))
|
||
(info ((test-jump-label->info info break-label) test))
|
||
(info (ast->info then info))
|
||
(info (append-text info (wrap-as (i386:jump break-label))))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals)))
|
||
|
||
((if ,test ,then ,else)
|
||
(let* ((info (append-text info (ast->comment `(if ,test (ellipsis) (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(else-label (string-append label "else"))
|
||
(info ((test-jump-label->info info else-label) test))
|
||
(info (ast->info then info))
|
||
(info (append-text info (wrap-as (i386:jump break-label))))
|
||
(info (append-text info (wrap-as `((#:label ,else-label)))))
|
||
(info (ast->info else info))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals)))
|
||
|
||
;; Hmm?
|
||
((expr-stmt (cond-expr ,test ,then ,else))
|
||
(let* ((info (append-text info (ast->comment `(cond-expr ,test (ellipsis) (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(else-label (string-append label "else"))
|
||
(break-label (string-append label "break"))
|
||
(info ((test-jump-label->info info else-label) test))
|
||
(info (ast->info then info))
|
||
(info (append-text info (wrap-as (i386:jump break-label))))
|
||
(info (append-text info (wrap-as `((#:label ,else-label)))))
|
||
(info (ast->info else info))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
info))
|
||
|
||
((switch ,expr (compd-stmt (block-item-list . ,statements)))
|
||
(let* ((info (append-text info (ast->comment `(switch ,expr (compd-stmt (block-item-list (ellipsis)))))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(clauses (statements->clauses statements))
|
||
(info (expr->accu expr info))
|
||
(info (clone info #:break (cons break-label (.break info))))
|
||
(info (let loop ((clauses clauses) (i 0) (info info))
|
||
(if (null? clauses) info
|
||
(loop (cdr clauses) (1+ i) ((clause->info info i label (null? (cdr clauses))) (car clauses))))))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals
|
||
#:break (cdr (.break info)))))
|
||
|
||
((for ,init ,test ,step ,body)
|
||
(let* ((info (append-text info (ast->comment `(for ,init ,test ,step (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(loop-label (string-append label "loop"))
|
||
(continue-label (string-append label "continue"))
|
||
(initial-skip-label (string-append label "initial_skip"))
|
||
(info (ast->info init info))
|
||
(info (clone info #:break (cons break-label (.break info))))
|
||
(info (clone info #:continue (cons continue-label (.continue info))))
|
||
(info (append-text info (wrap-as (i386:jump initial-skip-label))))
|
||
(info (append-text info (wrap-as `((#:label ,loop-label)))))
|
||
(info (ast->info body info))
|
||
(info (append-text info (wrap-as `((#:label ,continue-label)))))
|
||
(info (expr->accu step info))
|
||
(info (append-text info (wrap-as `((#:label ,initial-skip-label)))))
|
||
(info ((test-jump-label->info info break-label) test))
|
||
(info (append-text info (wrap-as (i386:jump loop-label))))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals
|
||
#:break (cdr (.break info))
|
||
#:continue (cdr (.continue info)))))
|
||
|
||
((while ,test ,body)
|
||
(let* ((info (append-text info (ast->comment `(while ,test (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(loop-label (string-append label "loop"))
|
||
(continue-label (string-append label "continue"))
|
||
(info (append-text info (wrap-as (i386:jump continue-label))))
|
||
(info (clone info #:break (cons break-label (.break info))))
|
||
(info (clone info #:continue (cons continue-label (.continue info))))
|
||
(info (append-text info (wrap-as `((#:label ,loop-label)))))
|
||
(info (ast->info body info))
|
||
(info (append-text info (wrap-as `((#:label ,continue-label)))))
|
||
(info ((test-jump-label->info info break-label) test))
|
||
(info (append-text info (wrap-as (i386:jump loop-label))))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals
|
||
#:break (cdr (.break info))
|
||
#:continue (cdr (.continue info)))))
|
||
|
||
((do-while ,body ,test)
|
||
(let* ((info (append-text info (ast->comment `(do-while ,test (ellipsis)))))
|
||
(here (number->string (length text)))
|
||
(label (string-append "_" (.function info) "_" here "_"))
|
||
(break-label (string-append label "break"))
|
||
(loop-label (string-append label "loop"))
|
||
(continue-label (string-append label "continue"))
|
||
(info (clone info #:break (cons break-label (.break info))))
|
||
(info (clone info #:continue (cons continue-label (.continue info))))
|
||
(info (append-text info (wrap-as `((#:label ,loop-label)))))
|
||
(info (ast->info body info))
|
||
(info (append-text info (wrap-as `((#:label ,continue-label)))))
|
||
(info ((test-jump-label->info info break-label) test))
|
||
(info (append-text info (wrap-as (i386:jump loop-label))))
|
||
(info (append-text info (wrap-as `((#:label ,break-label))))))
|
||
(clone info
|
||
#:locals locals
|
||
#:break (cdr (.break info))
|
||
#:continue (cdr (.continue info)))))
|
||
|
||
((labeled-stmt (ident ,label) ,statement)
|
||
(let ((info (append-text info `(((#:label ,(string-append "_" (.function info) "_label_" label)))))))
|
||
(ast->info statement info)))
|
||
|
||
((goto (ident ,label))
|
||
(append-text info (wrap-as (i386:jump (string-append "_" (.function info) "_label_" label)))))
|
||
|
||
((return ,expr)
|
||
(let ((info (expr->accu expr info)))
|
||
(append-text info (append (wrap-as (i386:ret))))))
|
||
|
||
((decl . ,decl)
|
||
;;FIXME: ridiculous performance hit with mes
|
||
(let ((info (append-text info (ast->comment o))))
|
||
(decl->info info decl)))
|
||
;; ...
|
||
((gt . _) (expr->accu o info))
|
||
((ge . _) (expr->accu o info))
|
||
((ne . _) (expr->accu o info))
|
||
((eq . _) (expr->accu o info))
|
||
((le . _) (expr->accu o info))
|
||
((lt . _) (expr->accu o info))
|
||
((lshift . _) (expr->accu o info))
|
||
((rshift . _) (expr->accu o info))
|
||
|
||
;; EXPR
|
||
((expr-stmt ,expression)
|
||
(let ((info (expr->accu expression info)))
|
||
(append-text info (wrap-as (i386:accu-zero?)))))
|
||
|
||
;; FIXME: why do we get (post-inc ...) here
|
||
;; (array-ref
|
||
(_ (let ((info (expr->accu o info)))
|
||
(append-text info (wrap-as (i386:accu-zero?))))))))
|
||
|
||
(define (ast-list->info o info)
|
||
(fold ast->info info o))
|
||
|
||
(define (global->static function)
|
||
(lambda (o)
|
||
(cons (car o) (set-field (cdr o) (global:function) function))))
|
||
|
||
(define (decl-local->info info)
|
||
(lambda (o)
|
||
(pmatch o
|
||
(((decl-spec-list (stor-spec (static)) (type-spec ,type)) (init-declr-list ,init))
|
||
(let* ((function (.function info))
|
||
(i (clone info #:function #f #:globals '()))
|
||
(i ((decl->info i `(decl (decl-spec-list (type-spec ,type)) (init-declr-list ,init)))))
|
||
(statics (map (global->static function) (.globals i))))
|
||
(clone info #:statics (append statics (.statics info)))))
|
||
(_ #f))))
|
||
|
||
(define (decl-global->info info)
|
||
(lambda (o)
|
||
#f))
|
||
|
||
(define (decl->info info o)
|
||
(pmatch o
|
||
(((decl-spec-list (type-spec ,type)) (init-declr-list . ,inits))
|
||
(let* ((info (type->info info type))
|
||
(type (ast->type info type))
|
||
(pointer 0)) ; FIXME
|
||
(fold (cut init-declr->info type pointer <> <>) info (map cdr inits))))
|
||
(((decl-spec-list (type-spec ,type)))
|
||
(type->info info type))
|
||
(((decl-spec-list (stor-spec (typedef)) (type-spec ,type)) (init-declr-list (init-declr (ident ,name))))
|
||
(let* ((info (type->info info type))
|
||
(type (ast->type info type)))
|
||
(clone info #:types (acons name type (.types info)))))
|
||
(((decl-spec-list (stor-spec (,store)) (type-spec ,type)) (init-declr-list . ,inits))
|
||
(let* ((type (ast->type info type))
|
||
(pointer 0) ; FIXME
|
||
(function (.function info))
|
||
(tmp (clone info #:function #f #:globals '()))
|
||
(tmp (fold (cut init-declr->info type pointer <> <>) tmp (map cdr inits)))
|
||
(statics (map (global->static function) (.globals tmp))))
|
||
(clone info #:statics (append statics (.statics info)))))
|
||
(((@ . _))
|
||
(stderr "decl->info: skip: ~s\n" o)
|
||
info)
|
||
(_ (error "decl->info: not supported:" o))))
|
||
|
||
(define (ast->name o)
|
||
(pmatch o
|
||
((ident ,name) name)
|
||
((ptr-declr ,pointer (ident ,name)) name)
|
||
((array-of ,array . ,_) (ast->name array))
|
||
((ftn-declr (scope (ptr-declr ,pointer (ident ,name)))) name)
|
||
((ptr-declr ,pointer ,decl . ,_) (ast->name decl))
|
||
(_ (error "ast->name not supported: " o))))
|
||
|
||
(define (init-declr->count info o)
|
||
(pmatch o
|
||
((array-of (ident ,name) ,count) (expr->number info count))
|
||
(_ #f)))
|
||
|
||
(define (init->accu o info)
|
||
(pmatch o
|
||
((initzer-list (initzer ,expr)) (expr->accu expr info))
|
||
(((#:string ,string))
|
||
(append-text info (list (i386:label->accu `(#:string ,string)))))
|
||
((,number . _) (guard (number? number))
|
||
(append-text info (wrap-as (i386:value->accu 0))))
|
||
((,c . ,_) (guard (char? c)) info)
|
||
(_ (expr->accu o info))))
|
||
|
||
(define (init-struct-field local field init info)
|
||
(let* ((offset (field-offset info (local:type local) (car field)))
|
||
(pointer (field:pointer field))
|
||
(size (field:size field))
|
||
(empty (clone info #:text '())))
|
||
(clone info #:text
|
||
(append
|
||
(.text info)
|
||
(local->accu local)
|
||
(wrap-as (append (i386:accu->base)))
|
||
(wrap-as (append (i386:push-base)))
|
||
(.text (expr->accu init empty))
|
||
(wrap-as (append (i386:pop-base)))
|
||
(wrap-as (case size
|
||
((1) (i386:byte-accu->base-mem+n offset))
|
||
((2) (i386:word-accu->base-mem+n offset))
|
||
(else (i386:accu->base-mem+n offset))))))))
|
||
|
||
(define (init-array-entry local index init info)
|
||
(let* ((size (or (and (zero? (local:pointer local)) ((compose type:size local:type) local))
|
||
4))
|
||
(offset (* index size))
|
||
(empty (clone info #:text '())))
|
||
(clone info #:text
|
||
(append
|
||
(.text info)
|
||
(local->accu local)
|
||
(wrap-as (append (i386:accu->base)))
|
||
(wrap-as (append (i386:push-base)))
|
||
(.text (expr->accu init empty))
|
||
(wrap-as (append (i386:pop-base)))
|
||
(wrap-as (case size
|
||
((1) (i386:byte-accu->base-mem+n offset))
|
||
((2) (i386:word-accu->base-mem+n offset))
|
||
(else (i386:accu->base-mem+n offset))))))))
|
||
|
||
(define (init-local local o n info)
|
||
(pmatch o
|
||
(#f info)
|
||
((initzer ,init)
|
||
(init-local local init n info))
|
||
((initzer-list ,init)
|
||
(init-local local init n info))
|
||
((initzer-list . ,inits)
|
||
(let* ((type ((compose type:type local:type) local))
|
||
(struct? (or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq type '(struct union)))))
|
||
(cond (struct?
|
||
(let ((fields ((compose struct->fields local:type) local)))
|
||
(fold (cut init-struct-field local <> <> <>) info fields (append inits (map (const '(p-expr (fixed "22"))) (iota (max 0 (- (length fields) (length inits)))))))))
|
||
(else (fold (cut init-local local <> <> <>) info inits (iota (length inits)))))))
|
||
(((initzer (initzer-list . ,inits)))
|
||
(fold (cut init-array-entry local <> <> <>) info (iota (length inits)) inits))
|
||
(() info)
|
||
(_ (let ((info (init->accu o info)))
|
||
(append-text info (accu->local+n-text local n))))))
|
||
|
||
(define (local->info type pointer array name o init info)
|
||
(let* ((locals (.locals info))
|
||
(id (if (or (null? locals) (not (local-var? (cdar locals)))) 1
|
||
(1+ (local:id (cdar locals)))))
|
||
(local (make-local-entry name type pointer array id))
|
||
(struct? (and (or (zero? pointer)
|
||
(= -1 pointer))
|
||
(or (and (pair? type)
|
||
(equal? (car type) "tag"))
|
||
(and (type? type)
|
||
(memq (type:type type) '(struct union))))))
|
||
(size (or (and (zero? pointer) (type? type) (type:size type))
|
||
(and struct? (and=> (ast->type info type) struct:size))
|
||
4))
|
||
(local (if (not array) local
|
||
(make-local-entry name type pointer array (+ (local:id (cdr local)) -1 (quotient (+ (* array size) 3) 4)))))
|
||
(local (if struct? (make-local-entry name type -1 array (+ (local:id (cdr local)) (quotient (+ size 3) 4)))
|
||
local))
|
||
(locals (cons local locals))
|
||
(info (clone info #:locals locals))
|
||
(local (cdr local)))
|
||
(init-local local init 0 info)))
|
||
|
||
(define (global->info type pointer array name o init info)
|
||
(let* ((size (cond ((type? type) (type:size type))
|
||
((not (zero? pointer)) 4)
|
||
(else (error "global->info: no such type:" type))))
|
||
(data (cond ((not init) (string->list (make-string size #\nul)))
|
||
(array (array-init->data (and array (* array (type:size type))) init info))
|
||
(else (let ((data (init->data init info)))
|
||
(append data (string->list (make-string (max 0 (- size (length data))) #\nul)))))))
|
||
(global (make-global-entry name type pointer array data)))
|
||
(clone info #:globals (append (.globals info) (list global)))))
|
||
|
||
(define (array-init-element->data size o info)
|
||
(pmatch o
|
||
((initzer (p-expr (string ,string)))
|
||
`((#:string ,string)))
|
||
((initzer (p-expr (fixed ,fixed)))
|
||
(int->bv32 (expr->number info fixed)))
|
||
(_ (init->data o info))
|
||
;;(_ (error "array-init-element->data: not supported: " o))
|
||
))
|
||
|
||
(define (array-init->data size o info)
|
||
(pmatch o
|
||
(((initzer (initzer-list . ,inits)))
|
||
(map (cut array-init-element->data size <> info) inits))
|
||
|
||
((initzer (p-expr (string ,string)))
|
||
(let ((data (string->list string)))
|
||
(if (not size) data
|
||
(append data (string->list (make-string (max 0 (- size (length data))) #\nul))))))
|
||
|
||
(((initzer (p-expr (string ,string))))
|
||
(let ((data (string->list string)))
|
||
(if (not size) data
|
||
(append data (string->list (make-string (max 0 (- size (length data))) #\nul))))))
|
||
|
||
((initzer (p-expr (fixed ,fixed)))
|
||
(int->bv32 (expr->number info fixed)))
|
||
|
||
(() (string->list (make-string size #\nul)))
|
||
(_ (error "array-init->data: not supported: " o))))
|
||
|
||
(define (init-declr->info type pointer o info)
|
||
(pmatch o
|
||
(((ident ,name))
|
||
(if (.function info) (local->info type pointer #f name o #f info)
|
||
(global->info type pointer #f name o #f info)))
|
||
(((ident ,name) (initzer ,init))
|
||
(let* ((strings (init->strings init info))
|
||
(info (if (null? strings) info
|
||
(clone info #:globals (append (.globals info) strings))))
|
||
(struct? (and (zero? pointer)
|
||
(or (and (pair? type) (equal? (car type) "tag"))
|
||
(memq (type:type type) '(struct union)))))
|
||
(pointer (if struct? (- (1+ (abs pointer))) pointer)))
|
||
(if (.function info) (local->info type pointer #f name o init info)
|
||
(global->info type pointer #f name o init info))))
|
||
(((ftn-declr (ident ,name) . ,_))
|
||
(let ((functions (.functions info)))
|
||
(if (member name functions) info
|
||
(let* ((type (ftn-declr:get-type info `(ftn-declr (ident ,name) ,@_)))
|
||
(function (make-function name type #f)))
|
||
(clone info #:functions (cons (cons name function) functions))))))
|
||
(((ftn-declr (scope (ptr-declr ,p (ident ,name))) ,param-list) ,init)
|
||
|
||
(let ((pointer (+ pointer (pointer->ptr p))))
|
||
(if (.function info) (local->info type pointer #f name o init info)
|
||
(global->info type pointer #f name o init info))))
|
||
(((ptr-declr ,p . ,_) . ,init)
|
||
(let ((pointer (+ pointer (pointer->ptr p))))
|
||
(init-declr->info type pointer (append _ init) info)))
|
||
(((array-of (ident ,name) ,array) . ,init)
|
||
(let* ((strings (init->strings init info))
|
||
(info (if (null? strings) info
|
||
(clone info #:globals (append (.globals info) strings))))
|
||
(array (expr->number info array))
|
||
(pointer (- (1+ pointer))))
|
||
(if (.function info) (local->info type pointer array name o init info)
|
||
(global->info type pointer array name o init info))))
|
||
(((array-of (ident ,name)) . ,init)
|
||
(let* ((strings (init->strings init info))
|
||
(info (if (null? strings) info
|
||
(clone info #:globals (append (.globals info) strings))))
|
||
(pointer (- (1+ pointer))))
|
||
(if (.function info) (local->info type pointer (length (cadar init)) name o init info)
|
||
(global->info type pointer #f name o init info))))
|
||
|
||
;; FIXME: recursion
|
||
(((array-of (array-of (ident ,name) ,array) ,array1) . ,init)
|
||
(let* ((strings (init->strings init info))
|
||
(info (if (null? strings) info
|
||
(clone info #:globals (append (.globals info) strings))))
|
||
(array (expr->number info array))
|
||
(pointer (- (+ 2 pointer))))
|
||
(if (.function info) (local->info type pointer array name o init info)
|
||
(global->info type pointer array name o init info))))
|
||
|
||
(_ (error "init-declr->info: not supported: " o))))
|
||
|
||
(define (enum-def-list->constants constants fields)
|
||
(let loop ((fields fields) (i 0) (constants constants))
|
||
(if (pair? fields)
|
||
(let ((field (car fields)))
|
||
(mescc:trace (cadr (cadr field)) " <e>")))
|
||
(if (null? fields) constants
|
||
(let* ((field (car fields))
|
||
(name (pmatch field
|
||
((enum-defn (ident ,name) . _) name)))
|
||
(i (pmatch field
|
||
((enum-defn ,name) i)
|
||
((enum-defn ,name ,exp) (expr->number #f exp))
|
||
(_ (error "not supported enum field=~s\n" field)))))
|
||
(loop (cdr fields)
|
||
(1+ i)
|
||
(append constants (list (ident->constant name i))))))))
|
||
|
||
(define (init->data o info)
|
||
(pmatch o
|
||
((p-expr ,expr) (init->data expr info))
|
||
((fixed ,fixed) (int->bv32 (expr->number info o)))
|
||
((char ,char) (int->bv32 (char->integer (string-ref char 0))))
|
||
((string ,string) `((#:string ,string)))
|
||
((string . ,strings) `((#:string ,(string-join strings ""))))
|
||
((ident ,name) (let ((var (ident->variable info name)))
|
||
`((#:address ,var))))
|
||
((initzer-list . ,initzers) (append-map (cut init->data <> info) initzers))
|
||
(((initzer (initzer-list . ,inits)))
|
||
(init->data `(initzer-list . ,inits) info))
|
||
((ref-to (p-expr (ident ,name)))
|
||
(let ((var (ident->variable info name)))
|
||
`((#:address ,var))))
|
||
((ref-to (i-sel (ident ,field) (cast (type-name (decl-spec-list ,struct) (abs-declr (pointer))) (p-expr (fixed ,base)))))
|
||
(let* ((type (ast->type info struct))
|
||
(offset (field-offset info type field))
|
||
(base (cstring->number base)))
|
||
(int->bv32 (+ base offset))))
|
||
((,char . _) (guard (char? char)) o)
|
||
((,number . _) (guard (number? number))
|
||
(append (map int->bv32 o)))
|
||
((initzer ,init) (init->data init info))
|
||
(_ (error "init->data: not supported: " o))))
|
||
|
||
(define (init->strings o info)
|
||
(let ((globals (.globals info)))
|
||
(pmatch o
|
||
((p-expr (string ,string))
|
||
(let ((g `(#:string ,string)))
|
||
(if (assoc g globals) '()
|
||
(list (string->global-entry string)))))
|
||
((p-expr (string . ,strings))
|
||
(let* ((string (string-join strings ""))
|
||
(g `(#:string ,string)))
|
||
(if (assoc g globals) '()
|
||
(list (string->global-entry string)))))
|
||
(((initzer (initzer-list . ,init)))
|
||
(append-map (cut init->strings <> info) init))
|
||
((initzer ,init)
|
||
(init->strings init info))
|
||
((initzer-list . ,init)
|
||
(append-map (cut init->strings <> info) init))
|
||
(_ '()))))
|
||
|
||
(define (type->info info o)
|
||
(pmatch o
|
||
((enum-def (ident ,name) (enum-def-list . ,fields))
|
||
(mescc:trace name " <t>")
|
||
(let* ((type-entry (enum->type-entry name fields))
|
||
(constants (enum-def-list->constants (.constants info) fields)))
|
||
(clone info
|
||
#:types (cons type-entry (.types info))
|
||
#:constants (append constants (.constants info)))))
|
||
((struct-def (ident ,name) (field-list . ,fields))
|
||
(mescc:trace name " <t>")
|
||
(let ((type-entry (struct->type-entry name (append-map (struct-field info) fields))))
|
||
(clone info #:types (cons type-entry (.types info)))))
|
||
((struct-ref . _)
|
||
info)
|
||
((union-def (ident ,name) (field-list . ,fields))
|
||
(mescc:trace name " <t>")
|
||
(let ((type-entry (union->type-entry name (append-map (struct-field info) fields))))
|
||
(clone info #:types (cons type-entry (.types info)))))
|
||
((union-ref . _)
|
||
info)
|
||
(_
|
||
(stderr "type->info: not supported: ~s\n" o)
|
||
info)))
|
||
|
||
;;; fctn-defn
|
||
(define (param-decl:get-name o)
|
||
(pmatch o
|
||
((ellipsis) #f)
|
||
((param-decl (decl-spec-list (type-spec (void)))) #f)
|
||
((param-decl _ (param-declr ,ast)) (ast->name ast))
|
||
(_ (error "param-decl:get-name not supported:" o))))
|
||
|
||
(define (fctn-defn:get-name o)
|
||
(pmatch o
|
||
((_ (ftn-declr (ident ,name) _) _) name)
|
||
((_ (ptr-declr (pointer . _) (ftn-declr (ident ,name) _)) _) name)
|
||
(_ (error "fctn-defn:get-name not supported:" o))))
|
||
|
||
(define (param-decl:get-type o info)
|
||
(pmatch o
|
||
((ellipsis) #f)
|
||
((param-decl (decl-spec-list (type-spec (void)))) #f)
|
||
((param-decl (decl-spec-list (type-spec ,type)) _) (ast->type info type))
|
||
((param-decl ,type _) (ast->type info type))
|
||
(_ (error "param-decl:get-type not supported:" o))))
|
||
|
||
(define (fctn-defn:get-formals o)
|
||
(pmatch o
|
||
((_ (ftn-declr _ ,formals) _) formals)
|
||
((_ (ptr-declr (pointer . _) (ftn-declr _ ,formals)) _) formals)
|
||
(_ (error "fctn-defn->formals: not supported:" o))))
|
||
|
||
(define (formal->text n)
|
||
(lambda (o i)
|
||
;;(i386:formal i n)
|
||
'()
|
||
))
|
||
|
||
(define (param-list->text o)
|
||
(pmatch o
|
||
((param-list . ,formals)
|
||
(let ((n (length formals)))
|
||
(wrap-as (append (i386:function-preamble)
|
||
(append-map (formal->text n) formals (iota n))
|
||
(i386:function-locals)))))
|
||
(_ (error "param-list->text: not supported: " o))))
|
||
|
||
(define (param-decl:get-ptr o)
|
||
(pmatch o
|
||
((param-decl (decl-spec-list . ,decl) (param-declr (ident ,name) (array-of _)))
|
||
1)
|
||
((param-decl (decl-spec-list . ,decl) (param-declr (ident ,name)))
|
||
0)
|
||
((param-decl _ (param-declr (ptr-declr ,pointer (array-of _))))
|
||
(1+ (pointer->ptr pointer)))
|
||
((param-decl _ (param-declr (ptr-declr ,pointer . _)))
|
||
(pointer->ptr pointer))
|
||
((param-decl (decl-spec-list (type-spec (void))))
|
||
0)
|
||
(_ (error "param-decl:get-ptr: not supported: " o))))
|
||
|
||
(define (param-list->locals o info)
|
||
(pmatch o
|
||
((param-list . ,formals)
|
||
(let ((n (length formals)))
|
||
(map make-local-entry
|
||
(map param-decl:get-name formals)
|
||
(map (cut param-decl:get-type <> info) formals)
|
||
(map param-decl:get-ptr formals)
|
||
(map (const #f) (iota n))
|
||
(iota n -2 -1))))
|
||
(_ (error "param-list->locals: not supported:" o))))
|
||
|
||
(define (fctn-defn:get-type info o)
|
||
(pmatch o
|
||
(((decl-spec-list (type-spec ,type)) (ptr-declr ,pointer . _) ,statement)
|
||
(let ((type (ast->type info type))
|
||
(pointer (ptr-declr->pointer pointer)))
|
||
(make-type (type:type type)
|
||
(type:size type)
|
||
(+ (type:pointer type) pointer)
|
||
(type:description type))))
|
||
(((decl-spec-list (type-spec ,type)) . ,rest)
|
||
(ast->type info type))
|
||
(((decl-spec-list (stor-spec ,store) (type-spec ,type)) (ftn-declr (ident _) _) _)
|
||
(ast->type info type))
|
||
(_ (error "fctn-defn:get-type: not supported:" o))))
|
||
|
||
(define (ftn-declr:get-type info o)
|
||
(pmatch o
|
||
((ftn-declr (ident _) . _) #f)
|
||
(_ (error "fctn-decrl:get-type: not supported:" o))))
|
||
|
||
(define (fctn-defn:get-statement o)
|
||
(pmatch o
|
||
((_ (ftn-declr (ident _) _) ,statement) statement)
|
||
((_ (ptr-declr (pointer . _) (ftn-declr (ident _) . _)) ,statement) statement)
|
||
(_ (error "fctn-defn:get-statement: not supported: " o))))
|
||
|
||
(define (fctn-defn->info o info)
|
||
(define (assert-return text)
|
||
(let ((return (wrap-as (i386:ret))))
|
||
(if (equal? (list-tail text (- (length text) (length return))) return) text
|
||
(append text return))))
|
||
(let ((name (fctn-defn:get-name o)))
|
||
(mescc:trace name)
|
||
(let* ((type (fctn-defn:get-type info o))
|
||
(formals (fctn-defn:get-formals o))
|
||
(text (param-list->text formals))
|
||
(locals (param-list->locals formals info))
|
||
(statement (fctn-defn:get-statement o))
|
||
(info (clone info #:locals locals #:function name #:text text))
|
||
(info (ast->info statement info))
|
||
(locals (.locals info))
|
||
(local (and (pair? locals) (car locals)))
|
||
(count (and=> local (compose local:id cdr)))
|
||
(stack (and count (* count 4))))
|
||
(if (and stack (getenv "MESC_DEBUG")) (stderr " stack: ~a\n" stack))
|
||
(clone info
|
||
#:function #f
|
||
#:globals (append (.statics info) (.globals info))
|
||
#:statics '()
|
||
#:functions (append (.functions info) (list (cons name (make-function name type (assert-return (.text info))))))))))
|
||
|
||
;; exports
|
||
|
||
(define* (c99-ast->info o)
|
||
(ast->info o (make <info> #:types i386:type-alist)))
|
||
|
||
(define* (c99-input->ast #:key (defines '()) (includes '()))
|
||
(stderr "parsing: input\n")
|
||
((compose ast-strip-const ast-strip-comment) (c99-input->full-ast #:defines defines #:includes includes)))
|
||
|
||
(define* (c99-input->info #:key (defines '()) (includes '()))
|
||
(lambda ()
|
||
(let* ((info (make <info> #:types i386:type-alist))
|
||
(ast (c99-input->ast #:defines defines #:includes includes))
|
||
(foo (stderr "compiling: input\n"))
|
||
(info (ast->info ast info))
|
||
(info (clone info #:text '() #:locals '())))
|
||
info)))
|
||
|
||
(define* (info->object o)
|
||
(stderr "compiling: object\n")
|
||
`((functions . ,(filter (compose function:text cdr) (.functions o)))
|
||
(globals . ,(.globals o))))
|
||
|
||
(define* (c99-input->elf #:key (defines '()) (includes '()))
|
||
((compose object->elf info->object (c99-input->info #:defines defines #:includes includes))))
|
||
|
||
(define* (c99-input->object #:key (defines '()) (includes '()))
|
||
((compose object->M1 info->object (c99-input->info #:defines defines #:includes includes))))
|