improve handling of negative numbers; add `DEF`

pull/2/head
Matthew Butterick 9 years ago
parent ce1b56d019
commit b83a09e6af

@ -75,7 +75,7 @@
[(statement ID "=" EXPR) #'(set! ID EXPR)] [(statement ID "=" EXPR) #'(set! ID EXPR)]
[(statement PROC-NAME . ARGS) [(statement PROC-NAME . ARGS)
(with-pattern (with-pattern
([PROC-ID (prefix-id "basic:" #'PROC-NAME)]) ([PROC-ID (prefix-id "basic:" #'PROC-NAME)])
#'(PROC-ID . ARGS))]) #'(PROC-ID . ARGS))])
(define-macro basic:if (define-macro basic:if
@ -104,7 +104,7 @@
#'(cond->int (equal? SUM COMP-EXPR))] ; special case because `=` is overloaded in basic #'(cond->int (equal? SUM COMP-EXPR))] ; special case because `=` is overloaded in basic
[(_ SUM OP-STR COMP-EXPR) [(_ SUM OP-STR COMP-EXPR)
(with-pattern (with-pattern
([OP (replace-context #'here (prefix-id #'OP-STR))]) ([OP (replace-context #'here (prefix-id #'OP-STR))])
#'(cond->int (OP SUM COMP-EXPR)))]) #'(cond->int (OP SUM COMP-EXPR)))])
(define <> (compose1 not equal?)) (define <> (compose1 not equal?))
@ -115,25 +115,44 @@
[(_ SUM "-" PRODUCT) #'(- SUM PRODUCT)]) [(_ SUM "-" PRODUCT) #'(- SUM PRODUCT)])
(define-macro product (define-macro product
[(_ "-" VALUE) #'(- VALUE)]
[(_ VALUE) #'VALUE] [(_ VALUE) #'VALUE]
[(_ PRODUCT "*" VALUE) #'(* PRODUCT VALUE)] [(_ PRODUCT "*" VALUE) #'(* PRODUCT VALUE)]
[(_ PRODUCT "/" VALUE) #'(/ PRODUCT VALUE)]) [(_ PRODUCT "/" VALUE) #'(/ PRODUCT VALUE)])
(define-macro number
[(_ "-" NUM) #'(- NUM)]
[(_ NUM) #'NUM])
(define-macro id-val
[(_ "-" ID) #'(- ID)]
[(_ ID) #'ID])
(define print-list list) (define print-list list)
;; todo: make it work more like http://www.antonis.de/qbebooks/gwbasman/PRINT.html
(define (basic:print [args #f]) (define (basic:print [args #f])
(match args (match args
[#f (displayln "")] [#f (displayln "")]
[(list print-list-item ... ";" pl) (begin (for-each display print-list-item) [(list print-list-item ... ";" pl) (begin (for-each (λ(pli)
(let ([pli (if (number? pli)
(format "~a " pli)
pli)])
(display pli))) print-list-item)
(basic:print pl))] (basic:print pl))]
[(list print-list-item ... ";") (for-each display print-list-item)] [(list print-list-item ... ";") (for-each display print-list-item)]
[(list print-list-item ...) (for-each displayln print-list-item)])) [(list print-list-item ...) (for-each displayln print-list-item)]))
;; todo: make it work more like http://www.antonis.de/qbebooks/gwbasman/TAB.html
;; need to track current line position
(define (TAB num) (make-string num #\space)) (define (TAB num) (make-string num #\space))
(define-macro (INT _ARG ...) #'(inexact->exact (truncate (expr _ARG ...)))) (define-macro (INT _ARG ...) #'(inexact->exact (truncate (expr _ARG ...))))
(define (SIN num) (sin num)) (define (SIN num) (sin num))
(define (ABS num) (inexact->exact (abs num))) (define (ABS num) (inexact->exact (abs num)))
(define (RND num) (* (random) num)) (define (RND num) (* (random) num))
(define (EXP num) (exp num))
(define (SQR num) (sqrt num))
(define-macro basic:input (define-macro basic:input
[(_ (print-list . PL-ITEMS) ID ...) [(_ (print-list . PL-ITEMS) ID ...)
@ -163,6 +182,10 @@
(define (pop-for-stack) (define (pop-for-stack)
(set! for-stack (cdr for-stack))) (set! for-stack (cdr for-stack)))
(define (in-closed-interval? x left right)
(define cmp (if (< left right) <= >=))
(cmp left x right))
(define-macro basic:for (define-macro basic:for
[(_ VAR START-VALUE END-VALUE) [(_ VAR START-VALUE END-VALUE)
#'(basic:for VAR START-VALUE END-VALUE 1)] #'(basic:for VAR START-VALUE END-VALUE 1)]
@ -173,7 +196,7 @@
(push-for-stack (cons 'VAR (push-for-stack (cons 'VAR
(λ () ; thunk that increments counter & teleports back to beginning of loop (λ () ; thunk that increments counter & teleports back to beginning of loop
(define next-val (+ VAR STEP-VALUE)) (define next-val (+ VAR STEP-VALUE))
(if (<= next-val END-VALUE) (if (next-val . in-closed-interval? . START-VALUE END-VALUE)
(begin (begin
(set! VAR next-val) (set! VAR next-val)
(return-k #f)) ; return value for subsequent visits to line (return-k #f)) ; return value for subsequent visits to line
@ -189,3 +212,6 @@
(define-macro (basic:next VAR ...) (define-macro (basic:next VAR ...)
#'(handle-next 'VAR ...)) #'(handle-next 'VAR ...))
(define-macro (basic:def DEF-ID LAMBDA-ID EXPR)
#'(set! DEF-ID (λ (LAMBDA-ID) EXPR)))

@ -4,7 +4,8 @@ basic-program : line*
line: NUMBER statement [/":" statement]* line: NUMBER statement [/":" statement]*
statement : "end" | "stop" statement : "def" id /"(" id /")" /"=" expr
| "end" | "stop"
| "gosub" expr | "gosub" expr
| "goto" expr | "goto" expr
| "if" expr /"then" (statement | expr) [/"else" (statement | expr)] | "if" expr /"then" (statement | expr) [/"else" (statement | expr)]
@ -25,12 +26,16 @@ sum : [sum ("+" | "-")] product
product : [product ("*" | "/")] value product : [product ("*" | "/")] value
@value : id @value : id-val
| id-expr | id-expr
| /"(" expr /")" | /"(" expr /")"
| NUMBER | number
| STRING | STRING
/id-expr : id [/"(" expr [/"," expr]* /")"] /id-expr : id [/"(" expr [/"," expr]* /")"]
@id : ID @id : ID
id-val : ["-"] id
number : ["-"] NUMBER

@ -0,0 +1,5 @@
#lang br/demo/basic
5 print 30; "foo"
10 PRINT TAB(10);"*";
20 PRINT TAB(15);"*";

@ -6,8 +6,9 @@
(define-lex-abbrevs (define-lex-abbrevs
(natural (repetition 1 +inf.0 numeric)) (natural (repetition 1 +inf.0 numeric))
(number (union (seq (? "-") natural) ;; don't lex the leading "-": muddles "-X" and "Y-X"
(seq (? "-") (? natural) (seq "." natural)))) (number (union (seq natural)
(seq (? natural) (seq "." natural))))
(quoted-string (seq "\"" (repetition 0 +inf.0 (char-complement "\"")) "\""))) (quoted-string (seq "\"" (repetition 0 +inf.0 (char-complement "\"")) "\"")))
(define (tokenize input-port) (define (tokenize input-port)
@ -15,19 +16,19 @@
(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)]
[(union #\tab #\space #\newline [(union #\tab #\space #\newline
(seq number " REM" (repetition 0 +inf.0 (char-complement #\newline)) #\newline)) (get-token input-port)] (seq number " REM" (repetition 0 +inf.0 (char-complement #\newline)) #\newline)) (get-token input-port)]
[(union "PRINT" "print" "FOR" "for" "TO" "to" "STEP" "step" "IF" "if" [(union "PRINT" "print" "FOR" "for" "TO" "to" "STEP" "step" "IF" "if"
"GOTO" "goto" "INPUT" "input" "LET" "let" "NEXT" "next" "GOTO" "goto" "INPUT" "input" "LET" "let" "NEXT" "next"
"RETURN" "return" "CLEAR" "clear" "LIST" "list" "RUN" "run" "RETURN" "return" "CLEAR" "clear" "LIST" "list" "RUN" "run"
"END" "end" "THEN" "then" "ELSE" "else" "GOSUB" "gosub" "END" "end" "THEN" "then" "ELSE" "else" "GOSUB" "gosub"
"AND" "and" "OR" "or" "STOP" "stop" "LET" "let" "AND" "and" "OR" "or" "STOP" "stop" "LET" "let" "DEF" "def"
";" "=" "(" ")" "+" "-" "*" "/" ";" "=" "(" ")" "+" "-" "*" "/"
"<=" ">=" "<>" "<" ">" "=" ":" ",") (string-downcase lexeme)] "<=" ">=" "<>" "<" ">" "=" ":" ",") (string-downcase lexeme)]
[(union ",") (get-token input-port)]
[number (token 'NUMBER (string->number lexeme))] [number (token 'NUMBER (string->number lexeme))]
[(seq (repetition 1 +inf.0 upper-case) (? "$")) (token 'ID (string->symbol lexeme))] [(seq upper-case (repetition 0 +inf.0 (or upper-case numeric)) (? "$")) (token 'ID (string->symbol lexeme))]
[upper-case (token 'UPPERCASE (string->symbol lexeme))]
[quoted-string (token 'STRING (string-trim lexeme "\""))])) [quoted-string (token 'STRING (string-trim lexeme "\""))]))
(get-token input-port)) (get-token input-port))
next-token) next-token)

Loading…
Cancel
Save