From c8ebca0bda25ee9844d103379965a7806fbdb690 Mon Sep 17 00:00:00 2001 From: "waldemar%netscape.com" Date: Tue, 7 Dec 1999 22:06:43 +0000 Subject: [PATCH] Fixed bug in forbidden terminalset calculations --- js/semantics/Grammar.lisp | 19 +++++++++++++++---- js/semantics/Parser.lisp | 23 +++++++++++++++++------ js2/semantics/Grammar.lisp | 19 +++++++++++++++---- js2/semantics/Parser.lisp | 23 +++++++++++++++++------ 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/js/semantics/Grammar.lisp b/js/semantics/Grammar.lisp index 48bfc1db67e7..a79dfec6fd57 100644 --- a/js/semantics/Grammar.lisp +++ b/js/semantics/Grammar.lisp @@ -601,7 +601,7 @@ (:predicate laitem?)) (grammar nil :type grammar :read-only t) ;The grammar to which this laitem belongs (item nil :type item :read-only t) ;The item to which this laitem corresponds - (forbidden nil :type terminalset :read-only t) ;A set of terminals that must not occur after the dot because of lookahead-constraints + (forbidden nil :type terminalset) ;A set of terminals that must not occur after the dot because of lookahead-constraints (lookaheads nil :type terminalset) ;Set of lookahead terminals (propagates nil :type list)) ;List of (laitem . mask) to which lookaheads propagate from this laitem (see note below) ;When parsing a LALR(1) grammar, propagates contains all laitems (in this and other states) @@ -708,9 +708,20 @@ ; Return the transition for the given terminal or nil if there is none. (defun state-transition (state terminal) - (cdr - (or (assoc terminal (state-transitions state) :test *grammar-symbol-=*) - (assoc nil (state-transitions state) :test *grammar-symbol-=*)))) + (let ((transitions (state-transitions state))) + (cdr + (or (assoc terminal transitions :test *grammar-symbol-=*) + (assoc nil transitions :test *grammar-symbol-=*))))) + + +; If the state has the same transition for every terminal, return that transition; +; otherwise return nil. +(defun state-only-transition (state) + (let ((transitions (state-transitions state))) + (and transitions + (null (cdr transitions)) + (null (caar transitions)) + (cdar transitions)))) ; If all outgoing transitions from the state are the same reduction, return that diff --git a/js/semantics/Parser.lisp b/js/semantics/Parser.lisp index 62bf46424b2e..43dcae2b4550 100644 --- a/js/semantics/Parser.lisp +++ b/js/semantics/Parser.lisp @@ -38,23 +38,27 @@ ; initial-lookaheads. (defun make-state (grammar kernel kernel-item-alist mode number initial-lookaheads) (let ((laitems nil) - (laitems-hash (make-hash-table :test #'eq))) + (laitems-hash (make-hash-table :test #'eq)) + (laitems-maybe-forbidden nil)) ;Association list of: laitem -> terminalset of potentially forbidden terminals; missing means *empty-terminalset* (labels ;Create a laitem for this item and add the association item->laitem to the laitems-hash ;hash table if it's not there already. Regardless of whether a new laitem was created, ;update the laitem's lookaheads to also include the given lookaheads. ;forbidden is a terminalset of terminals that must not occur immediately after the dot in this ;laitem. The forbidden set is inherited from constraints in parent laitems in the same state. + ;maybe-forbidden is an upper bounds on the forbidden lookaheads in this laitem. ;If prev is non-null, update (laitem-propagates prev) to include the laitem and the given ;passthrough terminalset if it's not already included there. ;If a new laitem was created and its first symbol after the dot exists and is a ;nonterminal A, recursively close items A->.rhs corresponding to all rhs's in the ;grammar's rule for A. - ((close-item (item forbidden lookaheads prev passthroughs) + ((close-item (item forbidden maybe-forbidden lookaheads prev passthroughs) (let ((production (item-production item)) (dot (item-dot item)) (laitem (gethash item laitems-hash))) - (terminalset-union-f forbidden (terminalset-complement (general-production-constraint production dot))) + (let ((extra-forbidden (terminalset-complement (general-production-constraint production dot)))) + (terminalset-union-f forbidden extra-forbidden) + (terminalset-union-f maybe-forbidden extra-forbidden)) (unless (terminalset-empty? forbidden) (multiple-value-bind (dot-lookaheads dot-passthroughs) (string-initial-terminals grammar (item-unseen item) (production-constraints production) (item-dot item) t) @@ -69,25 +73,32 @@ ;Convert forbidden into a canonical format by removing terminals that cannot begin this item's expansion anyway. (terminalset-intersection-f forbidden dot-initial)))) (if laitem - (progn - (unless (terminalset-= forbidden (laitem-forbidden laitem)) + (let ((laitem-maybe-forbidden-entry (assoc laitem laitems-maybe-forbidden)) + (new-forbidden (terminalset-union forbidden (laitem-forbidden laitem)))) + (when laitem-maybe-forbidden-entry + (terminalset-intersection-f (cdr laitem-maybe-forbidden-entry) maybe-forbidden)) + (unless (terminalset-<= new-forbidden (or (cdr laitem-maybe-forbidden-entry) *empty-terminalset*)) (error "Two laitems in the same state differing only in forbidden initial terminal constraints: ~S" laitem)) + (setf (laitem-forbidden laitem) new-forbidden) (terminalset-union-f (laitem-lookaheads laitem) lookaheads)) (let ((item-next-symbol (item-next-symbol item))) (setq laitem (allocate-laitem grammar item forbidden lookaheads)) (push laitem laitems) (setf (gethash item laitems-hash) laitem) + (unless (terminalset-empty? maybe-forbidden) + (push (cons laitem maybe-forbidden) laitems-maybe-forbidden)) (when (nonterminal? item-next-symbol) (multiple-value-bind (next-lookaheads next-passthroughs) (string-initial-terminals grammar (rest (item-unseen item)) (production-constraints production) (1+ dot) nil) (let ((next-prev (and (not (terminalset-empty? next-passthroughs)) laitem))) (dolist (production (rule-productions (grammar-rule grammar item-next-symbol))) - (close-item (make-item grammar production 0) forbidden next-lookaheads next-prev next-passthroughs))))))) + (close-item (make-item grammar production 0) forbidden maybe-forbidden next-lookaheads next-prev next-passthroughs))))))) (when prev (laitem-add-propagation prev laitem passthroughs))))) (dolist (acons kernel-item-alist) (close-item (car acons) + *empty-terminalset* *empty-terminalset* (if (eq mode :canonical-lr-1) (cdr acons) initial-lookaheads) (and (eq mode :lalr-1) (cdr acons)) diff --git a/js2/semantics/Grammar.lisp b/js2/semantics/Grammar.lisp index 48bfc1db67e7..a79dfec6fd57 100644 --- a/js2/semantics/Grammar.lisp +++ b/js2/semantics/Grammar.lisp @@ -601,7 +601,7 @@ (:predicate laitem?)) (grammar nil :type grammar :read-only t) ;The grammar to which this laitem belongs (item nil :type item :read-only t) ;The item to which this laitem corresponds - (forbidden nil :type terminalset :read-only t) ;A set of terminals that must not occur after the dot because of lookahead-constraints + (forbidden nil :type terminalset) ;A set of terminals that must not occur after the dot because of lookahead-constraints (lookaheads nil :type terminalset) ;Set of lookahead terminals (propagates nil :type list)) ;List of (laitem . mask) to which lookaheads propagate from this laitem (see note below) ;When parsing a LALR(1) grammar, propagates contains all laitems (in this and other states) @@ -708,9 +708,20 @@ ; Return the transition for the given terminal or nil if there is none. (defun state-transition (state terminal) - (cdr - (or (assoc terminal (state-transitions state) :test *grammar-symbol-=*) - (assoc nil (state-transitions state) :test *grammar-symbol-=*)))) + (let ((transitions (state-transitions state))) + (cdr + (or (assoc terminal transitions :test *grammar-symbol-=*) + (assoc nil transitions :test *grammar-symbol-=*))))) + + +; If the state has the same transition for every terminal, return that transition; +; otherwise return nil. +(defun state-only-transition (state) + (let ((transitions (state-transitions state))) + (and transitions + (null (cdr transitions)) + (null (caar transitions)) + (cdar transitions)))) ; If all outgoing transitions from the state are the same reduction, return that diff --git a/js2/semantics/Parser.lisp b/js2/semantics/Parser.lisp index 62bf46424b2e..43dcae2b4550 100644 --- a/js2/semantics/Parser.lisp +++ b/js2/semantics/Parser.lisp @@ -38,23 +38,27 @@ ; initial-lookaheads. (defun make-state (grammar kernel kernel-item-alist mode number initial-lookaheads) (let ((laitems nil) - (laitems-hash (make-hash-table :test #'eq))) + (laitems-hash (make-hash-table :test #'eq)) + (laitems-maybe-forbidden nil)) ;Association list of: laitem -> terminalset of potentially forbidden terminals; missing means *empty-terminalset* (labels ;Create a laitem for this item and add the association item->laitem to the laitems-hash ;hash table if it's not there already. Regardless of whether a new laitem was created, ;update the laitem's lookaheads to also include the given lookaheads. ;forbidden is a terminalset of terminals that must not occur immediately after the dot in this ;laitem. The forbidden set is inherited from constraints in parent laitems in the same state. + ;maybe-forbidden is an upper bounds on the forbidden lookaheads in this laitem. ;If prev is non-null, update (laitem-propagates prev) to include the laitem and the given ;passthrough terminalset if it's not already included there. ;If a new laitem was created and its first symbol after the dot exists and is a ;nonterminal A, recursively close items A->.rhs corresponding to all rhs's in the ;grammar's rule for A. - ((close-item (item forbidden lookaheads prev passthroughs) + ((close-item (item forbidden maybe-forbidden lookaheads prev passthroughs) (let ((production (item-production item)) (dot (item-dot item)) (laitem (gethash item laitems-hash))) - (terminalset-union-f forbidden (terminalset-complement (general-production-constraint production dot))) + (let ((extra-forbidden (terminalset-complement (general-production-constraint production dot)))) + (terminalset-union-f forbidden extra-forbidden) + (terminalset-union-f maybe-forbidden extra-forbidden)) (unless (terminalset-empty? forbidden) (multiple-value-bind (dot-lookaheads dot-passthroughs) (string-initial-terminals grammar (item-unseen item) (production-constraints production) (item-dot item) t) @@ -69,25 +73,32 @@ ;Convert forbidden into a canonical format by removing terminals that cannot begin this item's expansion anyway. (terminalset-intersection-f forbidden dot-initial)))) (if laitem - (progn - (unless (terminalset-= forbidden (laitem-forbidden laitem)) + (let ((laitem-maybe-forbidden-entry (assoc laitem laitems-maybe-forbidden)) + (new-forbidden (terminalset-union forbidden (laitem-forbidden laitem)))) + (when laitem-maybe-forbidden-entry + (terminalset-intersection-f (cdr laitem-maybe-forbidden-entry) maybe-forbidden)) + (unless (terminalset-<= new-forbidden (or (cdr laitem-maybe-forbidden-entry) *empty-terminalset*)) (error "Two laitems in the same state differing only in forbidden initial terminal constraints: ~S" laitem)) + (setf (laitem-forbidden laitem) new-forbidden) (terminalset-union-f (laitem-lookaheads laitem) lookaheads)) (let ((item-next-symbol (item-next-symbol item))) (setq laitem (allocate-laitem grammar item forbidden lookaheads)) (push laitem laitems) (setf (gethash item laitems-hash) laitem) + (unless (terminalset-empty? maybe-forbidden) + (push (cons laitem maybe-forbidden) laitems-maybe-forbidden)) (when (nonterminal? item-next-symbol) (multiple-value-bind (next-lookaheads next-passthroughs) (string-initial-terminals grammar (rest (item-unseen item)) (production-constraints production) (1+ dot) nil) (let ((next-prev (and (not (terminalset-empty? next-passthroughs)) laitem))) (dolist (production (rule-productions (grammar-rule grammar item-next-symbol))) - (close-item (make-item grammar production 0) forbidden next-lookaheads next-prev next-passthroughs))))))) + (close-item (make-item grammar production 0) forbidden maybe-forbidden next-lookaheads next-prev next-passthroughs))))))) (when prev (laitem-add-propagation prev laitem passthroughs))))) (dolist (acons kernel-item-alist) (close-item (car acons) + *empty-terminalset* *empty-terminalset* (if (eq mode :canonical-lr-1) (cdr acons) initial-lookaheads) (and (eq mode :lalr-1) (cdr acons))