set up basic-demo-2

pull/10/head
Matthew Butterick 7 years ago
parent d0f83eb24a
commit c58ac2a806

@ -0,0 +1,61 @@
#lang br/quicklang
(provide (rename-out [b-module-begin #%module-begin])
(matching-identifiers-out #rx"^b-" (all-defined-out)))
(define-macro (b-module-begin (b-program LINE ...))
(with-pattern
([(LINE-NUM ...)
(filter-stx-prop 'b-line-number
(stx-flatten #'(LINE ...)))]
[(LINE-ID ...) (prefix-ids "line-" #'(LINE-NUM ...))])
#'(#%module-begin
LINE ...
(define line-table
(apply hasheqv (append (list LINE-NUM LINE-ID) ...)))
(run line-table))))
(define-macro (b-line LINE-NUMBER STATEMENT ...)
(with-pattern
([LINE-NUMBER-ID (prefix-id "line-" #'LINE-NUMBER
#:source #'LINE-NUMBER)]
[ORIG-LOC caller-stx])
(syntax/loc caller-stx
(define (LINE-NUMBER-ID #:srcloc? [loc #f])
(if loc
(syntax-srcloc #'ORIG-LOC)
(begin (void) STATEMENT ...))))))
(define b-rem void)
(define (b-print [val ""]) (displayln val))
(define (b-sum . nums) (apply + nums))
(define (b-num-expr expr)
(if (integer? expr) (inexact->exact expr) expr))
(struct $program-end-signal ())
(define (b-end) (raise ($program-end-signal)))
(struct $change-line-signal (val))
(define (b-goto expr) (raise ($change-line-signal expr)))
(define-exn line-not-found exn:fail)
(define (run line-table)
(define line-vec
(list->vector (sort (hash-keys line-table) <)))
(with-handlers ([$program-end-signal? void])
(for/fold ([line-idx 0])
([i (in-naturals)])
(unless (< line-idx (vector-length line-vec)) (b-end))
(define line-num (vector-ref line-vec line-idx))
(define line-proc (hash-ref line-table line-num))
(with-handlers
([$change-line-signal?
(λ (cls)
(define clsv ($change-line-signal-val cls))
(or
(and (exact-positive-integer? clsv)
(vector-member clsv line-vec))
(raise-line-not-found
(line-proc #:srcloc? #t))))])
(line-proc)
(add1 line-idx)))))

@ -0,0 +1,85 @@
#lang br/quicklang
(require (for-syntax racket/list sugar/debug))
(provide (matching-identifiers-out #rx"^b-" (all-defined-out)))
(struct line-error (msg))
(define (handle-line-error num le)
(error (format "error in line ~a: ~a" num (line-error-msg le))))
(define return-ks empty)
(define (b-gosub num-expr)
(let/cc return-k
(push! return-ks return-k)
(b-goto num-expr)))
(define (b-return)
(unless (pair? return-ks)
(raise (line-error "return without gosub")))
(define top-return-k (pop! return-ks))
(top-return-k))
(define-macro (b-line NUM STATEMENT ...)
(with-pattern ([LINE-NUM (prefix-id "line-" #'NUM
#:source #'NUM)])
(syntax/loc caller-stx
(define (LINE-NUM)
(with-handlers ([line-error? (λ (le) (handle-line-error NUM le))])
(void) STATEMENT ...)))))
(define-for-syntax (find-unique-var-names stx)
(remove-duplicates
(for/list ([var-stx (in-list (syntax-flatten stx))]
#:when (syntax-property var-stx 'b-id))
var-stx)
#:key syntax->datum))
(define-macro (b-module-begin (b-program LINE ...))
(with-pattern
([((b-line NUM STMT ...) ...) #'(LINE ...)]
[(LINE-FUNC ...) (prefix-id "line-" #'(NUM ...))]
[(VAR-NAME ...) (find-unique-var-names #'(LINE ...))])
#'(#%module-begin
(define VAR-NAME 0) ...
LINE ...
(define line-table
(apply hasheqv (append (list NUM LINE-FUNC) ...)))
(void (run line-table)))))
(provide (rename-out [b-module-begin #%module-begin]))
(define-macro (b-let ID VAL)
#'(set! ID VAL))
(struct end-program-signal ())
(struct change-line-signal (val))
(define (b-end) (raise (end-program-signal)))
(define (b-goto num-expr) (raise (change-line-signal num-expr)))
(define (run line-table)
(define line-vec
(list->vector (sort (hash-keys line-table) <)))
(with-handlers ([end-program-signal? (λ (exn-val) (void))])
(for/fold ([line-idx 0])
([i (in-naturals)]
#:break (>= line-idx (vector-length line-vec)))
(define line-num (vector-ref line-vec line-idx))
(define line-func (hash-ref line-table line-num))
(with-handlers
([change-line-signal?
(λ (cls)
(define clsv (change-line-signal-val cls))
(or
(and (exact-positive-integer? clsv)
(vector-member clsv line-vec))
(error (format "error in line ~a: line ~a not found"
line-num clsv))))])
(line-func)
(add1 line-idx)))))
(define (b-rem val) (void))
(define (b-print [val ""]) (displayln val))
(define (b-sum . nums) (apply + nums))
(define (b-num-expr expr)
(if (integer? expr) (inexact->exact expr) expr))

@ -0,0 +1,3 @@
#lang br
(provide b-gosub b-return)

@ -0,0 +1,4 @@
#lang info
(define compile-omit-paths 'all)
(define test-omit-paths 'all)

@ -0,0 +1,58 @@
#lang br
(require "lexer.rkt" brag/support rackunit)
(define (lex str)
(apply-lexer basic-lexer str))
(check-equal? (lex "") empty)
(check-equal?
(lex " ")
(list (srcloc-token (token " " #:skip? #t)
(srcloc 'string #f #f 1 1))))
(check-equal?
(lex "rem ignored\n")
(list (srcloc-token (token 'REM "rem ignored")
(srcloc 'string #f #f 1 11))
(srcloc-token (token 'NEWLINE "\n")
(srcloc 'string #f #f 12 1))))
(check-equal?
(lex "print")
(list (srcloc-token "print"
(srcloc 'string #f #f 1 5))))
(check-equal?
(lex "goto")
(list (srcloc-token "goto"
(srcloc 'string #f #f 1 4))))
(check-equal?
(lex "end")
(list (srcloc-token "end"
(srcloc 'string #f #f 1 3))))
(check-equal?
(lex "+")
(list (srcloc-token "+"
(srcloc 'string #f #f 1 1))))
(check-equal?
(lex "12")
(list (srcloc-token (token 'INTEGER 12)
(srcloc 'string #f #f 1 2))))
(check-equal?
(lex "1.2")
(list (srcloc-token (token 'DECIMAL 1.2)
(srcloc 'string #f #f 1 3))))
(check-equal?
(lex "12.")
(list (srcloc-token (token 'DECIMAL 12.)
(srcloc 'string #f #f 1 3))))
(check-equal?
(lex ".12")
(list (srcloc-token (token 'DECIMAL .12)
(srcloc 'string #f #f 1 3))))
(check-equal?
(lex "\"foo\"")
(list (srcloc-token (token 'STRING "foo")
(srcloc 'string #f #f 1 5))))
(check-equal?
(lex "'foo'")
(list (srcloc-token (token 'STRING "foo")
(srcloc 'string #f #f 1 5))))
(check-exn exn:fail:read? (lambda () (lex "x")))

@ -0,0 +1,23 @@
#lang br
(require brag/support)
(define-lex-abbrev digits (:+ (char-set "0123456789")))
(define basic-lexer
(lexer-srcloc
[(eof) (return-without-srcloc eof)]
["\n" (token 'NEWLINE lexeme)]
[whitespace (token lexeme #:skip? #t)]
[(from/stop-before "rem" "\n") (token 'REM lexeme)]
[(:or "print" "goto" "end" "+" ":" "gosub" "return" "let" "=") lexeme]
[(:seq (:+ alphabetic) (:* (:or alphabetic numeric))) (token 'ID (string->symbol lexeme))]
[digits (token 'INTEGER (string->number lexeme))]
[(:or (:seq (:? digits) "." digits)
(:seq digits "."))
(token 'DECIMAL (string->number lexeme))]
[(:or (from/to "\"" "\"") (from/to "'" "'"))
(token 'STRING
(substring lexeme
1 (sub1 (string-length lexeme))))]))
(provide basic-lexer)

@ -0,0 +1,11 @@
#lang br/quicklang
(require "parser.rkt" "tokenizer.rkt")
(define (read-syntax path port)
(define parse-tree (parse path (make-tokenizer port path)))
(strip-bindings
#`(module basic-mod basic-demo-2/expander
#,parse-tree)))
(module+ reader
(provide read-syntax))

@ -0,0 +1,14 @@
#lang br/quicklang
(require "parser.rkt" "tokenizer.rkt")
(define (read-syntax path port)
(define parse-tree (parse path (make-tokenizer port path)))
(strip-bindings
#`(module basic-parser-mod basic-demo/parse-only
#,parse-tree)))
(module+ reader (provide read-syntax))
(define-macro (parser-only-mb PARSE-TREE)
#'(#%module-begin
'PARSE-TREE))
(provide (rename-out [parser-only-mb #%module-begin]))

@ -0,0 +1,15 @@
#lang br/quicklang
(require "parser.rkt" "tokenizer.rkt")
(define (read-syntax path port)
(define parse-tree (parse path (make-tokenizer port path)))
(strip-bindings
#`(module basic-parser-mod basic-demo/parse-stx
#'#,parse-tree)))
(module+ reader (provide read-syntax))
(define-macro (parser-only-mb PARSE-STX)
#'(#%module-begin
PARSE-STX))
(provide (rename-out [parser-only-mb #%module-begin]))
(provide syntax)

@ -0,0 +1,17 @@
#lang brag
b-program : [b-line] (/NEWLINE [b-line])*
b-line : b-line-number [b-statement] (/":" [b-statement])*
@b-line-number : INTEGER
@b-statement : b-rem | b-end | b-print | b-goto | b-gosub | b-return | b-let
b-rem : REM
b-end : /"end"
b-print : /"print" [STRING | b-num-expr]
b-goto : /"goto" b-num-expr
b-gosub : /"gosub" b-num-expr
b-return : /"return"
b-let : [/"let"] b-id /"=" b-num-expr
@b-id : ID
b-num-expr : b-sum
b-sum : b-value (/"+" b-value)*
@b-value : b-id | b-number
@b-number : INTEGER | DECIMAL

@ -0,0 +1,8 @@
(define (30) (rem print "'ignored'"))
(define (35) (void))
(define (50) (print "never gets here"))
(define (40) (end))
(define (60) (print "three") (print (+ 1.0 3)))
(define (70) (goto (+ 11 18.5 0.5)))
(define (10) (print "one"))
(define (20) (print) (goto 60) (end))

@ -0,0 +1,10 @@
#lang basic-demo-2
10 gosub 41
20 print "world"
30 gosub 100
31 print "hi"
35 end
40 return
41 print "hello" : return
100 print "third"
110 goto 40

@ -0,0 +1,8 @@
#lang basic-demo-2
10 a = 1 : a = 5
20 gosub 150
30 a = 25
40 gosub 150
50 end
150 print a + a + a
160 return

@ -0,0 +1,11 @@
#lang br
(require "tokenizer.rkt" "parser.rkt" brag/support)
(define str #<<here
10 rem print
20 end
here
)
(parse-tree (apply-tokenizer-maker make-tokenizer str))

@ -0,0 +1,14 @@
#lang br/quicklang
(require brag/support "tokenizer.rkt")
(define (read-syntax path port)
(define tokens (apply-tokenizer make-tokenizer port))
(strip-bindings
#`(module basic-tokens-mod basic-demo/tokenize-only
#,@tokens)))
(module+ reader (provide read-syntax))
(define-macro (parser-only-mb TOKEN ...)
#'(#%module-begin
(list TOKEN ...)))
(provide (rename-out [parser-only-mb #%module-begin]))

@ -0,0 +1,10 @@
#lang br
(require "lexer.rkt" brag/support)
(define (make-tokenizer ip [path #f])
(port-count-lines! ip)
(lexer-file-path path)
(define (next-token) (basic-lexer ip))
next-token)
(provide make-tokenizer)
Loading…
Cancel
Save