Common Lisp宏生成宏:实现带参数求值的宏生成器问题
解决Lisp宏生成宏时的反引号与逗号问题
我来帮你搞定这个宏生成宏的小麻烦!你想要用(make-type "int32" 32)自动生成make-int32t宏,核心问题是如何在生成的宏代码里正确保留反引号(`)和逗号(,)——这些符号在Lisp宏里是特殊语法,直接写会被当前宏当成自身的展开逻辑,而不是输出到目标宏中。
完整解决方案代码
(defmacro make-type (type-name bit-length) (let* ((type-t-symbol (intern (string-upcase (concatenate 'string type-name "t")))) (make-macro-name (intern (string-upcase (concatenate 'string "MAKE-" type-name "t"))))) `(defmacro ,make-macro-name (name) `(quote (:type ',',type-t-symbol :bit-length ,',bit-length :name ,name)))))
代码解释
咱们一步步拆解关键部分:
- 构造目标符号:
type-t-symbol:把输入的type-name(比如"int32")拼接成"int32t",转成大写符号INT32T,对应目标宏里的:type 'int32t。make-macro-name:生成目标宏的名称,比如把"int32"转成MAKE-INT32T。
- 双重反引号的嵌套:
- 外层的
是make-type宏自身的展开模板,用来生成defmacro`代码。 - 内层的
是目标宏make-int32t`的展开模板,这就是你要保留的反引号。
- 外层的
- 正确插值符号:
',',type-t-symbol:这里的第一个'是目标宏里的引号,,',是双重插值——先在make-type展开时插入type-t-symbol的值,再让目标宏里的'把它变成引用,最终生成'int32t。,',bit-length:同理,在make-type展开时插入bit-length的数值(比如32),目标宏里直接用这个常量。,name:这是目标宏的参数插值,在内层反引号里,单个逗号就表示引用目标宏的name参数。
测试验证
- 先定义上面的
make-type宏。 - 调用
(make-type "int32" 32),这会自动生成make-int32t宏,展开后就是你想要的:(defmacro make-int32t (name) `(quote (:type 'int32t :bit-length 32 :name ,name))) - 再调用
(make-int32t "myvar"),求值后会输出:(:TYPE 'INT32T :BIT-LENGTH 32 :NAME "myvar")
完全符合你的预期!
内容的提问来源于stack exchange,提问作者Makketronix
相关产品推荐
相关产品推荐

