Заставьте скрипт работать как в DrRacket, так и (x) repl - PullRequest
0 голосов
/ 07 февраля 2019

Я пытаюсь заставить скрипт работать как от DrRacket, так и от repl, используя это в качестве отправной точки: Калькулятор ракетки

Вот мой текущий код:

#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), но теперь я получаю только каждый второй результат.

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Есть две проблемы:

Во-первых, вы читаете строку, (let ((input (read-line))), но вы не отправляете эти входные данные в калькулятор, вы отправляете еще одну - (calc (read-line)).

Вы должны вместо этого передать input на calc для оценки.

Во-вторых, у вас много #<void> s в ваших выходных данных.

Это потому, чтоcalc предполагает, что ваш парсер выдает значение, которое он может напечатать:

(displayln result)

, но парсер не выдает никакого значения, он печатает только одно.
Либо удалите вывод result,или перепишите синтаксический анализатор, чтобы вернуть значение его вызывающей стороне.

0 голосов
/ 07 февраля 2019

Заменить (calc (read-line)) на (calc input).

...