Added support for writable actions

This commit is contained in:
waldemar%netscape.com 2001-10-17 03:57:51 +00:00
Родитель a87844beb8
Коммит f974c090d4
3 изменённых файлов: 417 добавлений и 215 удалений

Просмотреть файл

@ -830,6 +830,7 @@
;;; <value> value of this identifier if it is a variable of type other than ->
;;; <function> value of this identifier if it is a variable of type ->
;;; :value-expr unparsed expression defining the value of this identifier if it is a variable
;;; :mutable if present and non-nil, this identifier is a mutable variable
;;; :type type of this identifier if it is a variable
;;; :type-expr unparsed expression defining the type of this identifier if it is a variable
;;; :tag tag structure if this identifier is a tag
@ -1049,22 +1050,23 @@
;;; TYPES
(deftype typekind ()
'(member ;tag ;parameters
:bottom ;nil ;nil
:void ;nil ;nil
:boolean ;nil ;nil
:integer ;nil ;nil
:rational ;nil ;nil
:finite64 ;nil ;nil ;All non-zero finite 64-bit double-precision floating-point numbers
:character ;nil ;nil
:-> ;nil ;(result-type arg1-type arg2-type ... argn-type)
:string ;nil ;(character)
:vector ;nil ;(element-type)
:list-set ;nil ;(element-type)
:range-set ;nil ;(element-type)
:tag ;tag ;nil
:denormalized-tag ;tag ;nil
:union)) ;nil ;(type ... type) sorted by ascending serial numbers
'(member ;tag ;parameters
:bottom ;nil ;nil
:void ;nil ;nil
:boolean ;nil ;nil
:integer ;nil ;nil
:rational ;nil ;nil
:finite64 ;nil ;nil ;All non-zero finite 64-bit double-precision floating-point numbers
:character ;nil ;nil
:-> ;nil ;(result-type arg1-type arg2-type ... argn-type)
:string ;nil ;(character)
:vector ;nil ;(element-type)
:list-set ;nil ;(element-type)
:range-set ;nil ;(element-type)
:tag ;tag ;nil
:denormalized-tag ;tag ;nil
:union ;nil ;(type ... type) sorted by ascending serial numbers
:writable-cell)) ;nil ;(element-type)
;A denormalized-tag is a singleton tag type whose value carries no meaning.
;
@ -1158,6 +1160,16 @@
(make-type world :denormalized-tag tag nil 'always-true 'always-false))
(declaim (inline make-writable-cell-type))
(defun make-writable-cell-type (world element-type)
(make-type world :writable-cell nil (list element-type) nil nil))
(declaim (inline writable-cell-element-type))
(defun writable-cell-element-type (type)
(assert-true (eq (type-kind type) :writable-cell))
(car (type-parameters type)))
; Return true if the type is a tag type or a union of tag types all of which have a field with
; the given label.
(defun type-has-field (type label)
@ -1593,6 +1605,9 @@
(print-type (pprint-pop) stream)
(pprint-exit-if-list-exhausted)
(format stream " ~:_"))))
(:writable-cell (pprint-logical-block (stream nil :prefix "(" :suffix ")")
(format stream "writable-cell ~@_")
(print-type (writable-cell-element-type type) stream)))
(t (error "Bad typekind ~S" (type-kind type))))))
@ -1719,6 +1734,11 @@
type-exprs)))
; (writable-cell <element-type>)
(defun scan-writable-cell (world allow-forward-references element-type)
(make-writable-cell-type world (scan-type world element-type allow-forward-references)))
; Resolve all forward type references to refer to their target types.
; Signal an error if any unresolved type references remain.
; Only types reachable from some type name are affected. It is the caller's
@ -2115,6 +2135,7 @@
; ; index is the one-based index used to distinguish among identical
; ; symbols in the rhs of a production. The first occurrence of this
; ; symbol has index 1, the second has index 2, and so on.
; ; The occurrence of symbol on the left side of the production has index 0.
local-symbol ;A unique local variable name used to represent the action function's value in the generated lisp code
type ;Type of the action function's value
general-grammar-symbol) ;The general-grammar-symbol corresponding to the index-th instance of symbol in the production's rhs
@ -2133,12 +2154,7 @@
; If the currently generated function is an action for a rule with at least index
; instances of the given grammar-symbol's symbol on the right-hand side, and if action is
; a legal action for that symbol, return three values:
; the name to use from the generated lisp code to refer to the result of calling
; the action on the index-th instance of this symbol;
; the action result's type;
; the general-grammar-symbol corresponding to the index-th instance of this symbol in the rhs.
; Otherwise, return nil.
; a legal action for that symbol, return the type-env-action; otherwise, return nil.
; action must already be world-interned.
(defun type-env-get-action (type-env action symbol index)
(assoc (list* action symbol index) type-env :test #'equal))
@ -2233,6 +2249,8 @@
;;; A range-set of integers or characters (represented by an intset of its elements converted to integers)
;;; A tag (represented by either a keyword or a list (keyword [serial-num] field-value1 ... field-value n));
;;; serial-num is a unique integer present only on mutable tag instances.
;;; A writable-cell (represented by a cons whose car is a flag that is true if the cell is initialized
;;; and cdr is nil or the value)
; Return true if the value appears to have the given tag. This function
@ -2280,6 +2298,10 @@
(:tag (value-has-tag value (type-tag type) shallow))
(:union (some #'(lambda (subtype) (value-has-type value subtype shallow))
(type-parameters type)))
(:writable-cell (and (consp value)
(if (car value)
(or shallow (value-has-type (cdr value) (writable-cell-element-type type)))
(null (cdr value)))))
(t (error "Bad typekind ~S" (type-kind type)))))
@ -2350,6 +2372,9 @@
(when (value-has-type value subtype t)
(print-value value subtype stream)
(return))))
(:writable-cell (if (car value)
(print-value (cdr value) (writable-cell-element-type type) stream)
(write-string "uninitialized" stream)))
(t (error "Bad typekind ~S" (type-kind type)))))
@ -2404,7 +2429,7 @@
(eq (second annotated-expr) (world-find-symbol world special-form))))
; Return the value of the variable with the given symbol.
; Return the value of the global variable with the given symbol.
; Compute the value if the variable was unbound.
; Use the *busy-variables* list to prevent infinite recursion while computing variable values.
(defmacro fetch-value (symbol)
@ -2413,6 +2438,38 @@
(compute-variable-value ',symbol)))
; Store the value into the global variable with the given symbol.
(defmacro store-global-value (symbol value)
`(if (boundp ',symbol)
(setf (symbol-value ',symbol) ,value)
(error "Unbound variable ~S" ',symbol)))
; Generate a lisp expression that will call the given action on the grammar symbol.
; type-env is the type environment.
; Return three values:
; The expression's value (a lisp expression)
; The expression's type
; The annotated value-expr
(defun scan-action-call (type-env action symbol &optional (index 1 index-supplied))
(unless (integerp index)
(error "Production rhs grammar symbol index ~S must be an integer" index))
(let ((symbol-action (type-env-get-action type-env action symbol index)))
(unless symbol-action
(error "Action ~S not found" (list action symbol index)))
(let ((multiple-symbols (type-env-get-action type-env action symbol (if (= index 0) 1 2))))
(when (and (not index-supplied) multiple-symbols)
(error "Ambiguous index in action ~S" (list action symbol)))
(when (and (= index 1)
(not multiple-symbols)
(grammar-symbol-= symbol (assert-non-null (get-type-env-flag type-env :lhs-symbol))))
(setq multiple-symbols t))
(values (type-env-action-local-symbol symbol-action)
(type-env-action-type symbol-action)
(list* 'expr-annotation:action action (type-env-action-general-grammar-symbol symbol-action)
(and multiple-symbols (list index)))))))
; Generate a lisp expression that will compute the value of value-expr.
; type-env is the type environment. The expression may refer to free variables
; present in the type-env.
@ -2459,23 +2516,6 @@
(->-result-type function-type)
(list* 'expr-annotation:call function-annotated-expr arg-annotated-exprs))))))))
;Scan an action call
(scan-action-call (action symbol &optional (index 1 index-supplied))
(unless (integerp index)
(error "Production rhs grammar symbol index ~S must be an integer" index))
(let ((symbol-action (type-env-get-action type-env action symbol index)))
(unless symbol-action
(error "Action ~S not found" (list action symbol index)))
(let ((multiple-symbols (type-env-get-action type-env action symbol 2)))
(when (and (not index-supplied) multiple-symbols)
(error "Ambiguous index in action ~S" (list action symbol)))
(values (type-env-action-local-symbol symbol-action)
(type-env-action-type symbol-action)
(list* 'expr-annotation:action action (type-env-action-general-grammar-symbol symbol-action)
(and (or multiple-symbols
(grammar-symbol-= symbol (assert-non-null (get-type-env-flag type-env :lhs-symbol))))
(list index)))))))
;Scan an interned identifier
(scan-identifier (symbol)
(let ((symbol-binding (type-env-get-local type-env symbol)))
@ -2517,7 +2557,17 @@
(if (and (symbol-action symbol)
(let ((local (type-env-get-local type-env symbol)))
(not (and local (eq (type-kind (type-env-local-type local)) :->)))))
(apply #'scan-action-call symbol rest)
(multiple-value-bind (action-value action-type action-annotated-expr) (apply #'scan-action-call type-env symbol rest)
(if (eq (type-kind action-type) :writable-cell)
(progn
(assert-true (symbolp action-value))
(values
`(if (car ,action-value)
(cdr ,action-value)
(error "Uninitialized writable-cell"))
(writable-cell-element-type action-type)
action-annotated-expr))
(values action-value action-type action-annotated-expr)))
(multiple-value-call #'scan-call (scan-identifier symbol) rest)))))
(multiple-value-call #'scan-call (scan-value world type-env first) rest)))
@ -3607,6 +3657,19 @@
true-type-env))))
;;; Writable Cells
; (writable-cell-of <element-type>)
; Makes an uninitialized writable cell of the given type.
(defun scan-writable-cell-of (world type-env special-form element-type-expr)
(declare (ignore type-env))
(let ((element-type (scan-type world element-type-expr)))
(values
'(cons nil nil)
(make-writable-cell-type world element-type)
(list* 'expr-annotation:special-form special-form))))
;;; ------------------------------------------------------------------------------------------------------
;;; STATEMENT EXPRESSIONS
@ -3653,29 +3716,35 @@
; Compute the initial type-env to use for the given general-production's action code.
; The first cell of the type-env gives the production's lhs nonterminal's symbol;
; the remaining cells give the action arguments in order.
(defun general-production-action-env (grammar general-production)
(let* ((current-indices nil)
; If include-lhs is true, include the lhs's actions with index 0 at the beginning of the
; environment.
(defun general-production-action-env (grammar general-production include-lhs)
(let* ((index-override nil)
(current-indices nil)
(lhs-general-nonterminal (general-production-lhs general-production))
(bound-arguments-alist (nonterminal-sample-bound-argument-alist grammar lhs-general-nonterminal)))
(set-type-env-flag
(mapcan
#'(lambda (general-grammar-symbol)
(let* ((symbol (general-grammar-symbol-symbol general-grammar-symbol))
(index (incf (getf current-indices symbol 0)))
(grammar-symbol (instantiate-general-grammar-symbol bound-arguments-alist general-grammar-symbol)))
(mapcar
#'(lambda (declaration)
(let* ((action-symbol (car declaration))
(action-type (cdr declaration))
(local-symbol (gensym (symbol-name action-symbol))))
(make-type-env-action
(list* action-symbol symbol index)
local-symbol
action-type
general-grammar-symbol)))
(grammar-symbol-signature grammar grammar-symbol))))
(general-production-rhs general-production))
:lhs-symbol (general-grammar-symbol-symbol lhs-general-nonterminal))))
(flet ((general-symbol-action-env (general-grammar-symbol)
(let* ((symbol (general-grammar-symbol-symbol general-grammar-symbol))
(index (or index-override (incf (getf current-indices symbol 0))))
(grammar-symbol (instantiate-general-grammar-symbol bound-arguments-alist general-grammar-symbol)))
(mapcar
#'(lambda (declaration)
(let* ((action-symbol (car declaration))
(action-type (cdr declaration))
(local-symbol (gensym (symbol-name action-symbol))))
(make-type-env-action
(list* action-symbol symbol index)
local-symbol
action-type
general-grammar-symbol)))
(grammar-symbol-signature grammar grammar-symbol)))))
(let ((env (set-type-env-flag
(mapcan #'general-symbol-action-env (general-production-rhs general-production))
:lhs-symbol (general-grammar-symbol-symbol lhs-general-nonterminal))))
(when include-lhs
(setq index-override 0)
(setq env (nconc (general-symbol-action-env lhs-general-nonterminal) env)))
env))))
; Return the number of arguments that a function returned by compute-action-code
@ -3690,13 +3759,7 @@
; Compute the code for evaluating body-expr to obtain the value of one of the
; production's actions. Verify that the result has the given type and that the
; type is the same as type-expr.
; The code is a lambda-expression that takes as arguments the results of all
; defined actions on the production's rhs. The arguments are listed in the
; same order as the grammar symbols in the rhs. If a grammar symbol in the rhs
; has more than one associated action, arguments are used corresponding to all
; of the actions in the same order as they were declared. If a grammar symbol
; in the rhs has no associated actions, no argument is used for it.
(defun compute-action-code (world grammar production action-symbol type-expr body-expr type)
(defun compute-action-code (world production action-symbol type-expr body-expr type initial-env)
(handler-bind (((or error warning)
#'(lambda (condition)
(declare (ignore condition))
@ -3706,17 +3769,67 @@
(unless (type= type type2)
(error "Action declared using type ~A but defined using ~A"
(print-type-to-string type) (print-type-to-string type2))))
(let* ((initial-env (general-production-action-env grammar production))
(args (mapcar #'cadr (cdr initial-env)))
(body-code (scan-typed-value-or-begin world initial-env body-expr type))
(named-body-code (name-lambda body-code
(concatenate 'string (symbol-name (production-name production))
"~" (symbol-name action-symbol))
(world-package world))))
(gen-lambda args named-body-code))))
(let ((body-code (scan-typed-value-or-begin world initial-env body-expr type)))
(name-lambda body-code
(concatenate 'string (symbol-name (production-name production))
"~" (symbol-name action-symbol))
(world-package world)))))
; Return a list of all grammar symbols's symbols that are present in at least one expr-annotation:action
; Compute the body of all grammar actions for this production.
(defun compute-production-code (world grammar production)
(let* ((lhs (production-lhs production))
(n-action-args (n-action-args grammar production))
(initial-env (general-production-action-env grammar production nil))
(args (mapcar #'cadr (cdr initial-env))))
(assert-true (= (length args) n-action-args))
(let* ((result-vars nil)
(code-bindings
(mapcar
#'(lambda (action-binding)
(let ((action-symbol (car action-binding))
(action (cdr action-binding)))
(unless action
(error "Missing action ~S for production ~S" (car action-binding) (production-name production)))
(multiple-value-bind (has-type type) (action-declaration grammar (production-lhs production) action-symbol)
(declare (ignore has-type))
(let ((code (compute-action-code world production action-symbol (action-type action) (action-expr action) type initial-env))
(result-var (gensym (symbol-name action-symbol))))
(when *trace-variables*
(format *trace-output* "~&~@<~S[~S] := ~2I~_~:W~:>~%" action-symbol (production-name production) code))
(push result-var result-vars)
(push (make-type-env-action
(list* action-symbol (general-grammar-symbol-symbol lhs) 0)
result-var
type
lhs)
initial-env)
(list result-var code)))))
(production-actions production)))
(filtered-args (mapcar #'(lambda (arg)
(and (tree-member arg code-bindings) arg))
args))
(production-code
(if code-bindings
`(lambda (stack)
(list*-bind ,(nreconc filtered-args '(stack-rest)) stack
(let* ,code-bindings
(list* ,@result-vars stack-rest))))
`(lambda (stack)
(nthcdr ,n-action-args stack))))
(production-code-name (unique-function-name world (string (production-name production)))))
(setf (production-n-action-args production) n-action-args)
(when *trace-variables*
(format *trace-output* "~&~@<all[~S] := ~2I~_~:W~:>~%" (production-name production) production-code))
(handler-bind (((or error warning)
#'(lambda (condition)
(declare (ignore condition))
(format *error-output* "~&While computing production ~S:~%" (production-name production)))))
(quiet-compile production-code-name production-code)
(setf (production-evaluator production) (symbol-function production-code-name))))))
; Return a list of all grammar symbols' symbols that are present in at least one expr-annotation:action
; in the annotated expression. The symbols are returned in no particular order.
(defun annotated-expr-grammar-symbols (annotated-expr)
(let ((symbols nil))
@ -3796,21 +3909,31 @@
; (<- <name> <value>)
; Mutate the local variable.
; Mutate the local or global variable.
(defun scan-<- (world type-env rest-statements last special-form name value-expr)
(let* ((symbol (scan-name world name))
(symbol-binding (type-env-get-local type-env symbol)))
(unless symbol-binding
(error "Unknown local variable ~A" name))
(unless (eq (type-env-local-mode symbol-binding) :var)
(error "Local variable ~A not writable" name))
(multiple-value-bind (value-code value-annotated-expr) (scan-typed-value world type-env value-expr (type-env-local-type symbol-binding))
(symbol-binding (type-env-get-local type-env symbol))
type)
(if symbol-binding
(if (eq (type-env-local-mode symbol-binding) :var)
(setq type (type-env-local-type symbol-binding))
(error "Local variable ~A not writable" name))
(progn
(setq type (symbol-type symbol))
(unless type
(error "Unknown local or global variable ~A" name))
(unless (get symbol :mutable)
(error "Global variable ~A not writable" name))))
(multiple-value-bind (value-code value-annotated-expr) (scan-typed-value world type-env value-expr type)
(multiple-value-bind (rest-codes rest-live rest-annotated-stmts)
(scan-statements world type-env rest-statements last t)
(values
(cons (list 'setq (type-env-local-name symbol-binding) value-code) rest-codes)
(cons (if symbol-binding
(list 'setq (type-env-local-name symbol-binding) value-code)
(list 'store-global-value symbol value-code))
rest-codes)
rest-live
(cons (list special-form name value-annotated-expr) rest-annotated-stmts))))))
(cons (list special-form name value-annotated-expr (not symbol-binding)) rest-annotated-stmts))))))
; (&= <record-expr> <value-expr>)
@ -3855,6 +3978,39 @@
(cons (list special-form record-type label record-annotated-expr value-annotated-expr) rest-annotated-stmts))))))))
; (action<- <action> <value>)
; Mutate the writable action. This can be done only once per action.
(defun scan-action<- (world type-env rest-statements last special-form action value-expr)
(unless (and (consp action) (identifier? (first action)))
(error "Bad action: ~S" action))
(let ((symbol (world-intern world (first action))))
(unless (symbol-action symbol)
(error "~S is not an action name" (first action)))
(multiple-value-bind (action-value action-type action-annotated-expr) (apply #'scan-action-call type-env symbol (rest action))
(unless (eq (type-kind action-type) :writable-cell)
(error "action<- type ~S must be a writable-cell" action-type))
(assert-true (symbolp action-value))
(multiple-value-bind (value-code value-annotated-expr) (scan-typed-value world type-env value-expr (writable-cell-element-type action-type))
(multiple-value-bind (rest-codes rest-live rest-annotated-stmts)
(scan-statements world type-env rest-statements last t)
(values
(if (or (symbolp value-code) (numberp value-code))
(list* `(when (car ,action-value)
(error "Attempt to write ~S to an already initialized writable-cell ~S" ,value-code ,action-value))
`(setf (car ,action-value) t)
`(setf (cdr ,action-value) ,value-code)
rest-codes)
(let ((v (gensym "V")))
(cons `(let ((,v ,value-code))
(when (car ,action-value)
(error "Attempt to write ~S to an already initialized writable-cell ~S" ,v ,action-value))
(setf (car ,action-value) t)
(setf (cdr ,action-value) ,v))
rest-codes)))
rest-live
(cons (list special-form action-annotated-expr value-annotated-expr) rest-annotated-stmts)))))))
; (return [<value-expr>])
(defun scan-return (world type-env rest-statements last special-form &optional value-expr)
(let ((value-code nil)
@ -4174,7 +4330,7 @@
; (define <name> <type> <value>)
; (defun <name> (-> (<type1> ... <typen>) <result-type>) (lambda ((<arg1> <type1>) ... (<argn> <typen>)) <result-type> . <statements>))
; Create the variable in the world but do not evaluate its type or value yet.
; Create the constant in the world but do not evaluate its type or value yet.
(defun scan-define (world grammar-info-var name type-expr value-expr)
(declare (ignore grammar-info-var))
(let ((symbol (scan-name world name)))
@ -4185,6 +4341,19 @@
(export-symbol symbol)))
; (defvar <name> <type> <value>)
; Create the variable in the world but do not evaluate its type or value yet.
(defun scan-defvar (world grammar-info-var name type-expr value-expr)
(declare (ignore grammar-info-var))
(let ((symbol (scan-name world name)))
(unless (eq (get symbol :value-expr *get2-nonce*) *get2-nonce*)
(error "Attempt to redefine variable ~A" symbol))
(setf (get symbol :value-expr) value-expr)
(setf (get symbol :type-expr) type-expr)
(setf (get symbol :mutable) t)
(export-symbol symbol)))
; (set-grammar <name>)
; Set the current grammar to the grammar or lexer with the given name.
(defun scan-set-grammar (world grammar-info-var name)
@ -4211,14 +4380,15 @@
; (declare-action <action-name> <general-grammar-symbol> <type> <mode> <parameter-list> <command> ... <command>)
; <mode> is one of:
; :hide Don't depict this action declaration because it's for a hidden production
; :singleton Don't depict this action declaration because it contains a singleton production
; :hide Don't depict this action declaration because it's for a hidden production;
; :singleton Don't depict this action declaration because it contains a singleton production;
; :action Depict this action declaration; all corresponding actions will be depicted by depict-action;
; :actfun Depict this action declaration; all corresponding actions will be depicted by depict-actfun;
; :writable Depict this action declaration but not actions.
; <parameter-list> contains the names of the action parameters when <mode> is :actfun.
(defun scan-declare-action (world grammar-info-var action-name general-grammar-symbol-source type-expr mode parameter-list &rest commands)
(declare (ignore parameter-list))
(unless (member mode '(:hide :singleton :action :actfun))
(unless (member mode '(:hide :singleton :action :actfun :writable))
(error "Bad declare-action mode ~S" mode))
(let* ((grammar (checked-grammar grammar-info-var))
(action-symbol (scan-name world action-name))
@ -4235,9 +4405,9 @@
; <mode> is one of:
; :hide Don't depict this action;
; :singleton Depict this action along with its declaration;
; :first Depict this action, which is the first in the rule
; :middle Depict this action, which is neither the first nor the last in the rule
; :last Depict this action, which is the last in the rule
; :first Depict this action, which is the first in the rule;
; :middle Depict this action, which is neither the first nor the last in the rule;
; :last Depict this action, which is the last in the rule.
(defun scan-action (world grammar-info-var action-name production-name type-expr mode value-expr)
(unless (member mode '(:hide :singleton :first :middle :last))
(error "Bad action mode ~S" mode))
@ -4285,6 +4455,7 @@
(deftype scan-deftype depict-deftype)
(define scan-define depict-define)
(defun scan-define depict-defun) ;Occurs from desugaring a function define
(defvar scan-defvar depict-defvar)
(set-grammar scan-set-grammar depict-set-grammar)
(clear-grammar scan-clear-grammar depict-clear-grammar)
(declare-action scan-declare-action depict-declare-action)
@ -4300,6 +4471,7 @@
(function scan-function depict-function)
(<- scan-<- depict-<-)
(&= scan-&= depict-&=)
(action<- scan-action<- depict-action<-)
(return scan-return depict-return)
(rwhen scan-rwhen depict-cond)
(when scan-when depict-cond)
@ -4366,7 +4538,10 @@
;;Unions
(in scan-in depict-in)
(not-in scan-not-in depict-not-in))
(not-in scan-not-in depict-not-in)
;;Writable Cells
(writable-cell-of scan-writable-cell-of depict-writable-cell-of)) ;For internal use only
(:condition
(not scan-not-condition)
@ -4382,7 +4557,8 @@
(list-set scan-list-set depict-set)
(range-set scan-range-set depict-set)
(tag scan-tag-type depict-tag-type)
(union scan-union depict-union))))
(union scan-union depict-union)
(writable-cell scan-writable-cell depict-writable-cell))))
(defparameter *default-primitives*
@ -4724,43 +4900,7 @@
(each-grammar-production
grammar
#'(lambda (production)
(let* ((n-action-args (n-action-args grammar production))
(codes
(mapcar
#'(lambda (action-binding)
(let ((action-symbol (car action-binding))
(action (cdr action-binding)))
(unless action
(error "Missing action ~S for production ~S" (car action-binding) (production-name production)))
(multiple-value-bind (has-type type) (action-declaration grammar (production-lhs production) action-symbol)
(declare (ignore has-type))
(let ((code (compute-action-code world grammar production action-symbol (action-type action) (action-expr action) type)))
(setf (action-code action) code)
(when *trace-variables*
(format *trace-output* "~&~@<~S[~S] := ~2I~_~:W~:>~%" action-symbol (production-name production) code))
code))))
(production-actions production)))
(production-code
(if codes
(let* ((vars-and-rest (intern-n-vars-with-prefix "ARG" n-action-args '(stack-rest)))
(vars (nreverse (butlast vars-and-rest)))
(applied-codes (mapcar #'(lambda (code) (apply #'gen-apply code vars))
(nreverse codes))))
`(lambda (stack)
(list*-bind ,vars-and-rest stack
(list* ,@applied-codes stack-rest))))
`(lambda (stack)
(nthcdr ,n-action-args stack))))
(production-code-name (unique-function-name world (string (production-name production)))))
(setf (production-n-action-args production) n-action-args)
(when *trace-variables*
(format *trace-output* "~&~@<all[~S] := ~2I~_~:W~:>~%" (production-name production) production-code))
(handler-bind (((or error warning)
#'(lambda (condition)
(declare (ignore condition))
(format *error-output* "~&While computing production ~S:~%" (production-name production)))))
(quiet-compile production-code-name production-code)
(setf (production-evaluator production) (symbol-function production-code-name))))))))
(compute-production-code world grammar production)))))
; Evaluate the given commands in the world.
@ -5141,23 +5281,34 @@
(assert-type action-declarations (list (tuple symbol t)))
(preprocess-ensure-grammar preprocessor-state)
(labels
((actions-match (action-declarations parameter-lists actions)
((writable-action (action-declaration)
(let ((type (second action-declaration)))
(and (consp type)
(eq (first type) 'writable-cell))))
(actions-match (action-declarations parameter-lists actions)
(or (and (endp action-declarations) (endp parameter-lists) (endp actions))
(let ((declared-action-name (caar action-declarations))
(action-name (caar actions))
(parameter-list :value))
(when (consp action-name)
(setq parameter-list (mapcar #'(lambda (arg)
(if (consp arg)
(first arg)
arg))
(rest action-name)))
(setq action-name (first action-name)))
(when (eq (first parameter-lists) t)
(setf (first parameter-lists) parameter-list))
(and (eq declared-action-name action-name)
(equal (first parameter-lists) parameter-list)
(actions-match (rest action-declarations) (rest parameter-lists) (rest actions)))))))
(let ((action-declaration (first action-declarations)))
(if (writable-action action-declaration)
(progn
(when (eq (first parameter-lists) t)
(setf (first parameter-lists) :value))
(actions-match (rest action-declarations) (rest parameter-lists) actions))
(let ((declared-action-name (first action-declaration))
(action-name (caar actions))
(parameter-list :value))
(when (consp action-name)
(setq parameter-list (mapcar #'(lambda (arg)
(if (consp arg)
(first arg)
arg))
(rest action-name)))
(setq action-name (first action-name)))
(when (eq (first parameter-lists) t)
(setf (first parameter-lists) parameter-list))
(and (eq declared-action-name action-name)
(equal (first parameter-lists) parameter-list)
(actions-match (rest action-declarations) (rest parameter-lists) (rest actions)))))))))
(let* ((n-productions 0)
(parameter-lists (make-list (length action-declarations) :initial-element t))
@ -5180,34 +5331,41 @@
(preprocessor-state-highlight preprocessor-state)))))
(when (= n-productions 0)
(error "Empty rule"))
(dotimes (i (length action-declarations))
(let* ((action-declaration (pop action-declarations))
(parameter-list (pop parameter-lists))
(declare-mode (cond
((= n-productions 1) :singleton)
((eq parameter-list :value) :action)
(t (assert-true (listp parameter-list)) :actfun)))
(j 0))
(push (list*
'declare-action (first action-declaration) general-grammar-symbol (second action-declaration) declare-mode parameter-list
(each-preprocessed-command
#'(lambda (production highlight)
(declare (ignore highlight))
(let ((name (fourth production))
(action (nth (+ i 4) production))
(mode (cond
((= n-productions 1) :singleton)
((= j 0) :first)
((= j (1- n-productions)) :last)
(t :middle))))
(incf j)
(list (list* 'action (first action) name (second action-declaration) mode (rest action)))))
preprocessor-state
productions
(preprocessor-state-highlight preprocessor-state)))
commands-reverse)
(assert-true (= j n-productions))))
(values (nreverse commands-reverse) t))))
(let ((i 4))
(dolist (action-declaration action-declarations)
(let* ((parameter-list (pop parameter-lists))
(writable (writable-action action-declaration))
(declare-mode (cond
(writable :writable)
((= n-productions 1) :singleton)
((eq parameter-list :value) :action)
(t (assert-true (listp parameter-list)) :actfun)))
(j 0))
(push (list*
'declare-action (first action-declaration) general-grammar-symbol (second action-declaration) declare-mode parameter-list
(each-preprocessed-command
#'(lambda (production highlight)
(declare (ignore highlight))
(let ((name (fourth production))
(action (if writable
(list (first action-declaration)
(list 'writable-cell-of (second (second action-declaration))))
(nth i production)))
(mode (cond
((= n-productions 1) :singleton)
((= j 0) :first)
((= j (1- n-productions)) :last)
(t :middle))))
(incf j)
(list (list* 'action (first action) name (second action-declaration) mode (rest action)))))
preprocessor-state
productions
(preprocessor-state-highlight preprocessor-state)))
commands-reverse)
(assert-true (= j n-productions))
(unless writable
(incf i))))
(values (nreverse commands-reverse) t)))))
; (exclude <lhs> ... <lhs>)

Просмотреть файл

@ -331,6 +331,12 @@
:break 1)))))
; (writable-cell <element-type>)
; "<element-type>"
(defun depict-writable-cell (markup-stream world level element-type-expr)
(depict-type-expr markup-stream world element-type-expr level))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING EXPRESSIONS
@ -906,6 +912,14 @@
(depict-in-or-not-in markup-stream world level value-annotated-expr type type-expr :not-member-10 :not-equal))
;;; Writable Cells
; (writable-cell-of <element-type>)
(defun depict-writable-cell-of (markup-stream world level)
(declare (ignore markup-stream world level))
(error "No notation to creation of a writable cell"))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING STATEMENTS
@ -982,9 +996,11 @@
; (<- <name> <value>)
(defun depict-<- (markup-stream world semicolon last-paragraph-style name value-annotated-expr)
(defun depict-<- (markup-stream world semicolon last-paragraph-style name value-annotated-expr global)
(depict-paragraph (markup-stream last-paragraph-style)
(depict-local-variable markup-stream name)
(if global
(depict-global-variable markup-stream name :reference)
(depict-local-variable markup-stream name))
(depict markup-stream " " :assign-10)
(depict-logical-block (markup-stream 6)
(depict-break markup-stream 1)
@ -1003,6 +1019,17 @@
(depict-semicolon markup-stream semicolon))))
; (action<- <action> <value>)
(defun depict-action<- (markup-stream world semicolon last-paragraph-style action-annotated-expr value-annotated-expr)
(depict-paragraph (markup-stream last-paragraph-style)
(depict-expression markup-stream world action-annotated-expr %expr%)
(depict markup-stream " " :assign-10)
(depict-logical-block (markup-stream 6)
(depict-break markup-stream 1)
(depict-expression markup-stream world value-annotated-expr %expr%)
(depict-semicolon markup-stream semicolon))))
; (return [<value-expr>])
(defun depict-return (markup-stream world semicolon last-paragraph-style value-annotated-expr)
(depict-paragraph (markup-stream last-paragraph-style)
@ -1414,10 +1441,10 @@
(depict-type-expr markup-stream world type-expr)))
(defun depict-equals-and-value (markup-stream world value-annotated-expr)
(defun depict-equals-and-value (markup-stream world value-annotated-expr assignment)
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 4)
(depict markup-stream "= ")
(depict markup-stream assignment " ")
(depict-expression markup-stream world value-annotated-expr %expr%)
(depict markup-stream ";")))
@ -1449,7 +1476,19 @@
(depict-logical-block (markup-stream 0)
(depict-global-variable markup-stream name :definition)
(depict-colon-and-type markup-stream world type-expr)
(depict-equals-and-value markup-stream world value-annotated-expr))))))
(depict-equals-and-value markup-stream world value-annotated-expr "="))))))
; (defvar <name> <type> <value>)
(defun depict-defvar (markup-stream world depict-env name type-expr value-expr)
(let ((value-annotated-expr (nth-value 2 (scan-value world *null-type-env* value-expr))))
(if (eq (car value-annotated-expr) 'expr-annotation:begin)
(error "defvar shouldn't use begin")
(depict-semantics (markup-stream depict-env)
(depict-logical-block (markup-stream 0)
(depict-global-variable markup-stream name :definition)
(depict-colon-and-type markup-stream world type-expr)
(depict-equals-and-value markup-stream world value-annotated-expr :assign-10))))))
; (defun <name> (-> (<type1> ... <typen>) <result-type>) (lambda ((<arg1> <type1>) ... (<argn> <typen>)) <result-type> . <statements>))
@ -1524,10 +1563,11 @@
; (declare-action <action-name> <general-grammar-symbol> <type> <mode> <parameter-list> <command> ... <command>)
; <mode> is one of:
; :hide Don't depict this action declaration because it's for a hidden production
; :singleton Don't depict this action declaration because it contains a singleton production
; :hide Don't depict this action declaration because it's for a hidden production;
; :singleton Don't depict this action declaration because it contains a singleton production;
; :action Depict this action declaration; all corresponding actions will be depicted by depict-action;
; :actfun Depict this action declaration; all corresponding actions will be depicted by depict-actfun;
; :writable Depict this action declaration but not actions.
; <parameter-list> contains the names of the action parameters when <mode> is :actfun.
(defun depict-declare-action (markup-stream world depict-env action-name general-grammar-symbol-source type-expr mode parameter-list &rest commands)
(let* ((grammar-info (checked-depict-env-grammar-info depict-env))
@ -1563,7 +1603,12 @@
(depict-paragraph (markup-stream :statement-last)
(depict-semantic-keyword markup-stream 'end :after)
(depict-semantic-keyword markup-stream 'proc nil)
(depict markup-stream ";"))))))))))
(depict markup-stream ";"))))))
(:writable
(depict-delayed-action (markup-stream depict-env action-name)
(depict-semantics (markup-stream depict-env)
(depict-declare-action-contents markup-stream world action-name general-grammar-symbol type-expr)
(depict markup-stream ";"))))))))
; Declare and define the lexer-action on the charclass given by nonterminal.
@ -1617,7 +1662,7 @@
(general-production (grammar-general-production grammar production-name))
(lhs (general-production-lhs general-production)))
(unless (hidden-nonterminal? lhs)
(let* ((initial-env (general-production-action-env grammar general-production))
(let* ((initial-env (general-production-action-env grammar general-production t))
(type (scan-type world type-expr))
(value-annotated-expr (nth-value 1 (scan-typed-value-or-begin world initial-env value-expr type)))
(action-grammar-symbols (annotated-expr-grammar-symbols value-annotated-expr))
@ -1660,7 +1705,7 @@
(depict-action-signature markup-stream action-name general-production action-grammar-symbols)
(when (eq mode :singleton)
(depict-colon-and-type markup-stream world type-expr))
(depict-equals-and-value markup-stream world value-annotated-expr))))))))))))
(depict-equals-and-value markup-stream world value-annotated-expr "="))))))))))))
; (terminal-action <action-name> <terminal> <lisp-function>)

