dev-srcloc
Matthew Butterick 8 years ago
parent 5d7242fccb
commit 3d8f7f2ded

@ -1,8 +1,7 @@
#lang br #lang br/quicklang
(require (for-syntax syntax/strip-context)) (require (for-syntax syntax/strip-context))
(provide #%top-interaction #%app #%datum (provide #%top-interaction #%app #%datum
(rename-out [basic-module-begin #%module-begin]) (rename-out [basic-module-begin #%module-begin])
(rename-out [basic-top #%top])
(all-defined-out)) (all-defined-out))
; BASIC implementation details ; BASIC implementation details
@ -20,13 +19,9 @@
#'(#%module-begin #'(#%module-begin
(define UNIQUE-ID 0) ... (define UNIQUE-ID 0) ...
(provide UNIQUE-ID ...) (provide UNIQUE-ID ...)
(run PROGRAM-LINE ... (line #f (statement "end")))))) (run (sort (cons (line +inf.0 (statement "end"))
(list PROGRAM-LINE ...)) #:key $line-number <)))))
; #%app and #%datum have to be present to make #%top work
(define-macro (basic-top . ID)
#'(begin
(displayln (format "got unbound identifier: ~a" 'ID))
(procedure-rename (λ xs (cons 'ID xs)) (string->symbol (format "undefined:~a" 'ID)))))
(struct exn:line-not-found exn:fail ()) (struct exn:line-not-found exn:fail ())
(define (raise-line-not-found-error ln) (define (raise-line-not-found-error ln)
@ -43,13 +38,13 @@
(define (raise-end-line-signal) (define (raise-end-line-signal)
(raise (end-line-signal "" (current-continuation-marks)))) (raise (end-line-signal "" (current-continuation-marks))))
(define (run . line-list) (define (run line-list)
(define lines (list->vector line-list)) (define lines (list->vector line-list))
(define (find-index ln) (define (find-index ln)
(or (or
(for/or ([idx (in-range (vector-length lines))]) (for/or ([idx (in-range (vector-length lines))])
(and (= ($line-number (vector-ref lines idx)) ln) (and (= ($line-number (vector-ref lines idx)) ln)
idx)) idx))
(raise-line-not-found-error ln))) (raise-line-not-found-error ln)))
(void (void
(with-handlers ([end-program-signal? void]) (with-handlers ([end-program-signal? void])
@ -61,15 +56,15 @@
(find-index maybe-line-number) (find-index maybe-line-number)
(add1 program-counter))))))) (add1 program-counter)))))))
(define return-stack empty) (define current-return-stack (make-parameter empty))
(define (basic:gosub where) (define (basic:gosub where)
(let/cc return-k (let/cc return-k
(set! return-stack (cons return-k return-stack)) (current-return-stack (cons return-k (current-return-stack)))
(basic:goto where))) (basic:goto where)))
(define current-line (make-parameter #f)) (define current-line (make-parameter #f))
(struct $line (number thunk)) (struct $line (number thunk) #:transparent)
(define-macro (line NUMBER . STATEMENTS) (define-macro (line NUMBER . STATEMENTS)
#'($line NUMBER (λ () #'($line NUMBER (λ ()
(current-line NUMBER) (current-line NUMBER)
@ -89,9 +84,7 @@
(define-macro-cases basic:let (define-macro-cases basic:let
[(_ (id-expr ID) EXPR) [(_ (id-expr ID) EXPR)
#'(begin #'(set! ID EXPR)]
#;(displayln (format "setting ~a = ~a in ~a" 'ID EXPR (current-line)))
(set! ID EXPR))]
[(_ (id-expr ID DIM-IDX ...) EXPR) [(_ (id-expr ID DIM-IDX ...) EXPR)
#'(array-set! ID DIM-IDX ... EXPR)]) #'(array-set! ID DIM-IDX ... EXPR)])
@ -151,11 +144,7 @@
[(_ BASE) #'BASE] [(_ BASE) #'BASE]
[(_ BASE POWER) #'(expt BASE POWER)]) [(_ BASE POWER) #'(expt BASE POWER)])
(define-macro-cases number (define-macro-cases maybe-negative-val
[(_ "-" NUM) #'(- NUM)]
[(_ NUM) #'NUM])
(define-macro-cases id-val
[(_ "-" ID) #'(- ID)] [(_ "-" ID) #'(- ID)]
[(_ ID) #'ID]) [(_ ID) #'ID])
@ -165,11 +154,11 @@
(define (println [x ""]) (define (println [x ""])
(define xstr (format "~a" x)) (define xstr (format "~a" x))
(displayln xstr) (displayln xstr)
(set! current-print-position 0)) (current-print-position 0))
(define (print x) (define (print x)
(define xstr (format "~a" x)) (define xstr (format "~a" x))
(display xstr) (display xstr)
(set! current-print-position (+ current-print-position (string-length xstr)))) (current-print-position (+ (current-print-position) (string-length xstr))))
(match args (match args
[#f (println)] [#f (println)]
@ -186,8 +175,8 @@
[(list print-list-items ...) [(list print-list-items ...)
(for-each println print-list-items)])) (for-each println print-list-items)]))
(define current-print-position 0) (define current-print-position (make-parameter 0))
(define (TAB num) (make-string (max 0 (INT (- num current-print-position))) #\space)) (define (TAB num) (make-string (max 0 (INT (- num (current-print-position)))) #\space))
(define (INT num) (inexact->exact (truncate num))) (define (INT num) (inexact->exact (truncate num)))
(define (SIN num) (sin num)) (define (SIN num) (sin num))
(define (ABS num) (inexact->exact (abs num))) (define (ABS num) (inexact->exact (abs num)))
@ -215,8 +204,8 @@
(define (basic:return) (define (basic:return)
(define return-k (car return-stack)) (define return-k (car (current-return-stack)))
(set! return-stack (cdr return-stack)) (current-return-stack (cdr (current-return-stack)))
(return-k #f)) (return-k #f))
(define (basic:stop) (basic:end)) (define (basic:stop) (basic:end))
@ -228,13 +217,13 @@
#'(begin #'(begin
(set! ID (make-array (apply shape (append (list 0 (add1 EXPR)) ...)))) ...)) (set! ID (make-array (apply shape (append (list 0 (add1 EXPR)) ...)))) ...))
(define for-stack empty) (define current-for-stack (make-parameter empty))
(define (push-for-stack thunk) (define (push-for-stack thunk)
(set! for-stack (cons thunk for-stack))) (current-for-stack (cons thunk (current-for-stack))))
(define (pop-for-stack) (define (pop-for-stack)
(set! for-stack (cdr for-stack))) (current-for-stack (cdr (current-for-stack))))
(define (in-closed-interval? x left right) (define (in-closed-interval? x left right)
(define cmp (if (< left right) <= >=)) (define cmp (if (< left right) <= >=))
@ -258,10 +247,10 @@
#f))]) ; return value for first visit to line #f))]) ; return value for first visit to line
(define (handle-next [which #f]) (define (handle-next [which #f])
(unless (pair? for-stack) (error 'next "for-stack is empty")) (unless (pair? (current-for-stack)) (error 'next "for-stack is empty"))
(define for-thunk (cdr (if which (define for-thunk (cdr (if which
(assq which for-stack) (assq which (current-for-stack))
(car for-stack)))) (car (current-for-stack)))))
(for-thunk)) (for-thunk))
(define-macro (basic:next VAR ...) (define-macro (basic:next VAR ...)

@ -1,4 +1,14 @@
#lang br/quicklang #lang br/quicklang
(module reader br (require "parser.rkt" "tokenizer.rkt")
(require "reader.rkt")
(provide read-syntax)) (module+ reader (provide read-syntax))
(define (read-syntax path port)
(define-values (line col pos) (port-next-location port))
(define port+newline (input-port-append #f port (open-input-string "\n")))
(port-count-lines! port+newline)
(set-port-next-location! port+newline line col pos)
(define parse-tree (parse path (tokenize port+newline)))
(strip-bindings
#`(module basic-mod basic-demo/expander
#,parse-tree)))

@ -30,16 +30,13 @@ product : [product ("*" | "/")] power
power : value [/"^" value] power : value [/"^" value]
@value : id-val @value : maybe-negative-val
| id-expr | id-expr
| /"(" expr /")" | /"(" expr /")"
| number
| STRING | STRING
id-expr : id [/"(" expr [/"," expr]* /")"] id-expr : id [/"(" expr [/"," expr]* /")"]
@id : ID @id : ID
id-val : ["-"] id-expr maybe-negative-val : ["-"] (id-expr | NUMBER)
number : ["-"] NUMBER

@ -1,6 +0,0 @@
#lang br
(require br/reader-utils "parser.rkt" "tokenizer.rkt")
(define-read-and-read-syntax (source-path input-port)
#`(module bf-mod basic-demo/expander
#,(parse source-path (tokenize input-port))))

@ -1,34 +1,46 @@
#lang br #lang br
(require parser-tools/lex parser-tools/lex-sre (require parser-tools/lex (prefix-in : parser-tools/lex-sre)
brag/support brag/support racket/string)
racket/string)
(provide tokenize) (provide tokenize)
(define-lex-abbrevs (define-lex-abbrevs
(natural (repetition 1 +inf.0 numeric)) (positive-integer (:+ numeric))
;; don't lex the leading "-": muddles "-X" and "Y-X" ;; don't lex the leading "-": muddles "-X" and "Y-X"
(number (union (seq natural) (positive-number (:or positive-integer (:seq (:? positive-integer) (:seq "." positive-integer)))))
(seq (? natural) (seq "." natural))))
(quoted-string (seq "\"" (repetition 0 +inf.0 (char-complement "\"")) "\"")))
(define (tokenize input-port) (define (tokenize ip)
(port-count-lines! ip)
(define (next-token) (define (next-token)
(define get-token (define get-token
(lexer-src-pos (lexer-src-pos
[(eof) eof] [(eof) eof]
[(seq "/*" (complement (seq any-string "*/" any-string)) "*/") (get-token input-port)] [whitespace (next-token)]
[(union #\tab #\space #\newline [(from/to "/*" "*/") (next-token)]
(seq number " REM" (repetition 0 +inf.0 (char-complement #\newline)) #\newline)) (get-token input-port)] [(:: positive-number (:+ whitespace) (from/to (uc+lc "rem") "\n")) (next-token)]
[(union "PRINT" "print" "FOR" "for" "TO" "to" "STEP" "step" "IF" "if" [(:or (uc+lc "print" "for" "to" "step" "if"
"GOTO" "goto" "INPUT" "input" "LET" "let" "NEXT" "next" "goto" "input" "let" "next"
"RETURN" "return" "CLEAR" "clear" "LIST" "list" "RUN" "run" "return" "clear" "list" "run"
"END" "end" "THEN" "then" "ELSE" "else" "GOSUB" "gosub" "end" "then" "else" "gosub"
"AND" "and" "OR" "or" "STOP" "stop" "LET" "let" "DEF" "def" "DIM" "dim" "ON" "on" "and" "or" "stop" "let" "def" "dim" "on")
";" "=" "(" ")" "+" "-" "*" "/" "^" ";" "=" "(" ")" "+" "-" "*" "/" "^"
"<=" ">=" "<>" "<" ">" "=" ":" ",") (string-downcase lexeme)] "<=" ">=" "<>" "<" ">" "=" ":" ",") (string-downcase lexeme)]
[number (token 'NUMBER (string->number lexeme))] [positive-number (token 'NUMBER (string->number lexeme)
[(seq upper-case (repetition 0 +inf.0 (or upper-case numeric)) (? "$")) (token 'ID (string->symbol lexeme))] #:position (pos lexeme-start)
[quoted-string (token 'STRING (string-trim lexeme "\""))])) #:line (line lexeme-start)
(get-token input-port)) #:column (col lexeme-start)
#:span (- (pos lexeme-end)
(pos lexeme-start)))]
[(:: alphabetic (:* (:or alphabetic numeric)) (:? "$")) (token 'ID (string->symbol lexeme)
#:position (pos lexeme-start)
#:line (line lexeme-start)
#:column (col lexeme-start)
#:span (- (pos lexeme-end)
(pos lexeme-start)))]
[(from/to "\"" "\"") (token 'STRING (trim-ends "\"" lexeme "\"")
#:position (+ (pos lexeme-start) 1)
#:line (line lexeme-start)
#:column (+ (col lexeme-start) 1)
#:span (- (pos lexeme-end)
(pos lexeme-start) 2))]))
(get-token ip))
next-token) next-token)

Loading…
Cancel
Save