我有一个用Lisp编写的系统运行状态机。我只想给出目录名称,从目录动态加载状态机的定义和任何所需的资产(图像等)。将有多个不同的状态机。这与Apache加载和运行WAR文件类似,但不完全相同。
我担心的是,简单地编译和加载文件几乎可以运行任何东西。理想情况下,我只想获得状态机定义,使用资产路径配置它,并让它可以执行。现在我正在加载一个实现特定基类的类,但这不是直截了当的。有没有标准的技术呢?
感谢。
答案 0 :(得分:3)
你是说你担心从文件中读取任意代码执行的可能性?我应该考虑重新定义读取表以排除不需要的符号。
有关结帐this的示例,请查找“SAFE-READ-FROM-STRING”。
它不完整但是你可以使用#'sread来获取数据结构,做一些健全性检查并在需要时进行编译。
如果这不是你想要的,那么我道歉,你能否进一步解释你在寻找什么?
答案 1 :(得分:1)
鉴于您想要在不执行任意代码的情况下读取状态机的定义,您可以考虑以下宏:
(defmacro def-state-machine (name (&rest assets) &rest states)
`(defparameter ,name
(list
:assets ',(remove-if-not #'legal-asset? assets)
:states ',(remove-if-not #'legal-state? states))))
将创建有效资产和状态的列表(因为我不知道你的机器是什么样的,我在这里放了一些抽象谓词 - 他们可能会检查法律语法,或者如果参数是某种类型的,或者如果资产或国家是非法的,则抛出错误。)
让我们假设,你还需要定义一些运行机器的函数:
(defmacro def-transition (name args &body body)
`(defun ,name (,@args)
,@body))
用于定义函数的单独宏允许进行额外的健全性检查。最后,您可以定义阅读器功能:
(defun load-toy-state-machine (directory)
(let ((path (cl-fad:merge-pathnames-as-file directory #P"machine.lisp"))
;(*readtable* (copy-readtable nil))
)
; (make-dispatch-macro-character #\#)
(with-open-file (stream path :direction :input)
(do ((form (read stream nil 'done)
(read stream nil 'done)))
((eql form 'done) T)
(if (member (car form) '(def-state-machine def-transition))
(eval form)
(error "malformed state machine definition file"))))))
eval只允许使用具有固定语法的宏(def-state-machine和def-transition),并且可能包含额外的健全性检查。这些都不执行代码。