fisl

fisl is scheme lox
git clone git://git.alexkarle.com.com/fisl
Log | Files | Refs | README | LICENSE

commit 19417d286621943eb6406d6b938c8ee63b0f08ac (patch)
parent 11be32bbaf9d22ba7ff60767326ef152810f9c7b
Author: Alex Karle <alex@alexkarle.com>
Date:   Mon,  7 Nov 2022 22:37:47 -0500

Implement global variable declaration and access

ch8.2 and ch8.3

Diffstat:
Minterpreter.scm | 26++++++++++++++++++++++++--
Mparser.scm | 50++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/interpreter.scm b/interpreter.scm @@ -1,8 +1,12 @@ ;; interpreter.scm -- evaluates parsed statements -(import (chicken format)) +(import + srfi-69 ; hash-tables + (chicken format)) (define interpreter-abort #f) +(define global-env (make-hash-table)) + (define (runtime-err! msg) (err! msg) (interpreter-abort #f)) @@ -31,6 +35,12 @@ ((literal? expr) (literal-value expr)) ((grouping? expr) (evaluate (grouping-expression expr))) + ((variable? expr) + (let ((tok (variable-name expr))) + (if (hash-table-exists? global-env (token-lexeme tok)) + (hash-table-ref global-env (token-lexeme tok)) + (runtime-err! (format "~Unbound variable ~A at line ~A" + (token-lexeme tok) (token-line tok)))))) ((unary? expr) (let ((right (evaluate (unary-right expr))) (op (token-type (unary-operator expr)))) @@ -79,7 +89,19 @@ (define (execute stmt) (cond ((print-stmt? stmt) - (print (evaluate (print-stmt-value stmt))) + (let ((res (evaluate (print-stmt-value stmt)))) + (print (cond + ((null? res) "nil") + ((eq? res #f) "false") + ((eq? res #t) "true") + (else res))) + '())) + ((var-stmt? stmt) + (let ((value + (if (null? (var-stmt-init stmt)) + '() + (evaluate (var-stmt-init stmt))))) + (hash-table-set! global-env (token-lexeme (var-stmt-name stmt)) value)) '()) (else (runtime-err! (format "Unknown stmt ~A" stmt))))) diff --git a/parser.scm b/parser.scm @@ -24,6 +24,11 @@ (token-lexeme (unary-operator x)) (unary-right x)))) +(define-record variable name) +(set-record-printer! variable + (lambda (x out) (fprintf out "~A" (token-lexeme x)))) + + (define-record print-stmt value) (set-record-printer! print-stmt (lambda (x out) @@ -34,11 +39,16 @@ (lambda (x out) (fprintf out "(expr ~A)" (expr-stmt-value x)))) +(define-record var-stmt name init) +(set-record-printer! var-stmt + (lambda (x out) + (fprintf out "(var ~A ~A)" (var-stmt-name x) (var-stmt-init x)))) + + (define (top-type? tokens types) (memq (token-type (car tokens)) types)) (define (parse tokens fname) - (define (panic tok msg) (if (eq? (token-type tok) 'EOF) (err! (format "~A:~A:~A ~A" fname (token-line tok) "Error at end." msg)) @@ -48,9 +58,29 @@ "Error at" (token-lexeme tok) msg))) - ; TODO: synchronize instead of abort + ;; TODO: synchronize instead of abort (parser-abort #f)) + (define (declaration tokens) + (if (top-type? tokens '(VAR)) + ;; TODO: sync on failure + (var-decl (cdr tokens)) + (statement tokens))) + + (define (var-decl tokens) + (if (top-type? tokens '(IDENTIFIER)) + (let* ((ret + (if (top-type? (cdr tokens) '(EQUAL)) + (expression '() (cddr tokens)) + (cons '() (cdr tokens)))) + (init (car ret)) + (toks (cdr ret))) + (if (top-type? toks '(SEMICOLON)) + (cons (make-var-stmt (car tokens) init) + (cdr toks)) + (panic (car toks) "Expected ';' after variable declaration"))) + (panic (car tokens) "expected variable name"))) + (define (statement tokens) (if (top-type? tokens '(PRINT)) (print-statement (cdr tokens)) @@ -74,7 +104,7 @@ (equality expr toks)) (define (equality expr toks) - ; (print (format "equality ~S ~S" expr toks)) + ;; (print (format "equality ~S ~S" expr toks)) (let ((ret (comparison expr toks))) (let loop ((e (car ret)) (ts (cdr ret))) (if (top-type? ts '(BANG_EQUAL EQUAL_EQUAL)) @@ -83,7 +113,7 @@ (cons e ts))))) (define (comparison expr toks) - ; (print (format "comparison ~S ~S" expr toks)) + ;; (print (format "comparison ~S ~S" expr toks)) (let ((ret (term expr toks))) (let loop ((e (car ret)) (ts (cdr ret))) (if (top-type? ts '(GREATER GREATER_EQUAL LESS LESS_EQUAL)) @@ -92,7 +122,7 @@ (cons e ts))))) (define (term expr toks) - ; (print (format "term ~S ~S" expr toks)) + ;; (print (format "term ~S ~S" expr toks)) (let ((ret (factor expr toks))) (let loop ((e (car ret)) (ts (cdr ret))) (if (top-type? ts '(MINUS PLUS)) @@ -101,7 +131,7 @@ (cons e ts))))) (define (factor expr toks) - ; (print (format "factor ~S ~S" expr toks)) + ;; (print (format "factor ~S ~S" expr toks)) (let ((ret (unary expr toks))) (let loop ((e (car ret)) (ts (cdr ret))) (if (top-type? ts '(SLASH STAR)) @@ -110,21 +140,21 @@ (cons e ts))))) (define (unary expr toks) - ; (print (format "unary ~S ~S" expr toks)) + ;; (print (format "unary ~S ~S" expr toks)) (if (top-type? toks '(BANG MINUS)) (let ((ret (unary expr (cdr toks)))) (cons (make-unary (car toks) (car ret)) (cdr ret))) (primary expr toks))) (define (primary expr toks) - ; (print (format "primary ~S ~S" expr toks)) + ;; (print (format "primary ~S ~S" expr toks)) (cond ((top-type? toks '(FALSE)) (cons (make-literal #f) (cdr toks))) ((top-type? toks '(TRUE)) (cons (make-literal #t) (cdr toks))) - ; XXX: nil vs false? ((top-type? toks '(NIL)) (cons (make-literal '()) (cdr toks))) ((top-type? toks '(NUMBER STRING)) (cons (make-literal (token-literal (car toks))) (cdr toks))) + ((top-type? toks '(IDENTIFIER)) (cons (make-variable (car toks)) (cdr toks))) ((top-type? toks '(LEFT_PAREN)) (let ((ret (expression expr (cdr toks)))) (if (eq? (token-type (cadr ret)) 'RIGHT_PAREN) @@ -137,6 +167,6 @@ (set! parser-abort cc) (let loop ((toks tokens)) (if (not (top-type? toks '(EOF))) - (let ((ret (statement toks))) + (let ((ret (declaration toks))) (cons (car ret) (loop (cdr ret)))) '())))))