使脚本在DrRacket和(x)repl中均可工作

时间:2019-02-07 09:48:45

标签: parsing scheme racket lex

我正在尝试从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) $1)
           ((expr start) $2))

    (expr ((INT PLUS INT) (display-plus (list $1 $3)))
          ((INT MINUS INT) (display-minus (list $1 $3)))
          ((INT MULTIPLY INT) (display-multiply (list $1 $3)))
          ((INT DIVIDE INT) (display-divide (list $1 $3)))
          ((ANY) (displayln $1))))))


(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返回了新行,我尝试使用(eof-object? input)(eq? input #\newline)进行检查,但是现在我只得到每一秒钟的结果。

1 个答案:

答案 0 :(得分:3)

有两个问题:

首先,您正在读取一行(let ((input (read-line))),但没有将输入发送到计算器,而是发送了另一行– (calc (read-line))

您应该将input传递给calc进行评估。

第二,您的输出中有很多#<void>

这是因为calc假定您的解析器产生了可以打印的值:

(displayln result)

,但是解析器不产生任何值,它仅输出一个值。
要么删除result的输出,要么重写解析器以将值返回给其调用者。