我在Scheme中有以下功能(使用Dr. Racket),它是从Scheme到Javascript的模糊翻译。
我似乎无法弄清楚为什么会打印#void。
我猜它与fprintf的返回值有关,但我不确定如何克服这种行为。
有什么想法吗?
(define unparse->js
(lambda (ast output-port)
(cond ((def-exp? ast) (fprintf output-port "const ~a = ~a;" (unparse->js
(def-exp->var ast) output-port) (unparse->js (def-exp->val ast) output-port)))
((cexp? ast)
(cond ((num-exp? ast) (number->string (num-exp->val ast)))
((bool-exp? ast) (if (eq? (bool-exp->val ast) #t) "true" "false"))
((str-exp? ast) (str-exp->val ast))
((var-exp? ast) (symbol->string (var-exp->var ast)))
((literal-exp? ast) (list 'quote (literal-exp->val ast)))
((proc-exp? ast) (fprintf output-port "(~a) => { ~a }"
(string-join
(map (lambda (b)
(unparse->js b output-port)
)
(proc-exp->params ast)
)
",")
(string-join
(map (lambda (ast)
(unparse->js ast output-port)
)
(proc-exp->body ast))
";")))
((if-exp? ast) (fprintf output-port "~a ? ~a : ~a"
(unparse->js (if-exp->test ast) output-port)
(unparse->js (if-exp->then ast) output-port)
(unparse->js (if-exp->else ast) output-port)))
((let-exp? ast) (fprintf output-port "let ~a; ~a;"
(string-join
(map (lambda (b)
(fprintf output-port "~a = ~a"
(unparse->js (binding->var b) output-port)
(unparse->js (binding->val b) output-port)
)
)
(let-exp->bindings ast)
)
",")
(string-join
(map (lambda (b)
(unparse->js b output-port)
)
(let-exp->body ast))
";")
)
)
((app-exp? ast) (fprintf output-port "~a(~a)"
(unparse->js (app-exp->rator ast) output-port)
(string-join
(map (
lambda (rand)
(unparse->js rand output-port)
)
(app-exp->rands ast)
)
",")
)
)
(else (error "Unknown exp type: " ast))))
(else (error "Unknown exp type: " ast)))
)
)
我这样称呼它:
(unparse-> js(parse'(if(eq?5 3)1 0))(current-output-port))
预期结果是:
等等?(5,3)? 1:0
然而,我得到的结果是:
eq?(5,3)#<无效> ? 1:0
答案 0 :(得分:1)
尝试打印到字符串输出端口,看看是否能解决问题。 如果没有生成完整的例子我们可以测试。该错误可能在,例如,unparse-> js或其他功能。
要计算空白的打印位置,请插入
(displayln ast)
在
之后 (lambda (ast output-port)
这样,每次调用unparse-> js时都会显示当前的ast。然后你可以找到罪魁祸首的条款。
关于评论,会弹出更多“空洞”。
有两个问题:首先输出端口与repl输出端口相同。这意味着您不打印的值(例如在num-exp子句中)由repl打印。
试试这个
(具有输出到字符串 (lambda()(unparse-> js(解析'(if(eq?5 3)1 0))(current-output-port))))
这将生成一个包含所有内容的字符串。
第二个问题是由于这种打印方式:
(fprintf output-port "~a ? ~a : ~a"
(unparse->js (if-exp->test ast) output-port)
(unparse->js (if-exp->then ast) output-port)
(unparse->js (if-exp->else ast) output-port)))
由于unparse-js在您使用fprintf的所有子句中返回void
(请记住fprintf返回void
),如果其中一个子表达式返回void
,则会打印void
现在的问题是如何避免这个问题。一种常见的解决方案是将打印分为两部分。第一阶段是建立一个字符串树。打印字符串中的字符串将产生正确的输出。
所以而不是:
(fprintf output-port "~a ? ~a : ~a"
(unparse->js (if-exp->test ast) output-port)
(unparse->js (if-exp->then ast) output-port)
(unparse->js (if-exp->else ast) output-port)))
你写了
(list (unparse->js (if-exp->test ast))
" ? "
(unparse->js (if-exp->then ast))
" : "
(unparse->js (if-exp->else ast))))
这将使unparse->js
返回一个字符串树。
然后简单地创建一个打印机功能,通过树进行递归并打印单个字符串。