#lang scheme/base (provide make-constant constants) (require "../tools.ss" "../scat.ss" "../target.ss" "macro-syntax.ss" "macro-eval.ss" ) ;; Constants. ;; A constant is a macro that compiles a single literal value. ;; It's convenient to have constant names bound also in the scheme ;; namespace for asm pattern specification. There it represents a ;; value. ;; However, as the PIC18 case has illustrated, it is best to keep ;; constants late bound: they are part of the compiler specialization ;; which fills in some macro hooks (redefines the stubs that throw ;; errors). ;; For the scheme names to work, they need to refer to a delayed ;; target-value that refers to the macro to obtain its value. ;; Cyclic implementation: ;; - the macro compiles a literal, with value = the tval ;; - the tval extracts a constant from the macro ;; The cycle is broken in 2 ways: ;; - macro is redefined with a real constant ;; - the tval gets evaluated at assembly time, and produces an error ;; The macro compiles a literal, this literal is the target-value ;; that refers to the macro struct. This allows the macro to behave ;; as a constant before it is actually defined with a value. ;; The evaluator checks if the macro evaluates to itself, end only ;; then raises an error. As long as the macro is redefined before ;; assembly time, things are ok. (define (constant->value macro) (macro->data macro 'qw)) (define (make-constant name) (define macro (macro: ',tval)) (define tval (target-value-delay (tval-thunk) name)) (define tval-thunk (lambda () (let ((value (constant->value macro))) (if (eq? value tval) (error 'undefined-parameter "~a" name) value)))) macro) (define-sr (constants name ...) (begin (define-ns (macro) name (make-constant 'name)) ... (define name (constant->value (ns (macro) name))) ...))