Просмотреть файл

@ -155,8 +155,7 @@
(defstruct (action (:constructor make-action (type expr))
(:predicate action?))
(type nil :read-only t) ;The unparsed type of the action's result
(expr nil :read-only t) ;The unparsed source expression that defines the action
(code nil)) ;The generated lisp source code that performs the action
(expr nil :read-only t)) ;The unparsed source expression that defines the action
;;; ------------------------------------------------------------------------------------------------------
@ -300,33 +299,33 @@
; link is the lhs's link type.
(defun depict-general-production (markup-stream general-production link &optional symbols-with-subscripts)
(let ((lhs (general-production-lhs general-production))
(rhs-components (general-production-rhs-components general-production)))
(depict-general-nonterminal markup-stream lhs link)
(rhs-components (general-production-rhs-components general-production))
(counts-hash (make-hash-table :test *grammar-symbol-=*)))
(when symbols-with-subscripts
(dolist (symbol symbols-with-subscripts)
(setf (gethash symbol counts-hash) 0))
(dolist (production-rhs-component (cons lhs (general-production-rhs general-production)))
(when (general-grammar-symbol? production-rhs-component)
(let ((symbol (general-grammar-symbol-symbol production-rhs-component)))
(when (gethash symbol counts-hash)
(incf (gethash symbol counts-hash))))))
(maphash #'(lambda (symbol count)
(assert-true (> count 0))
(if (> count 1)
(setf (gethash symbol counts-hash) 0)
(remhash symbol counts-hash)))
counts-hash))
(depict-general-nonterminal markup-stream lhs link (gethash (general-grammar-symbol-symbol lhs) counts-hash))
(depict markup-stream " " :derives-10)
(if rhs-components
(let ((counts-hash (make-hash-table :test *grammar-symbol-=*)))
(when symbols-with-subscripts
(dolist (symbol symbols-with-subscripts)
(setf (gethash symbol counts-hash) 0))
(dolist (production-rhs-component (cons lhs (general-production-rhs general-production)))
(when (general-grammar-symbol? production-rhs-component)
(let ((symbol (general-grammar-symbol-symbol production-rhs-component)))
(when (gethash symbol counts-hash)
(incf (gethash symbol counts-hash))))))
(maphash #'(lambda (symbol count)
(assert-true (> count 0))
(if (> count 1)
(setf (gethash symbol counts-hash) 0)
(remhash symbol counts-hash)))
counts-hash))
(dolist (production-rhs-component rhs-components)
(let ((subscript nil))
(when (general-grammar-symbol? production-rhs-component)
(let ((symbol (general-grammar-symbol-symbol production-rhs-component)))
(when (gethash symbol counts-hash)
(setq subscript (incf (gethash symbol counts-hash))))))
(depict-space markup-stream)
(depict-production-rhs-component markup-stream production-rhs-component subscript))))
(dolist (production-rhs-component rhs-components)
(let ((subscript nil))
(when (general-grammar-symbol? production-rhs-component)
(let ((symbol (general-grammar-symbol-symbol production-rhs-component)))
(when (gethash symbol counts-hash)
(setq subscript (incf (gethash symbol counts-hash))))))
(depict-space markup-stream)
(depict-production-rhs-component markup-stream production-rhs-component subscript)))
(depict markup-stream " " :left-angle-quote "empty" :right-angle-quote))))
@ -1092,7 +1091,7 @@
(items-hash nil :type (or null hash-table)) ;Hash table of (production . dot) -> item; nil for a cleaned grammar or a grammar without a parser
(states nil :type list) ;List of LR(0) states (in order of state numbers)
;The following fields are used for the action generator.
(action-signatures nil :type (or null hash-table))) ;Hash table of grammar-symbol -> list of (action-symbol . type-or-type-expr)
(action-signatures nil :type (or null hash-table))) ;Hash table of grammar-symbol -> list of (action-symbol type-or-type-expr writable)
; Return a list of the given terminal's variants, including the terminal itself.