如何使我的Racket设计的语言从外部文件运行脚本?

时间:2019-06-30 13:12:29

标签: racket

我在Racket中设计了一种自定义语言,我们称之为waffle

假设我有

(define (printstr . input)
   (if (string? (car input)) 
       (write (string-join input ""))
       (write input)))

; ... a whole bunch of other definitions

(command-line
 #:multi
 [("-v" "--verbose")    "more verbose"      (set! loglevel (add1 loglevel))]
 [("-q" "--quiet")      "be quiet"          (set! loglevel 0)]
 #:once-any
 [("-i" "--in-place")   "edit in-place"     (set! mode 'in-place)]
 [("-c" "--create-new") "create a new file" (set! mode 'new)]
 [("-n" "--dry-run")    "do nothing"        (set! mode #f)]
 #:once-each
 [("-d" "--directory") dir "work in a given directory" (set! root dir)]
 #:help-labels "operations to perform:"
 #:multi
 [("+l" "++line") "add a line"    (set! ops `(,@ops "add"))]
 [("-l" "--line") "delete a line" (set! ops `(,@ops "delete"))]
 [("-e" "--edit") "edit a line"   (set! ops `(,@ops "edit"))]
 #:args (file)
 (define in (open-input-file file))

 ; This is probably where I'm going wrong with how my language REPL evaluates files passed to it.
 (eval (file->list file) ns))

然后我使用'Racket [menu]-> Create Executable ...-> [Type] Launcher'从DrRacket创建一个可执行文件。名称例如waffle-test

我有一个用华夫饼干语言hello.waffle编写的文件:

(printstr "Hello!")

我希望这会打印“你好!”在命令行上,然后退出且没有错误。但是我收到一个我不明白的奇怪错误,并且没有换行符,我也得到了提示。

$ ./waffle-test hello.waffle 
application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #<void>
  arguments...: [none]
  context...:
   eval-one-top12
   "/home/connie/Desktop/racket-ffgardfghf/waffle": [running body]
   temp37_0
   for-loop
   run-module-instance!125
   perform-require!78
"Hello!" $

我知道您不应该使用eval,但是我不知道如何使我的语言可执行文件能够读取和运行传递给它的文件。最好的方法是什么?

2 个答案:

答案 0 :(得分:2)

仅通过这个简单的测试,我就发现了几件事:

#!racket
(file->list "test.waffle")

test.waffle为:

(waffle me)
(waffle it)

已打印的副本:

((waffle me)
 (waffle it))

即使waffle是有效的过程,那也不是有效的代码。您需要使其看起来像这样:

(begin
  (waffle me)
  (waffle it))

现在您可以通过要求您的语言来做到这一点,但是您也可以只对生成的结构consbegin进行eval评估,eval将按顺序对每个顶级表单进行评估。

使用eval会遇到问题。您很快就会知道。制作解释器的正确方法是创建自己的eval,该{@ 1}实现语言语法并在原始环境中使用环境。它具有使用主机的接口,但不是。使用waffle +--------+--------------------+ |item_id| value | +--------+--------------------+ | 1 | 1 | | 2 | 4 | | 3 | 2 | | 4 | 6 | +--------+--------------------+ ,程序可以访问所有内部函数,并且您实际上并没有创建解释器,因为您只公开了Racket。

我记得有人对Ruby进行了同样的操作,并拥有一个网页,并且有人刚刚尝试键入一个命令,该命令删除了系统上的所有文件,并且Web服务消失了。

答案 1 :(得分:1)

通过修复代码中的一些错误,我设法解决了我的问题!

我改变了

(eval (file->list file) ns))

(define program (cons 'begin (file->list file)))

(eval program ns))

我还更改了'printstr'功能,

 (define (printstr . input)
   (if (string? (car input)) 
       (write (string-join input ""))
       (write input)))

 (define (printstr input)
   (displayln input))