;;
;; Simple arithmetic calculator.
;;
(require-extension lalr-driver)
;; parser
(include "brep.yy.scm")
;;;
;;;; The lexer
;;;
(define (port-line port)
(let-values (((line _) (port-position port)))
line))
(define (port-column port)
(let-values (((_ column) (port-position port)))
column))
(define (make-lexer errorp in)
(lambda ()
(letrec ((skip-spaces
(lambda ()
(let loop ((c (peek-char in)))
(if (and (not (eof-object? c))
(or (char=? c #\space) (char=? c #\tab)))
(begin
(read-char in)
(loop (peek-char in)))))))
(skip-line
(lambda ()
(let loop ((c (peek-char in)))
(if (and (not (eof-object? c)) (not (char=? c #\newline)) (not (char=? c #\return)))
(begin
(read-char in)
(loop (peek-char in)))
))
))
(read-number
(lambda (l)
(let ((c (peek-char in)))
(if (or (char-numeric? c) (char=? #\. c) (char=? #\- c) (char=? #\e c))
(read-number (cons (read-char in) l))
(string->number (apply string (reverse l))) ))
))
(read-id
(lambda (l)
(let ((c (peek-char in)))
(if (or (char-alphabetic? c) (char=? #\_ c))
(read-id (cons (read-char in) l))
(string->symbol (apply string (reverse l))) ))
))
(read-string
(lambda (l)
(let ([c (peek-char in)])
(cond [(eq? 'eof c) (errorp "unexpected end of string constant")]
[(char=? c #\\) (let ((n (read-char in)))
(loop (cons n l)))]
[(char=? c #\") (begin (read-char in) (apply string (reverse l))) ]
[else (read-string (cons (read-char in) cs))] ))
))
)
;; -- skip spaces
(skip-spaces)
;; -- read the next token
(let loop ()
(let* ((location (make-source-location "*stdin*" (port-line in) (port-column in) -1 -1))
(c (read-char in)))
(cond ((eof-object? c) '*eoi*)
((char=? c #\newline) (make-lexical-token 'NEWLINE location #f))
((char=? c #\+) (make-lexical-token '+ location #f))
((char=? c #\-) (make-lexical-token '- location #f))
((char=? c #\*) (make-lexical-token '* location #f))
((char=? c #\/) (let ((n (peek-char in)))
(if (char=? n #\/)
(begin (skip-line) (loop))
(make-lexical-token '/ location #f))))
((char=? c #\=) (make-lexical-token '= location #f))
((char=? c #\,) (make-lexical-token 'COMMA location #f))
((char=? c #\() (make-lexical-token 'LPAREN location #f))
((char=? c #\)) (make-lexical-token 'RPAREN location #f))
((char=? c #\") (make-lexical-token 'STRING location (read-string (list c))))
((char-numeric? c) (make-lexical-token 'NUM location (read-number (list c))))
((char-alphabetic? c) (make-lexical-token 'ID location (read-id (list c))))
(else
(errorp "PARSE ERROR : illegal character: " c)
(skip-spaces)
(loop))))))))
;;;
;;;; Environment management
;;;
(define *env* (make-parameter (list (cons '$$ 0))))
(define (init-bindings)
(*env* (list (cons '$$ 0)))
(add-binding 'PI 3.14159265358979)
(add-binding 'int round)
(add-binding 'cos cos)
(add-binding 'sin sin)
(add-binding 'tan tan)
(add-binding 'expt expt)
(add-binding 'sqrt sqrt)
(add-binding 'loadPoints load-points-from-file)
)
(define (add-binding var val)
(*env* (cons (cons var val) (*env*)))
val)
(define (get-binding var)
(let ((p (assq var (*env*))))
(if p
(cdr p)
0)))
(define (invoke-func proc-name args)
(let ((proc (get-binding proc-name)))
(if (procedure? proc)
(apply proc args)
(begin
(display "ERROR: invalid procedure:")
(display proc-name)
(newline)
0))))
;; (init-bindings)
(define (errorp message . args)
(display message)
(if (and (pair? args)
(lexical-token? (car args)))
(let ((token (car args)))
(display (or (lexical-token-value token)
(lexical-token-category token)))
(let ((source (lexical-token-source token)))
(if (source-location? source)
(let ((line (source-location-line source))
(column (source-location-column source)))
(if (and (number? line) (number? column))
(begin
(display " (at line ")
(display line)
(display ", column ")
(display (+ 1 column))
(display ")")))))))
(for-each display args))
(newline))
(define (brep-lexer in) (make-lexer errorp in))
(define (brep-eval lexer) (brep-parser lexer errorp))
(define (brep-eval-string s)
(brep-parser (brep-lexer (open-input-string (string-append s "\n"))) errorp))