Syntax 使用Racket&x27在编译时注入语法;语法参数?
我试图使用语法参数,以便在需要注入语法的地方注入新语法。然后,此操作的结果将用于其他语法中。 然而,它并没有像我期望的那样工作。下面是一个简单的工作示例:Syntax 使用Racket&x27在编译时注入语法;语法参数?,syntax,macros,racket,Syntax,Macros,Racket,我试图使用语法参数,以便在需要注入语法的地方注入新语法。然后,此操作的结果将用于其他语法中。 然而,它并没有像我期望的那样工作。下面是一个简单的工作示例: #lang racket (require (for-syntax racket/contract)) (require racket/stxparam) ;; A list for holding the instructions (define instructions-db '()) ;===================
#lang racket
(require (for-syntax racket/contract))
(require racket/stxparam)
;; A list for holding the instructions
(define instructions-db
'())
;===================================
; MACRO FOR DEFINING AN INSTRUCTION
;===================================
(provide define-instruction)
(define-syntax (define-instruction stx)
(syntax-case stx ()
[(_ id (attrs ...))
;; Insert instruction into database
#'(set! instructions-db (append instructions-db '(id (attrs ...))))]))
;=============================================================
; MACRO TO MIMIC 'FOR' BUT TO BE USED WITH DEFINE-INSTRUCTION
;=============================================================
(begin-for-syntax
; Gets the head of each list within the given list of syntax lists. If any of
; the lists are empty, an empty list is returned.
(define/contract (stx-heads ls)
((listof (syntax/c list?)) . -> . (listof (syntax/c any/c)))
(let loop ([ls ls]
[hs '()])
(if (null? ls)
hs
(let ([l (syntax-e (car ls))])
(if (null? l)
'()
(loop (cdr ls) (append hs (list (car l)))))))))
; Gets the tail of each list within the given list of syntax lists. If any of
; the lists are empty, an empty list is returned.
(define/contract (stx-tails ls)
((listof (syntax/c list?)) . -> . (listof (syntax/c list?)))
(let loop ([ls ls]
[ts '()])
(if (null? ls)
ts
(let* ([stx-l (car ls)]
[l (syntax-e stx-l)])
(if (null? l)
'()
(loop (cdr ls) (append ts (list
(datum->syntax stx-l
(cdr l)
stx-l
stx-l)))))))))
(define (define-instruction-stx? stx)
(if (syntax? stx)
(let ([e (syntax-e stx)])
(and (pair? e)
(syntax? (car e))
(equal? (syntax-e (car e)) 'define-instruction)))
#f))
;; Given a syntax object, an identifier, and a replacement value, construct a
;; new syntax object where any occurrence of the identifier is substituted for
;; the value.
(define (stx-id-substitute id replacement stx)
(let loop ([e stx])
(cond [(and (identifier? e)
(bound-identifier=? e id))
replacement]
[(syntax? e)
(datum->syntax e (loop (syntax-e e)) e e)]
[(pair? e)
(cons (loop (car e)) (loop (cdr e)))]
[else e])))
;; Given a 'define-instruction' syntax object, extends its ID with the given
;; string. If any other object is given, it is left intact and returned.
(define (extend-id-of-define-instruction-stx suffix stx)
(if (define-instruction-stx? stx)
(let* ([e (syntax-e stx)]
[stx-construct (car e)]
[stx-id (cadr e)]
[new-stx-id
(datum->syntax stx-id
(string->symbol
(format "~a~a"
(symbol->string (syntax-e stx-id))
suffix))
stx-id
stx-id)]
[stx-attrs (caddr e)])
(datum->syntax stx
`(,stx-construct ,new-stx-id ,stx-attrs)
stx
stx))
stx))
;; Given a list of variable-value pairs and define-instruction body, construct
;; a new body where all varible occurrences have been replaced with its
;; values.
(define (instr-for-body-args-sub var-val-pairs stx-body)
(let loop ([var-val-pairs var-val-pairs]
[stx-body stx-body])
(if (null? var-val-pairs)
stx-body
(let* ([var-val-p (car var-val-pairs)]
[var (car var-val-p)]
[val (cdr var-val-p)]
[new-stx-body (stx-id-substitute var val stx-body)]
[rest-var-val-pairs (cdr var-val-pairs)])
(loop rest-var-val-pairs new-stx-body)))))
;; Given a list of variable-value pairs and define-instruction body, construct
;; a new body where all varible occurrences have been replaced with its
;; values. Also, an index is appended to the identifier of the new
;; define-instruction body.
(define (instr-for-body-args var-val-pairs instr-index stx-body0)
(let* ([stx-body1 (instr-for-body-args-sub var-val-pairs stx-body0)]
[stx-body2 (let loop ([e stx-body1])
(cond [(define-instruction-stx? e)
(extend-id-of-define-instruction-stx
(format ":~a" instr-index)
e)]
[(syntax? e)
(datum->syntax e (loop (syntax-e e)) e e)]
[(pair? e)
(cons (loop (car e)) (loop (cdr e)))]
[else e]))])
stx-body2))
;; Given a list of iteration arguments and an define-instruction body,
;; construct a list of define-instruction bodies.
(define (instr-for-body stx-args stx-body)
(let ([stx-vars (stx-heads (syntax-e stx-args))])
(let loop ([stx-val-lists (stx-heads (stx-tails (syntax-e stx-args)))]
[instr-index 0])
(if (null? stx-val-lists)
'() ;; No more values to iterate over
(let ([stx-vals (stx-heads stx-val-lists)])
(if (null? stx-vals)
'() ;; At least one arg list has no more values
(let ([stx-arg-val-pairs (map cons stx-vars stx-vals)])
(cons (instr-for-body-args stx-arg-val-pairs
instr-index
stx-body)
(loop (stx-tails stx-val-lists)
(+ instr-index 1)))))))))))
(provide instr-for)
(define-syntax (instr-for stx)
(syntax-case stx ()
[(_ args body ...)
(with-syntax ([(replaced-body ...)
(foldl
(lambda (stx-body replaced-stx-bodies)
(append (instr-for-body #'args stx-body)
replaced-stx-bodies))
'()
(syntax-e #'(body ...)))])
#'(begin replaced-body ...))]))
;===============================================
; MACROS TO SIMPLIFY DEFINITION OF INSTRUCTIONS
;===============================================
(define-syntax-parameter mem-op-addr
(lambda (stx)
(raise-syntax-error
(syntax-e stx)
"can only be used inside define-modrm-mem-op-instruction")))
(provide define-complex-addr-mode-instructions)
(define-syntax (define-complex-addr-mode-instructions stx)
(syntax-case stx ()
[(_ id (attrs ...))
#'(begin
(instr-for ([addr (#'reg1
#'[inttoptr 32 offset 32]
#'[inttoptr 32 (add 32 rbase rindex) 32]
#'[inttoptr 32 (add 32
#' rbase
#' (add 32 rindex offset))
#' 32])])
(let ([_addr (syntax->datum addr)])
(syntax-parameterize ([mem-op-addr
(make-rename-transformer #'_addr)])
(define-instruction id (attrs ...))))))]))
此代码用于定义指令并将其放入数据库中。该数据库指令的语义随后用于生成代码
现在我要声明一条指令。具体做法如下:
(define-instruction ADD:0
((semantics (add 8 reg0 reg1))))
(displayln instructions-db)
产生:
(ADD:0 ((semantics (add 8 reg0 reg1))
([ADD:0 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:1 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:2 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:3 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:0 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:1 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:2 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:3 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))])
要处理不同的位宽度,我们可以执行以下操作之一:
(define-instruction ADD:0
((semantics (add 8 reg0 reg1))))
(define-instruction ADD:1
((semantics (add 16 reg0 reg1))))
(define-instruction ADD:2
((semantics (add 32 reg0 reg1))))
(displayln instructions-db)
或者只需将我的指令用于
宏:
(instr-for ([i (8 16 32)])
(define-instruction ADD
((semantics (add i reg0 reg1)))))
(displayln instructions-db)
得出与上述相同的结果:
([ADD:0 ((semantics (add 8 reg0 reg1)))]
[ADD:1 ((semantics (add 16 reg0 reg1)))]
[ADD:2 ((semantics (add 32 reg0 reg1)))])
现在,一些指令具有复杂的寻址模式,这些模式出现在多个指令之间。例如:
; some ADD instructions
(define-instruction ADD:0
((semantics
(add 32 reg0 (load-mem 32 reg1)))))
(define-instruction ADD:1
((semantics
(add 32 reg0 (load-mem 32 [inttoptr 32 offset 32])))))
(define-instruction ADD:2
((semantics
(add 32 reg0 (load-mem 32 [inttoptr 32 (add 32 rbase rindex) 32])))))
(define-instruction ADD:3
((semantics
(add 32 reg0 (load-mem 32 [inttoptr 32 (add 32
rbase
(add 32 rindex offset))
32])))))
; some SUB instructions, with the same addressing modes
(define-instruction SUB:0
((semantics
(sub 32 reg0 (load-mem 32 reg1)))))
(define-instruction SUB:1
((semantics
(sub 32 reg0 (load-mem 32 [inttoptr 32 offset 32])))))
(define-instruction SUB:2
((semantics
(sub 32 reg0 (load-mem 32 [inttoptr 32 (add 32 rbase rindex) 32])))))
(define-instruction SUB:3
((semantics
(sub 32 reg0 (load-mem 32 [inttoptr 32 (add 32
rbase
(add 32 rindex offset))
32])))))
为了避免复制粘贴,我定义了一个新的宏define complex addr mode instructions
,允许我们声明与上面相同的指令,只需使用:
(define-complex-addr-mode-instructions ADD
((semantics (add 32 reg0 (load-mem 32 mem-op-addr)))))
(define-complex-addr-mode-instructions SUB
((semantics (add 32 reg0 (load-mem 32 mem-op-addr)))))
(displayln instructions-db)
然而,这会产生:
(ADD:0 ((semantics (add 8 reg0 reg1))
([ADD:0 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:1 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:2 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[ADD:3 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:0 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:1 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:2 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))]
[SUB:3 ((semantics (add 32 reg0 (load-mem 32 mem-op-addr))))])
在阅读Greg Hendershott的著作时,我试图使用语法参数实现
定义复杂的addr模式指令
,因为使用语法->数据
显然是不好的。我是否误解了语法参数的工作原理,或者在这种情况下我需要使用datum->syntax
?我注意到,如果我将instr for
中的绑定标识符=?
替换为免费标识符=?
,它会起作用,但我怀疑这不是正确的方法。在我看来,你的问题的答案实际上与,尽管复杂性增加:define指令
在其扩展中仍将其输入置于quote
下,并且在quote
下不会进行扩展。我会重新考虑在那里,quote
是否真的是正确的选择。看起来你真的应该对这些输入进行更多的处理,并且你可以通过一种方式向宏扩展器发出信号(直接或间接)表明扩展可能会再次出现在这些点上。是的,我昨天在下班回家的路上也意识到了这一点,在发布了这个问题之后。说实话,我没有为define指令
编写代码,所以我没有完全理解它是如何处理其参数的,但它似乎将所有内容都封装在quote
中,然后逐个元素对其进行解析。由于参数没有被执行,因此没有被Racket解析为语法,所以现在很明显syntax parameterize
在这种情况下不起作用。因此,对我来说,最简单的解决办法就是按照instr for
的思路做一些事情。谢谢你的帮助@AlexisKing能否请您将您的评论转化为答案,以便我将此问题标记为已回答?我不同意您想要的解决方案是类似于instr for
的方法,它遍历其子表单并对其进行重击。这样做几乎总是错误的。让宏扩展器为您工作,而不是与之斗争。在可能的情况下,允许展开为允许进一步展开的表达式。考虑使用代码>局部扩展< /代码>,如果你真的需要强制扩展递归的原因。屈服于宏扩展器,让它完成它的工作。这是否意味着宏扩展器可以遍历引用的语句?如果是,怎么做?显然,上述方法不是实现这一目标的方法。