2012-09-10 87 views
3

设计一个解释器重写该脚本的原始脚本是这样的:在球拍

#lang racket 
(for ([i (in-range 3)]) 
    (for ([j (in-range 9)]) 
     (display "X")) 
    (display "\n")) 

(for ([i (in-range 6)]) 
    (for ([j (in-range 3)]) 
    (display " ")) 
    (for ([j (in-range 3)]) 
    (display "X")) 
    (for ([j (in-range 3)]) 
    (display " ")) 
    (display "\n")) 

(for ([i (in-range 3)]) 
    (for ([j (in-range 9)]) 
     (display "X")) 
    (display "\n")) 

输出是:

XXXXXXXXX 
XXXXXXXXX 
XXXXXXXXX 
    XXX 
    XXX 
    XXX 
    XXX 
    XXX 
    XXX 
XXXXXXXXX 
XXXXXXXXX 
XXXXXXXXX 

我不知道我是否可以使用像DSL重写这个这样的:

(define a 
    "3 9 X 
6 3 b 3 X 3 b 
3 9 X") 

然后:

(interpret a) 

绘制此图。

有谁知道什么是最好的方法来做到这一点?

+1

我不会通过举例来描述DSL。实际显示语法或类似的东西会更有用。 –

+0

数字列表和“X”和“b”会比字符串更加自然。 – erjiang

+0

Firegun:你对下面的答案有任何疑问或疑问吗?只是跟进这一点。 – dyoo

回答

8

要攻击这样的问题,首先要描述一种数据类型,它捕获您在DSL中所需的操作,而不是集中在表面语法上。一旦掌握了数据类型,您就可以更容易地解决问题。

从第一眼看上去,它的样子,我们可以在你的语言设计的三个基本形式:

  1. 字符串
  2. 重复
  3. 测序

我们可以代表本不相交类原始字符串和结构。让我们把这个类作为一个整体称为“pexpr”,用于“可打印的expr”。在代码:

;; An pexpr is one of the following: 
;; * a primitive string, 
;; * a seq, or 
;; * a repeat 
(struct seq (bodies) #:transparent) ;; bodies is a list of pexpr 
(struct repeat (n body) #:transparent) ;; n is a number, body is a pexpr 

这可能有助于使一些辅助功能,因为“序列”和缩写“重复”是自己有点啰嗦。

;; For convenience, we define some abbreviations s and r for seq and repeat, 
;; respectively. 
(define (s . bodies) 
    (seq bodies)) 
(define (r n . bodies) 
    (repeat n (seq bodies))) 

你们的榜样“I”字符串可以写成这样:

(define an-example 
    (s 
    (r 3 (r 9 "X") "\n") 
    (r 6 (r 3 " ") (r 3 "X") "\n") 
    (r 3 (r 9 "X") "\n"))) 

注意,该编码具有新行明确表示它,单从表面的语法,是隐含的。然后,它成为解析器的工作,在表面语法中使用线条并将它们变成pexprs,但这不应该太困难。希望。:)

反正解释功能,然后,变成填充细节对于这样的一个模板的问题:

(define (interpret pexpr) 
    (match pexpr 
    [(? string?) 
    ...] 
    [(struct seq (bodies)) 
    ...] 
    [(struct repeat (n body)) 
    ...])) 

其中“...的应该是容易填写英寸

这种类型的问题的方法是由How to Design ProgramsProgramming Languages: Application and Interpretation描述的方法。我建议看看他们:他们是好东西。

+0

不错!哦,等等,我需要输入更多的字符。 –

1

当然,这看起来可行。这主要是一个解析问题。我会像这样分解它。每个输入行指定一个输出行块。找出一个在Racket中表现出来的好方法。举一些例子,以确保它涵盖了你想要的内容。接下来,我可能会编写呈现其中一个块的函数。大多数情况下,我会先做一个,这样我才能看到输出的满意度。然后,我会编写一个函数,它将这些块规范列表并将其输出。然后,我会编写一个解析单行输入的函数。看起来您可以使用空格分隔这些行(例如,使用“regexp-split”),然后使用即席分析器处理这些列表。这是我认为最可能出错的部分,在编写代码之前我会编写大量测试用例。最后,您需要一个函数,在每一行输入中调用此解析器,然后将生成的块规格传送到显示函数。