#cs (module grammar mzscheme (require (lib "class.ss")) ;; Constructs to create and access grammars, the internal ;; representation of the input to the parser generator. (provide make-item make-term make-non-term make-prec make-prod ;; Things that work on items start-item? item-prod item->string sym-at-dot move-dot-right itemstring non-term? term? non-termbit-vector term-index non-term-index ;; Things that work on precs prec-num prec-assoc grammar% ;; Things that work on productions prod-index prod-prec prod-rhs prod-lhs prod-action) ;;---------------------- LR items -------------------------- ;; LR-item = (make-item production nat) ;; The dot-pos field is the index of the element in the rhs ;; of prod that the dot immediately preceeds. ;; Thus 0 <= dot-pos <= (vector-length rhs). (define-struct item (prod dot-pos) (make-inspector)) ;; item bool ;; Lexicographic comparison on two items. (define (item bool ;; The start production always has index 0 (define (start-item? i) (= 0 (non-term-index (prod-lhs (item-prod i))))) ;; move-dot-right: LR-item -> LR-item | #f ;; moves the dot to the right in the item, unless it is at its ;; rightmost, then it returns false (define (move-dot-right i) (cond ((= (item-dot-pos i) (vector-length (prod-rhs (item-prod i)))) #f) (else (make-item (item-prod i) (add1 (item-dot-pos i)))))) ;; sym-at-dot: LR-item -> gram-sym | #f ;; returns the symbol after the dot in the item or #f if there is none (define (sym-at-dot i) (let ((dp (item-dot-pos i)) (rhs (prod-rhs (item-prod i)))) (cond ((= dp (vector-length rhs)) #f) (else (vector-ref rhs dp))))) ;; print-item: LR-item -> (define (item->string it) (let ((print-sym (lambda (i) (let ((gs (vector-ref (prod-rhs (item-prod it)) i))) (cond ((term? gs) (format "~a " (term-sym gs))) (else (format "~a " (non-term-sym gs)))))))) (string-append (format "~a -> " (non-term-sym (prod-lhs (item-prod it)))) (let loop ((i 0)) (cond ((= i (vector-length (prod-rhs (item-prod it)))) (if (= i (item-dot-pos it)) ". " "")) ((= i (item-dot-pos it)) (string-append ". " (print-sym i) (loop (add1 i)))) (else (string-append (print-sym i) (loop (add1 i))))))))) ;; --------------------- Grammar Symbols -------------------------- ;; gram-sym = (make-term symbol int prec) ;; | (make-non-term symbol int) ;; Each term has a unique index 0 <= index < number of terms ;; Each non-term has a unique index 0 <= index < number of non-terms (define-struct term (sym index prec) (make-inspector)) (define-struct non-term (sym index) (make-inspector)) (define (non-termstring gs) (symbol->string (gram-sym-symbol gs))) ;; term-list->bit-vector: term list -> int ;; Creates a number where the nth bit is 1 if the term with index n is in ;; the list, and whose nth bit is 0 otherwise (define (term-list->bit-vector terms) (cond ((null? terms) 0) (else (bitwise-ior (arithmetic-shift 1 (term-index (car terms))) (term-list->bit-vector (cdr terms)))))) ;; ------------------------- Precedences --------------------------- ;; a precedence declaration. the sym should be 'left 'right or 'nonassoc ;; prec = (make-prec int sym) ;; | #f (define-struct prec (num assoc) (make-inspector)) ;; ------------------------- Grammar ------------------------------ (define grammar% (class object% (super-instantiate ()) ;; prods: production list list ;; where the nth element in the outermost list is the list of productions with the nth non-term as lhs (init prods) ;; nullable-non-terms is indexed by the non-term-index and is true iff non-term is nullable (init-field terms non-terms nullable-non-terms end-terms) ;; indexed by the index of the non-term - contains the list of productions for that non-term (define nt->prods (list->vector prods)) ;; list of all productions (define all-prods (apply append prods)) (define num-prods (length all-prods)) (define num-terms (length terms)) (define num-non-terms (length non-terms)) (define/public (get-num-terms) num-terms) (define/public (get-num-non-terms) num-non-terms) (define/public (get-prods-for-non-term nt) (vector-ref nt->prods (non-term-index nt))) (define/public (get-prods) all-prods) (define/public (get-init-prod) (car (vector-ref nt->prods 0))) (define/public (get-terms) terms) (define/public (get-non-terms) non-terms) (define/public (get-num-prods) num-prods) (define/public (get-end-terms) end-terms) (define/public (nullable-non-term? nt) (vector-ref nullable-non-terms (non-term-index nt))) (define/public (nullable-after-dot? item) (let* ((rhs (prod-rhs (item-prod item))) (prod-length (vector-length rhs))) (let loop ((i (item-dot-pos item))) (cond ((< i prod-length) (if (and (non-term? (vector-ref rhs i)) (nullable-non-term? (vector-ref rhs i))) (loop (add1 i)) #f)) ((= i prod-length) #t))))))) ;; ------------------------ Productions --------------------------- ;; production = (make-prod non-term (gram-sym vector) int prec syntax-object) ;; Each production has a unique index 0 <= index <= number of productions (define-struct prod (lhs rhs index prec action) (make-inspector)) )