Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros 在公共lisp包中导出回指宏_Macros_Package_Common Lisp_Symbols - Fatal编程技术网

Macros 在公共lisp包中导出回指宏

Macros 在公共lisp包中导出回指宏,macros,package,common-lisp,symbols,Macros,Package,Common Lisp,Symbols,我在导出宏时遇到问题,当宏在同一个包中声明时,它可以工作,但在导入时却不能工作。我在Windows上使用Emacs、SLIME和Clozure 包文件 (defpackage :tokenizer (:use :common-lisp) (:export :tokenize-with-symbols :current-token :advanze-token :peek-token :with-token-and-peek

我在导出宏时遇到问题,当宏在同一个包中声明时,它可以工作,但在导入时却不能工作。我在Windows上使用Emacs、SLIME和Clozure

包文件

(defpackage :tokenizer
  (:use :common-lisp)
  (:export :tokenize-with-symbols 
       :current-token 
       :advanze-token 
       :peek-token
       :with-token-and-peek
       :with-token))

(defpackage :csharp-parser
  (:use :common-lisp :tokenizer)
  (:import-from :tokenizer :with-token-and-peek :with-token))
标记器文件

(in-package :tokenizer)

(defmacro with-token-and-peek (&body body) 
  `(let ((token (current-token tokenizer))
     (peek (peek-token tokenizer)))
     ,@body))
解析器文件

(in-package :csharp-parser)

(defun expression (tokenizer node-stack)
  (with-token-and-peek
   (cond ((is-number? token) (make-value-node "number" token))
         ((is-bool? token) (make-value-node "bool" token))
         ((is-identifier? token peek) (make-identifier-node tokenizer node-stack))
         (t (make-ast-node :identifier "bla")))))
给出编译时的错误:

csharpParser.lisp:265:3:
  warning: Undeclared free variable TOKENIZER::TOKENIZER (2 references)
           style-warning: Unused lexical variable TOKENIZER::PEEK
           style-warning: Unused lexical variable TOKENIZER::TOKEN
csharpParser.lisp:266:14:
  warning: Undeclared free variable TOKEN
etc etc etc
如果我在包中尝试宏扩展:csharp parser

(macroexpand-1 '(with-token-and-peek tok))

(LET ((TOKENIZER::TOKEN (CURRENT-TOKEN TOKENIZER::TOKENIZER))
      (TOKENIZER::PEEK (PEEK-TOKEN TOKENIZER::TOKENIZER)))
  TOK)
T
现在就像我说的,如果我把宏移到解析器文件中,它会编译并工作得很好。但是,当我试图将其重构为标记器文件并通过包系统导出它时,会出现这些错误,因为它似乎将符号内部化为调用包。我通过冒号尝试了多种方法,但都没有成功


如果有人能在这方面帮助我,我将非常感激

宏中的符号
TOKEN
PEEK
驻留在
TOKENIZER
包中,而
COND
中的代码使用驻留在
CSHARP-PARSER
包中的符号。有两种方法可以解决这个问题

  • 让扩展使用代码所在包中的符号。这可以通过在展开宏的同时在当前包中手动插入符号来实现。例如:

    (defpackage #:foo
      (:use #:cl)
      (:export #:aif))
    
    (in-package #:foo)
    
    (defmacro aif (test then &optional else)
      (let ((it (intern (symbol-name 'it))))
        `(let ((,it ,test))
           (if ,it ,then ,else))))
    
    (in-package :cl-user)
    (use-package :foo)
    (aif (+ 3 3) it) ;=> 6
    
    使用
    (intern(symbol name'it))
    而不仅仅是
    (intern“it”)
    是一种避免lisp无法将符号转换为大写时出现问题的方法

  • 让代码使用标记器包中的符号。这可以通过导出符号来完成

    (defpackage #:foo
      (:use #:cl)
      (:export #:aif
               #:it))
    
    (in-package #:foo)
    
    (defmacro aif (test then &optional else)
      `(let ((it ,test))
         (if it ,then ,else)))
    
    (in-package :cl-user)
    (use-package :foo)
    (aif (+ 3 3) it) ;=> 6
    
    缺点是宏的用户必须导入符号,因此他们不能为宏使用包限定名

    (defpackage #:foo
      (:use #:cl)
      (:export #:aif
               #:it))
    
    (in-package #:foo)
    
    (defmacro aif (test then &optional else)
      `(let ((it ,test))
         (if it ,then ,else)))
    
    (in-package :cl-user)
    (foo:aif (+ 3 3) it) ; Fails
    

  • 发生这种情况的原因是,具有插入符号的宏扩展为代码,其中包括插入到标记器中的符号,而cond表达式只有插入到CSHARP-PARSER中的符号。宏扩展包含的任何符号(关键字或gensym除外)都应插入

    以下宏将符号列表插入到同名变量中:

    (defmacro with-interned-symbols (symbol-list &body body)
      "Interns a set of symbols in the current package to variables of the same (symbol-name)."
      (let ((symbol-list (mapcar (lambda (s)
                                   (list s `(intern (symbol-name ',s))))
                                 symbol-list)))
        `(let ,symbol-list ,@body)))
    
    可以使用上述方法重新定义带有令牌和peek的宏,以避免这种不匹配:

    (with-interned-symbols (token peek)
      (defmacro with-token-and-peek (&body body) 
        `(let ((,token (current-token tokenizer))
           (,peek (peek-token tokenizer)))
           ,@body)))
    

    请注意,虽然回指宏可能是这里最明显的特例,但这可能发生在任何将新符号引入扩展的宏中,关键字除外,因为它们总是在关键字包中。

    谢谢!第一个解决方案运行良好,已编译!