代码之家  ›  专栏  ›  技术社区  ›  Denes Cselovszki

在宏定义中使用读取器宏字符

  •  0
  • Denes Cselovszki  · 技术社区  · 2 年前

    为了使访问COM对象中的属性看起来更像s-表达式,我为LispWorks的COM包编写了以下代码作为精简包装器的一部分:

    ;;; Create dispatch function for '#<' and '#>'.
    (eval-when (:load-toplevel :compile-toplevel :execute)
      (defun com-dispatch-function (invoke-function)
        (lambda (stream sub-char infix)
          (declare (ignore sub-char infix))
          (destructuring-bind (thing object &rest args)
              (read stream)
            `(,invoke-function ,object (symbol-name ',thing) ,@args)))))
    
    
    ;;; COM 'get property' read macro.
    (set-dispatch-macro-character
     #\# #\<
     (com-dispatch-function 'com::invoke-dispatch-get-property))
    

    所以现在,而不是

    (invoke-dispatch-get-property object "Property" argument)
    

    我会写字

    #<(property object argument)
    

    然而,当我尝试在宏定义中使用这种语法时,如下所示:

    (defmacro something ((object) &body body)
      (let ((excel (gensym)))
        `(cclet* ((,excel #<(application ,object)))
          ,@))) 
    

    编译器会抱怨在后引号外使用逗号。

    我想错误的原因是阅读器宏函数应该以某种方式与反引号语法相配合,但我不知道如何做到这一点。有什么建议吗?

    谢谢

    0 回复  |  直到 2 年前
        1
  •  0
  •   ignis volens    2 年前

    在一条评论中表示,这不可能以便携方式实现,这就是为什么它实际上必须是可能的:如果不是这样,就不可能为其编写自述 #\( 而不依赖于特定于特殊实现的魔术。

    然而,在实现这样的readmacross时,需要做的一件事是告诉读者您正在递归地阅读。这允许诸如 # n = / # n # 工作,但它看起来也可能让读者知道,它可能会看到LispWorks的逗号,而没有周围的后引号。虽然我不能代表LW实现者发言,但这可能是作为一种健全性检查。

    要做到这一点,你必须确保打电话 read as(read s t nil t)`(或者无论如何都要确保第四个参数为真)。

    这意味着你的功能应该是

    (destructuring-bind (thing object &rest args) (read stream t nil t)
      `(,invoke-function ,object (symbol-name ',thing) ,@args))
    
    推荐文章