diff --git a/beautiful-racket/br/basic/expander.rkt b/beautiful-racket/br/basic/expander.rkt index 78d6b0b..8d57e12 100644 --- a/beautiful-racket/br/basic/expander.rkt +++ b/beautiful-racket/br/basic/expander.rkt @@ -6,37 +6,51 @@ (define #'(basic-module-begin PARSE-TREE ...) #'(#%module-begin - 'PARSE-TREE ...)) + PARSE-TREE ...)) (define #'(basic-program LINE ...) - #'(begin - (define program-lines (vector LINE ...)) - (run program-lines))) + #'(basic-run LINE ...)) -(define (run program-lines) +(define (basic-run . lines) + (define program-lines (list->vector (filter (λ(x) x) lines))) (for/fold ([line-idx 0]) ([i (in-naturals)] #:break (= line-idx (vector-length program-lines))) - (match-define (list line-number proc jump-number) + (match-define (cons line-number proc) (vector-ref program-lines line-idx)) - (when proc (proc)) - (if jump-number - (for/first ([idx (in-range (vector-length program-lines))] - #:when (= (car (vector-ref program-lines idx)) jump-number)) - idx) + (define maybe-jump-number (and proc (proc))) + (if (number? maybe-jump-number) + (let ([jump-number maybe-jump-number]) + (for/or ([idx (in-range (vector-length program-lines))]) + (and (= (car (vector-ref program-lines idx)) jump-number) + idx))) (add1 line-idx)))) -;; model each line as (list line-number line-thunk jump) -;; if jump is #f, that means go to the next line -;; a `GOTO` would not have a line-thunk, just a jump -;; what about `GOSUB`? A jump with a return jump ... +;; model each line as (cons line-number line-thunk) (define-cases #'line - [#'(line 'end) #'(list #f #f #f)] - [#'(_ NUMBER (statement ARG ...) 'end) #'(list NUMBER (statement ARG ...) #f)] - [#'(_ (statement ARG ...) 'end) #'(list #f (statement ARG ...) #f)]) + [#'(line 'end) #'#f] + [#'(_ NUMBER STATEMENT 'end) #'(cons NUMBER (λ _ STATEMENT))] + [#'(_ STATEMENT 'end) #'(cons #f (λ _ STATEMENT))]) + +(define #'(statement NAME ARG ...) #'(NAME ARG ...)) + +(define #'(expression ITEM) #'ITEM) +(define #'(unsignedexpr ITEM) #'ITEM) +(define #'(term ITEM) #'ITEM) +(define #'(factor ITEM) #'ITEM) +(define #'(number ITEM) #'ITEM) + +(define #'(printitem EXPR-OR-STRING) #'EXPR-OR-STRING) + +(define #'(printlist ITEM-OR-SEPARATOR ...) #'(list ITEM-OR-SEPARATOR ...)) + +(define (PRINT args) + (for-each display args) + (displayln "")) + +(define (GOTO where) + where) -(define-cases #'statement - [#'(_ "PRINT" EXPR-LIST) #'(λ _ (begin (for-each display EXPR-LIST) (displayln "")))]) (define-cases #'expr-list [#'(_ EXPR ...) #'(list EXPR ...)]) diff --git a/beautiful-racket/br/basic/parser.rkt b/beautiful-racket/br/basic/parser.rkt index a93afe7..458e855 100644 --- a/beautiful-racket/br/basic/parser.rkt +++ b/beautiful-racket/br/basic/parser.rkt @@ -1,32 +1,55 @@ #lang ragg +;; adapted from http://www.ittybittycomputers.com/IttyBitty/TinyBasic/TBuserMan.txt basic-program : line* -line : CR | NUMBER statement CR | statement CR -| NUMBER statement | statement +line : NUMBER statement CR | statement CR | CR -statement : "PRINT" expr-list -| "IF" expression relop expression "THEN" statement -| "GOTO" expression -| "INPUT" var-list +statement : "PRINT" printlist +| "PR" printlist +| "INPUT" varlist | "LET" var "=" expression +| var "=" expression +| "GOTO" expression | "GOSUB" expression | "RETURN" +| "IF" expression relop expression "THEN" statement +| "IF" expression relop expression statement +;| "REM" commentstring ; todo: implement in tokenizer | "CLEAR" -| "LIST" | "RUN" -| "END" +| "RUN" exprlist +| "LIST" +| "LIST" exprlist + +printlist : printitem [(":" | separator printlist)] -expr-list : (STRING | expression) ("," (STRING | expression) )* +printitem : expression | STRING -var-list : var ("," var)* +varlist: var ["," varlist] -expression : term (("+"|"-") term)* +exprlist : expression ["," exprlist] -term : factor (("*"|"/") factor)* +expression : [("+"|"-")] unsignedexpr -factor : var | NUMBER | (expression) +unsignedexpr : term [("+"|"-") unsignedexpr] + +term : factor [("*"|"/") term] + +factor : var +| number +| "(" expression ")" +| function + +function : "RND(" expression ")" +| "USR(" exprlist ")" + +number : NUMBER + +separator : "," | ";" var : UPPERCASE -relop : "<" (">"|"="|"ε") | ">" ("<"|"="|"ε") | "=" \ No newline at end of file +digit: DIGIT + +relop : "<" [("="|">")] | ">" [("="|"<")] | "=" \ No newline at end of file diff --git a/beautiful-racket/br/basic/test.rkt b/beautiful-racket/br/basic/test.rkt index 4ef2bde..d634193 100644 --- a/beautiful-racket/br/basic/test.rkt +++ b/beautiful-racket/br/basic/test.rkt @@ -1,2 +1,7 @@ #lang br/basic -20 GOTO 10 +10 PRINT "shit" +20 PRINT "bird" +25 PRINT "dork" +30 GOTO 10 + + diff --git a/beautiful-racket/br/basic/tokenizer.rkt b/beautiful-racket/br/basic/tokenizer.rkt index 18ad12b..c16bbbf 100644 --- a/beautiful-racket/br/basic/tokenizer.rkt +++ b/beautiful-racket/br/basic/tokenizer.rkt @@ -12,7 +12,7 @@ ["\n" (token 'CR ''end)] [(union "PRINT" "IF" "THEN" "GOTO" "INPUT" "LET" "GOSUB" "RETURN" - "CLEAR" "LIST" "RUN" "END") lexeme] + "CLEAR" "LIST" "RUN" "END") (string->symbol lexeme)] ;; this only matches integers [(repetition 1 +inf.0 numeric) (token 'NUMBER (string->number lexeme))] [(char-set ",+-ε*/<>=") lexeme]