;; Derived from 08/meta/scm.scm -- ;; An implementation of 'META' and 'Precedence Climbing' in Scheme ;; Operator precedence, arity & associativity ;; ;; Initialize (define binary-table (make-hash)) (define unary-table (make-hash)) (define (init-prec table ops) (for-each (lambda (x) (let ([level (car x)]) ; Add operators to hash table (for-each (lambda (op) (hash-set! table op level) ;(printf "~a ~a~n" op level) ) (cdr x))) ) ops)) (init-prec binary-table '[(2 "=" "+=" "-=" "*=" "/=" "%=" "^=") ;... (3 "==" "!=") ;... (4 "|") (5 "&") ; Left out "&&" and "||" (6 "+" "-" "~") (8 "*" "/" "%" "<<" ">>" ">>>") (9 "^")] ) (init-prec unary-table '[(7 "+" "-" "~" "!") (10 "++" "--")] ) (define (binary op) (hash-ref binary-table op #f)) (define (unary op) (hash-ref unary-table op #f)) (define (left-assoc? op) ;;;TODO: += -= etc... and more? ;;;Looks like the highest & lowest precedence levels are left-associative (not (or (equal? op "=") (equal? op "^")))) ;;--------------------------------------------------------------- (define (ctoi d) (- (char->integer d) (char->integer #\0))) (define (digit) "Parse a single decimal digit" (let ((d (match char-numeric?))) (and d (ctoi d)))) (define (number) "Parse a decimal integer" (ws) (let ((n 0) (d 0)) (and (and (setf d (digit)) (setf n d)) (do () ((not (setf d (digit))) n) ; Return n (setf n (+ (* n 10) d)) )))) ;; Indentation (define *ind* 0) (define (push v) (set! *ind* (cons v *ind*))) (define (pop) (let ((v (car *ind*))) (set! *ind* (cdr *ind*)) v)) (define (dent) "Parse leading whitespace... indent/dedent/no change" (do ((n #f)) ((begin (set! n *i*) (do () ((not (match-char #\space)) ;count spaces.. (set! n (- *i* n)))) ;(printf "~n~s ~s~n" *i* n) (when (match-char #\#) ;skip comments (do () ((match (lambda (x) (not (char=? x #\newline))))))) (not (match-char #\newline))) ; Return (cond ((= n (car *ind*)) 0) ((> n (car *ind*)) (push n) 1) ((= n (cadr *ind*)) (pop) -1) (else #f)) ))) (define (indent) (= (dent) 1)) (define (dedent) (= (dent) -1)) (define (samedent) (= (dent) 0)) (define (optarg n) `(#:optional ,n)) (define (restarg n) `(#:rest ,n)) (define (kwarg n) `(#:other-keys ,n)) ;; Expressions (define (Operator) ; Will need to handle 2-4 char operators too, e.g. >>= (let ((op (match (lambda (c) (member c (string->list "+-*/^=")))))) ;(printf "op: ~s~n" op) (and op (list->string (list op))))) (define (Value) (or (number) (let ((x (name)) (y null)) (if x (if (setf y (Parens)) (append x y) x) #f)))) (define (Parens) (let ((__start *i*) (tree null)) (if (and (literal "(") ;(setf tree (or (List Expr0 ",") null)) (setf tree (or (Expr 0) null)) (literal ")")) tree (begin (set! *i* __start) #f)))) (define (P) (let ((__start *i*) (op null) (q 0) (tree null)) (or (and (setf op (Operator)) (setf q (unary op)) (setf tree (Expr q)) (cons op tree)) (begin (set! *i* __start) (or (Value) (Parens)))))) (define (Expr n) ;(printf "EXPR~n") (do ((__start *i*) (op null) (q 0) (tree (P))) ; Until ((begin (set! __start *i*) ;(printf "backtrack=~a~n" backtrack) (not (or (and (setf op (Operator)) (setf q (binary op)) (>= q n)) (begin (set! *i* __start) #f)))) ; Return ;(printf "~s RETURN~n" (list q op tree)) tree) ; Loop ;(printf "~s~n" (list q op tree)) (when (left-assoc? op) (set! q (+ q 1))) (setf tree (list (string->symbol op) tree (Expr q))) )) (define (expr) (Expr 0))