last changed on Fri 31 Aug 2007 at 17:45:20 PST by lamport ------------------------------ MODULE PlusCal ------------------------------ (***************************************************************************) (* Compiling a +cal algorithm to a TLA+ specification is performed in *) (* three steps: *) (* *) (* Parsing : Mapping the algorithm text to an AST (Abstract *) (* Syntax Tree). *) (* *) (* Renaming : Renaming algorithm identifiers to avoid clashes in *) (* the TLA+ specification. Those identifiers may *) (* include local variable names and labels. *) (* *) (* Translation : Mapping the AST to a TLA+ specification. *) (* *) (* This module specifies the translation step. It extends module AST, *) (* which is assumed to define two values: *) (* *) (* ast : The algorithm's AST. *) (* fairness : A specification of the algorithm's fairness condition, *) (* which is one of the following *) (* *) (* "" - No fainess condition. *) (* "wf" - Weak fairness of all process actions. *) (* "wfNext" - Weak fairness of entire next-state action. *) (* "sf" - Strong fairness of all process actions. *) (* *) (* *) (* The specification contains three main parts: a specification of the *) (* AST, a specification of "label correctness", and a specification of the *) (* translation. These sections contain the following definitions, where *) (* an error value is one that equals Assert(FALSE, ...) and whose *) (* evaluation produces an error message. *) (* *) (* IsAlgorithm : Equals TRUE if ast is a legal AST, FALSE otherwise. *) (* (However, evaluating it may produce a TLC error if *) (* ast is not a legal AST.) *) (* *) (* CheckLabels : Equals TRUE if there are no duplicate labels in the *) (* same context and every goto statement specifies *) (* a label that is legal in the statement's context. *) (* Otherwise, it equals an error value. *) (* *) (* Translation : Equals either a sequence of strings that represents *) (* the TLA+ specification obtained from the algorithm, *) (* or equals an error value if an error in the *) (* algorithm is detected. *) (* *) (* Specifying an AST is straightforward, so Part I of the specification is *) (* of no intrinsic interest. However, since the translation works on the *) (* AST, understanding the translation requires understanding the AST. So, *) (* the AST must be specified precisely. Label checking is rather trivial *) (* and Part II has little redeeming social value. Readers should feel *) (* free to skip it. Part III, the specification of the actual *) (* translation, is the interesting part of the specification. *) (* *) (* One important aspect of the translation that is not specified here is *) (* the formatting of expressions and of the specification. Neither the *) (* AST representation of an expression nor the translation contain any *) (* formatting information. Hence, an algorithm with expressions *) (* containing bulleted conjunction/disjunction lists may not be *) (* translated correctly, and the translation does not specify how the *) (* TLA+ specification is to be formatted. *) (* *) (* Other than the limitations mentioned above, this module should be a *) (* correct specification of the version of +cal at the time of the *) (* last-modification date at the beginning of the file. *) (***************************************************************************) EXTENDS Naturals, Sequences, TLC, AST ----------------------------------------------------------------------------- (***************************************************************************) (* PART I: THE DEFINITION OF IsAlgorithm *) (* *) (* We describe the AST in terms of a BNF grammar for +cal. This grammar *) (* describes the labeling rules as well as the simple syntax, so it is *) (* more complicated than the one in the +cal manual. However, it is *) (* simpler because the parsing phase is assumed to perform macro *) (* substitution and to represent an `if' with `elsif' clauses as nested *) (* if-then-else statements. *) (* *) (* The AST is a tree in which each non-leaf node is either a record. *) (* Each field of that record is either a child node, a sequence of *) (* children nodes, or a value associated with the node. If a *) (* non-terminal in the BNF grammar represents a record node of the AST, *) (* we indicate the fields of that record in that non-terminal's *) (* production. For example, the production *) (* *) (* ::= .var [= | \in].eqOrIn .val *) (* *) (* indicates that a node is a record r where r.var is a *) (* node, r.val is an node, and r.eqOrIn is a value indicating if *) (* the statement has an "=" or "\in" token. *) (* *) (* THE BNF GRAMMAR *) (* --------------- *) (* High-Level Constructs and VariableDeclarations *) (* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *) (* ::== | *) (* *) (* ::= --algorithm .name *) (* variable[s] *.decls *) (* [define end define]^0,1.defs *) (* *.prcds *) (* begin *.body *) (* end algorithm *) (* *) (* ::= --algorithm .name *) (* * *) (* [define end define]^0,1.defs *) (* *.prcds *) (* *.procs *) (* *) (* ::= procedure .name *) (* ( [ [, ]*]^0,1.params ) *) (* variable[s] *.decls *) (* begin *.body *) (* end procedure *) (* *) (* ::= process .name [= | \in].eqOrIn .id *) (* variable[s] *.decls *) (* begin *.body *) (* end procedure *) (* *) (* ::= .var [= | \in].eqOrIn .val *) (* *) (* ::= .var =.eqOrIn .val *) (* For convenience, we define a node to be a restricted *) (* class of node. *) (* *) (* Statements *) (* ^^^^^^^^^^ *) (* In explaining the grammar, we consider three classes of statements: *) (* *) (* - A label statement that may be labeled or contain a label *) (* somewhere inside it. *) (* *) (* - A final statement that contains no label but may contain a *) (* , , or within it. *) (* *) (* - A simple statement that contains no label, , , or *) (* . *) (* *) (* We use the naming convention for non-terminals that , , *) (* and is a statement of type X of the indicated class. *) (* *) (* Label Statement *) (* ^^^^^^^^^^^^^^^ *) (* ::=