使脚本在 DrRacket 和 (x)repl 中工作
Make script work both in DrRacket and (x)repl
我正在尝试从 DrRacket 和 repl 制作一个脚本,以此作为我的起点:Racket calculator
这是我当前的代码:
#lang racket
(provide (all-defined-out))
(require parser-tools/lex
(prefix-in re: parser-tools/lex-sre)
parser-tools/yacc)
(define-tokens value-tokens (INT ANY))
(define-empty-tokens empty-tokens
(PLUS MINUS MULTIPLY DIVIDE NEWLINE EOF))
(define basic-lexer
(lexer
((re:+ numeric) (token-INT lexeme))
(#\+ (token-PLUS))
(#\- (token-MINUS))
(#\* (token-MULTIPLY))
(#\/ (token-DIVIDE))
((re:or #\tab #\space) (basic-lexer input-port))
(#\newline (token-NEWLINE))
((eof) (token-EOF))
(any-char (token-ANY lexeme))))
(define (display-plus expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (+ left right)))
(newline))
(define (display-minus expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (- left right)))
(newline))
(define (display-multiply expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (* left right)))
(newline))
(define (display-divide expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (/ left right)))
(newline))
(define basic-parser
(parser
(start start)
(end NEWLINE EOF)
(tokens value-tokens empty-tokens)
(error (lambda (ok? name value)
(printf "Couldn't parse: ~a\n" name)))
(grammar
(start ((expr) )
((expr start) ))
(expr ((INT PLUS INT) (display-plus (list )))
((INT MINUS INT) (display-minus (list )))
((INT MULTIPLY INT) (display-multiply (list )))
((INT DIVIDE INT) (display-divide (list )))
((ANY) (displayln ))))))
(define input1 (open-input-string "123 + 456"))
(define input2 (open-input-string "123 *456"))
(basic-parser (lambda() (basic-lexer input1)))
(basic-parser (lambda() (basic-lexer input2)))
;(define (my-repl)
; (display ">>> ")
; (let* ((input (read-line))
; (input-port (open-input-string
; (list->string
; (drop-right
; (string->list input) 1)))))
; (cond
; ((not (equal? "\r" input)
; (print (basic-parser
; (lambda () (basic-lexer input-port))))))))
; (my-repl))
(define (calc str)
(let* ([port (open-input-string str)]
[result (basic-parser (lambda() (basic-lexer port)))])
(displayln result)))
(define (repl)
(display ">>> ")
(let ((input (read-line)))
(print input)
(cond
((eof-object? input) (displayln "eof"))
((eq? input #\newline) (displayln "new line"))
(else (calc (read-line))))
(newline))
(repl))
此处显示了来自 DrRacket 的测试:
Welcome to DrRacket, version 7.1 [3m].
Language: racket, with debugging; memory limit: 512 MB.
Result: 579
Result: 56088
> (repl)
>>> 1+1
"1+1"2+2
Result: 4
#<void>
>>> 3+3
"3+3"4+4
Result: 8
#<void>
来自回复:
Welcome to Racket v7.1.
> (require "untitled7.rkt")
Result: 579
Result: 56088
> (repl)
>>> "\r"
#<void>
>>> 1+1
"1+1\r"2+2
Result: 4
#<void>
>>> 3+3
"3+3\r"4+4
Result: 8
#<void>
>>> #<eof>eof
>>> ; user break [,bt for context]
它只显示每秒的计算。看起来 read-line returns 在等待用户输入之前是一个新行,我试图用 (eof-object? input)
和 (eq? input #\newline)
检查,但现在我只得到每隔一秒的结果。
将 (calc (read-line))
替换为 (calc input)
。
有两个问题:
首先,您正在读取一行,(let ((input (read-line)))
,但您没有将该输入发送到计算器,而是发送了另一行 – (calc (read-line))
。
您应该将 input
传递给 calc
进行评估。
其次,您的输出中有很多 #<void>
。
这是因为 calc
假设您的解析器生成了一个可以打印的值:
(displayln result)
但解析器不产生任何值,它只打印一个。
要么删除 result
的输出,要么将解析器重写为 return 其调用者的值。
我正在尝试从 DrRacket 和 repl 制作一个脚本,以此作为我的起点:Racket calculator
这是我当前的代码:
#lang racket
(provide (all-defined-out))
(require parser-tools/lex
(prefix-in re: parser-tools/lex-sre)
parser-tools/yacc)
(define-tokens value-tokens (INT ANY))
(define-empty-tokens empty-tokens
(PLUS MINUS MULTIPLY DIVIDE NEWLINE EOF))
(define basic-lexer
(lexer
((re:+ numeric) (token-INT lexeme))
(#\+ (token-PLUS))
(#\- (token-MINUS))
(#\* (token-MULTIPLY))
(#\/ (token-DIVIDE))
((re:or #\tab #\space) (basic-lexer input-port))
(#\newline (token-NEWLINE))
((eof) (token-EOF))
(any-char (token-ANY lexeme))))
(define (display-plus expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (+ left right)))
(newline))
(define (display-minus expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (- left right)))
(newline))
(define (display-multiply expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (* left right)))
(newline))
(define (display-divide expr)
(display "Result: ")
(let ((left (string->number (first expr)))
(right (string->number (last expr))))
(display (/ left right)))
(newline))
(define basic-parser
(parser
(start start)
(end NEWLINE EOF)
(tokens value-tokens empty-tokens)
(error (lambda (ok? name value)
(printf "Couldn't parse: ~a\n" name)))
(grammar
(start ((expr) )
((expr start) ))
(expr ((INT PLUS INT) (display-plus (list )))
((INT MINUS INT) (display-minus (list )))
((INT MULTIPLY INT) (display-multiply (list )))
((INT DIVIDE INT) (display-divide (list )))
((ANY) (displayln ))))))
(define input1 (open-input-string "123 + 456"))
(define input2 (open-input-string "123 *456"))
(basic-parser (lambda() (basic-lexer input1)))
(basic-parser (lambda() (basic-lexer input2)))
;(define (my-repl)
; (display ">>> ")
; (let* ((input (read-line))
; (input-port (open-input-string
; (list->string
; (drop-right
; (string->list input) 1)))))
; (cond
; ((not (equal? "\r" input)
; (print (basic-parser
; (lambda () (basic-lexer input-port))))))))
; (my-repl))
(define (calc str)
(let* ([port (open-input-string str)]
[result (basic-parser (lambda() (basic-lexer port)))])
(displayln result)))
(define (repl)
(display ">>> ")
(let ((input (read-line)))
(print input)
(cond
((eof-object? input) (displayln "eof"))
((eq? input #\newline) (displayln "new line"))
(else (calc (read-line))))
(newline))
(repl))
此处显示了来自 DrRacket 的测试:
Welcome to DrRacket, version 7.1 [3m].
Language: racket, with debugging; memory limit: 512 MB.
Result: 579
Result: 56088
> (repl)
>>> 1+1
"1+1"2+2
Result: 4
#<void>
>>> 3+3
"3+3"4+4
Result: 8
#<void>
来自回复:
Welcome to Racket v7.1.
> (require "untitled7.rkt")
Result: 579
Result: 56088
> (repl)
>>> "\r"
#<void>
>>> 1+1
"1+1\r"2+2
Result: 4
#<void>
>>> 3+3
"3+3\r"4+4
Result: 8
#<void>
>>> #<eof>eof
>>> ; user break [,bt for context]
它只显示每秒的计算。看起来 read-line returns 在等待用户输入之前是一个新行,我试图用 (eof-object? input)
和 (eq? input #\newline)
检查,但现在我只得到每隔一秒的结果。
将 (calc (read-line))
替换为 (calc input)
。
有两个问题:
首先,您正在读取一行,(let ((input (read-line)))
,但您没有将该输入发送到计算器,而是发送了另一行 – (calc (read-line))
。
您应该将 input
传递给 calc
进行评估。
其次,您的输出中有很多 #<void>
。
这是因为 calc
假设您的解析器生成了一个可以打印的值:
(displayln result)
但解析器不产生任何值,它只打印一个。
要么删除 result
的输出,要么将解析器重写为 return 其调用者的值。