M3AST_AS
is the syntactic layer of the Modula-3 AST specification.
INTERFACETo support clients of previous versions of this interface,M3AST_AS ; IMPORT M3AST_LX; <* PRAGMA FIELDS *> TYPE SRC_NODE = M3AST_LX.SRC_NODE; SRC_NODE_C = M3AST_LX.SRC_NODE_C;
SRC_NODE
is passed through by this interface.
\subsection{Identifiers}
TYPE ID = M3AST_LX.ID;The subtypes of the
ID
class are partitioned into two disjoint sets,
those which correspond to identifers that are definitions (DEF_ID
)
and those which are correspond to uses (USED_ID
). Unlike the
concrete syntax, which does not distinguish identifier definitions,
each construct that can introduce a new identifier definition has an
aassociated, unique, subtype, e.g. Proc_id
for identifiers
associated with PROCEDURE
declarations.
\subsubsection{Definitions}
DEF_ID <: ID; DEF_ID_NULL = DEF_ID; UNIT_ID <: DEF_ID; (* INTERFACE or MODULE *) Module_id <: UNIT_ID; (* MODULE m *) Interface_id <: UNIT_ID; (* INTERFACE i *) Interface_AS_id <: DEF_ID; (* the J in IMPORT I AS J *) F_Interface_id <: DEF_ID; (* generic formal *)The class
TYPED_ID
is introduced as a placeholder for semantic
information, to mitigate the lack of multiple inheritance. All the
identifiers below are subtypes of TYPED_ID
.
TYPED_ID <: DEF_ID; FORMAL_ID <: TYPED_ID; (* procedure formals *) F_Value_id <: FORMAL_ID; (* VALUE v *) F_Var_id <: FORMAL_ID; (* VAR v *) F_Readonly_id <: FORMAL_ID; (* READONLY v *) Type_id <: TYPED_ID; (* TYPE T *) Const_id <: TYPED_ID; (* CONST C *) Var_id <: TYPED_ID; (* VAR v (in blocks) *) Proc_id <: TYPED_ID; (* PROCEDURE P *) Enum_id <: TYPED_ID; (* {Red,Green,Blue} *) METHOD_OVERRIDE_ID <: TYPED_ID; Method_id <: METHOD_OVERRIDE_ID; (* METHODS m *) Override_id <: METHOD_OVERRIDE_ID; (* OVERRIDES m *) Field_id <: TYPED_ID; (* in RECORD/OBJECT *) For_id <: TYPED_ID; (* FOR i *) Handler_id <: TYPED_ID; (* EXCEPT E(v) *) Handler_id_NULL = Handler_id; Tcase_id <: TYPED_ID; (* TYPECASE ... T(v) *) Tcase_id_NULL = Tcase_id; With_id <: TYPED_ID; (* WITH b *) Exc_id <: TYPED_ID; (* EXCEPTION E(T) *)\subsubsection{Uses} Identifier uses are separated into three distinct subtypes. Firstly, there are several cases where the binding of the use is required by the language definition to be to an
Interface_id
, e.g.
IMPORT I
. To improve readability, such uses are denoted by the
subtype Used_interface_id
. Secondly, there are occurrences such as
the identifier N
in a FROM I IMPORT N
. These are denoted by the
subtype Used_def_id
. Finally, there are identifiers that can occur
in expressions. Here we have a problem, since such identifiers also
need to be a subtype of the class that denotes expressions (EXP
).
The solution, of which more later, is to make these a subtype of
EXP
, and call them Exp_used_id
.
USED_ID <: ID; Used_interface_id <: USED_ID; Used_interface_id_NULL = Used_interface_id; Used_def_id <: USED_ID;Qualified identifiers, e.g.
I.B
, can also appear in both
expression and non-expression contexts. In the former case, it is not
known after syntax analysis, whether a construct of the form a.b
denotes a qualified identifier or not, until the binding for a
is
resolved. In the non-expression case, e.g. in REVEAL I.T = ...
, a
qualified identifier is denoted by a separate node containing two
children of class USED_ID
. Note that the interface
component of
such a node can be empty, denoted by NIL.
Qual_used_id <: SRC_NODE_C; Qual_used_id_NULL = Qual_used_id; <* FIELDS OF Qual_used_id as_intf_id: Used_interface_id_NULL; as_id: Used_def_id; *>To support the {\em multiple inheritance} of the
ID
, or USED_ID
classes, methods are provided to enquire whether any M3AST.NODE
instance
is also a member of these classes. See, for example,
Exp_used_id
in the expressions section. These methods are actually
revealed in the representation interface, e.g. M3AST_AS_F
.
METHODS IsA_USED_ID(VAR (*outused_id): BOOLEAN; | IsA_ID(VAR (*out*) id): BOOLEAN; *)\subsection{Compilation Units}In order to provide a node in which to place to miscellaneous attributes, e.g. compilation status, the AST is rooted in a node called
Compilation_Unit
, which has no direct counterpart in the concrete syntax.
Compilation_Unit <: SRC_NODE_C; <* FIELDS OF Compilation_Unit as_root: UNIT; *>The class that corresponds to the non-terminal namedCompilation
in the concrete grammar is calledUNIT
, and it has subtypes to denote generic definitions, generic instantiations andnormal
interfaces and modules. Multiple inheritance would simplify the structure here also, but in this case, it is simplest to simply repeat (multiply inherited) attributes in the subtypes. TheUNIT
class carries the attribute denoting the identifier that is common to all forms ofUNIT
.
UNIT <: SRC_NODE_C; <* FIELDS OF UNIT as_id: UNIT_ID; *>Generic definitions and {\it normal} units both have {\it bodies}, i.e. imports and declarations, and these are associated with the classUNIT_WITH_BODY
.
UNIT_WITH_BODY <: UNIT; <* FIELDS OF UNIT_WITH_BODY as_import_s: SEQUENCE OF IMPORTED; as_block: Block *>Generic definitions contain a list of formal parameters, and this is captured by theUNIT_GEN_DEF
class.
UNIT_GEN_DEF <: UNIT_WITH_BODY; <* FIELDS OF UNIT_GEN_DEF as_id_s: SEQUENCE OF F_Interface_id; *> Interface_gen_def <: UNIT_GEN_DEF; Module_gen_def <: UNIT_GEN_DEF;Normal interfaces and modules can beUNSAFE
. (as can generic instantiations, but this example of multiple inheritance is not captured in the type hierarchy.
UNIT_NORMAL <: UNIT_WITH_BODY; <* FIELDS OF UNIT_NORMAL as_unsafe: Unsafe_NULL; *> Interface <: UNIT_NORMAL;Modules can have an EXPORT list (as can generically instantiated modules, but this example of multiple inheritance is not captured in the type hierarchy).
Module <: UNIT_NORMAL; <* FIELDS OF Module as_export_s: SEQUENCE OF Used_interface_id; *>Generic instantiations can beUNSAFE
, contain an identifier that refers to the generic definition and a list of actual parameters. These identifier occurrences must all bind toInterface_id
s.
UNIT_GEN_INS <: UNIT; <* FIELDS OF UNIT_GEN_INS as_unsafe: Unsafe_NULL; as_gen_id: Used_interface_id; as_id_s: SEQUENCE OF Used_interface_id *> Interface_gen_ins <: UNIT_GEN_INS; Module_gen_ins <: UNIT_GEN_INS; <* FIELDS OF Module_gen_ins as_export_s: SEQUENCE OF Used_interface_id; *>UNSAFE
is represented as node with no children. In order to record the actual lexical token, it is declared as a subtype ofSRC_NODE_C
. Thelx_node_s
will contain a singleToken
element.
Unsafe <: SRC_NODE_C; Unsafe_NULL = Unsafe;Imports fall into two classes, denoted byAsImport
andFromImport
in the concrete syntax. The classIMPORTED
is used in the AST to denote the choice, with subtypesSimple_import
andFrom_import
.
IMPORTED <: SRC_NODE_C; Simple_import <: IMPORTED; <* FIELDS OF Simple_import as_import_item_s: SEQUENCE OF Import_item; *>AnImport_item
node corresponds directly toImportItem
in the concrete syntax
Import_item <: SRC_NODE_C; <* FIELDS OF Import_item as_intf_id: Used_interface_id; as_id: Interface_AS_id; *> From_import <: IMPORTED; <* FIELDS OF From_import as_intf_id: Used_interface_id; as_id_s: SEQUENCE OF Used_def_id; *>\subsection{Declarations and Revelations} The concrete syntax groups revelations under theDecl
rules. In the AST we introduce a classDECL_REVL
to handle either, and two subtypesDECL
andRevelation_s
DECL_REVL <: SRC_NODE_C;Declarations are somewhat tedious to represent, since each occurrence of, say,CONST
, can introduce several actual declarations. Accordingly, we introduce nodes of the formX_s
, which carry a sequence attribute.
DECL <: DECL_REVL; Const_decl_s <: DECL; (* CONST ... *) <* FIELDS OF Const_decl_s as_const_decl_s: SEQUENCE OF Const_decl *> Type_decl_s <: DECL; (* TYPE ... *) <* FIELDS OF Type_decl_s as_type_decl_s: SEQUENCE OF TYPE_DECL *> Var_decl_s <: DECL; (* VAR ... *) <* FIELDS OF Var_decl_s as_var_decl_s: SEQUENCE OF Var_decl *> Exc_decl_s <: DECL; (* EXCEPTION ... *) <* FIELDS OF Exc_decl_s as_exc_decl_s: SEQUENCE OF Exc_decl *>Proc_decl
is the exception to the rule. Theas_body
attribute will beNIL
in an AST that represents an interface.
Proc_decl <: DECL; <* FIELDS OF Proc_decl as_id: Proc_id; as_type: Procedure_type; as_body: Block_NULL; *>Now the declarations proper. Note that the identifer in each node is of the appropriate type, e.g.Const_id
for aConst_decl
.
Const_decl <: SRC_NODE_C; <* FIELDS OF Const_decl as_id: Const_id; as_type: M3TYPE_NULL; as_exp: EXP; *>Type declarations are either opaque (subtype) or concrete. The classTYPE_DECL
captures this.
TYPE_DECL <: SRC_NODE_C; <* FIELDS OF TYPE_DECL as_id: Type_id; as_type: M3TYPE; *>Theas_type
attribute for aSubtype_decl
is always anOpaque_type
node (see below). The value ofU
is encoded as an attribute of theOpaque_type
node.
Subtype_decl <: TYPE_DECL; (* TYPE T <: U *) Concrete_decl <: TYPE_DECL; (* TYPE T = U *)Variable declarations are unusual in that several identifiers can be introduced in the same declaration. Note that either theas_type
attribute or theas_default
attribute may beNIL
, but not both. The latter constraint is not expressed in the AST.
Var_decl <: SRC_NODE_C; <* FIELDS OF Var_decl as_id_s: SEQUENCE OF Var_id; as_type: M3TYPE_NULL; as_default: EXP_NULL; *> Exc_decl <: SRC_NODE_C; <* FIELDS OF Exc_decl as_id: Exc_id; as_type: M3TYPE_NULL; *> Revelation_s <: DECL_REVL; <* FIELDS OF Revelation_s as_reveal_s: SEQUENCE OF REVELATION; *>Like type declarations, revelations can be opaque (subtype) or concrete.
REVELATION <: SRC_NODE_C; <* FIELDS OF REVELATION as_qual_id: Qual_used_id; as_type: M3TYPE; *> Subtype_reveal <: REVELATION; (* REVEAL T <: U *) Concrete_reveal <: REVELATION; (* REVEAL T = U *)\subsubsection{Type Productions}There are situations where an attribute can be either a type or an expression, so we define the class
EXP_TYPE
to denote that choice.
EXP_TYPE <: SRC_NODE_C;Types can appear in the AST as type constructions or as qualified identifiers (which must ultimately bind to a name declared as aType_id
. The classM3TYPE
is used to denote this choice.
M3TYPE <: EXP_TYPE; M3TYPE_NULL = M3TYPE; Named_type <: M3TYPE; <* FIELDS OF Named_type as_qual_id: Qual_used_id; *>Type constructions (specifications) are grouped under the classTYPE_SPEC
TYPE_SPEC <: M3TYPE;The following built-in types are primitive. Others, such asBOOLEAN
, are expressed as instances of the apropriateTYPE_SPEC
subtype (Enumeration_type
forBOOLEAN
).For convenience all the floating types are grouped under
FLOAT_TYPE
FLOAT_TYPE <: TYPE_SPEC; Real_type <: FLOAT_TYPE; (* REAL *) LongReal_type <: FLOAT_TYPE; (* LONGREAL *) Extended_type <: FLOAT_TYPE; (* EXTENDED *) INT_TYPE <: TYPE_SPEC; Integer_type <: INT_TYPE; (* INTEGER *) Longint_type <: INT_TYPE; (* LONGINT *) WideChar_type <: TYPE_SPEC; (* WIDECHAR *) Null_type <: TYPE_SPEC; (* NULL *) RefAny_type <: TYPE_SPEC; (* REFANY *) Address_type <: TYPE_SPEC; (* ADDRESS *) Root_type <: TYPE_SPEC; (* ROOT/UNTRACED ROOT *) <* FIELDS OF Root_type as_trace_mode: Untraced_NULL *>UNTRACED ...
is denoted by a node of typeUntraced
. In order to record the actual lexical token, it is declared as a subtype ofSRC_NODE_C
. Thelx_node_s
will contain a singleToken
element.
Untraced <: SRC_NODE_C; Untraced_NULL = Untraced; Packed_type <: TYPE_SPEC; <* FIELDS OF Packed_type as_exp: EXP; as_type: M3TYPE *> Array_type <: TYPE_SPEC; <* FIELDS OF Array_type as_indextype_s: SEQUENCE OF M3TYPE; as_elementtype: M3TYPE; *> Enumeration_type <: TYPE_SPEC; <* FIELDS OF Enumeration_type as_id_s: SEQUENCE OF Enum_id; *> Set_type <: TYPE_SPEC; <* FIELDS OF Set_type as_type: M3TYPE; *> Subrange_type <: TYPE_SPEC; <* FIELDS OF Subrange_type as_range: Range; *>Several attributes need to encode a range of expressions, and in Expressome cases a single value is a legal choice . To avoid duplication, the classRANGE_EXP
is introduced to denote this choice.
RANGE_EXP <: SRC_NODE_C;A single value is denoted by aRange_EXP
(sic).Range_EXP <: RANGE_EXP; <* FIELDS OF Range_EXP as_exp: EXP; *> Range <: RANGE_EXP; <* FIELDS OF Range as_exp1, as_exp2: EXP *>RECORD
types simply contain a sequence ofFields
.
Record_type <: TYPE_SPEC; <* FIELDS OF Record_type as_fields_s: SEQUENCE OF Fields; *>Like VAR declarations, Eachfield
can introduce several identifiers of the same type and initial value. The remarks aboutas_type
andas_default
in theVar_decl
node apply to fields also.
Fields <: SRC_NODE_C; <* FIELDS OF Fields as_id_s: SEQUENCE OF Field_id; as_type: M3TYPE_NULL; as_default: EXP_NULL; *>OBJECT
types andREF
types can beBRANDED
, and this is denoted by theBRANDED_TYPE
class.
BRANDED_TYPE <: TYPE_SPEC; <* FIELDS OF BRANDED_TYPE as_brand: Brand_NULL *>A user supplied brand is optional.Brand <: SRC_NODE_C; Brand_NULL = Brand; <* FIELDS OF Brand as_exp: EXP_NULL; *> Ref_type <: BRANDED_TYPE; <* FIELDS OF Ref_type as_trace_mode: Untraced_NULL; as_type: M3TYPE *>The object supertype (ancestor) is encoded as an attribute of typeM3TYPE
. In fact only aNamed_type
,Object_type
orRoot_Type
is legal.
Object_type <: BRANDED_TYPE; <* FIELDS OF Object_type as_ancestor: M3TYPE_NULL; as_fields_s: SEQUENCE OF Fields; as_method_s: SEQUENCE OF Method; as_override_s: SEQUENCE OF Override; *>Methods and Overrides have a similar syntactic structure, which is encoded by the classMETHOD_OVERRIDE
. AnOverride
has the additional constraint thatas_default # NIL
.
METHOD_OVERRIDE <: SRC_NODE_C; <* FIELDS OF METHOD_OVERRIDE as_id: METHOD_OVERRIDE_ID; as_default: EXP_NULL *> Method <: METHOD_OVERRIDE; <* FIELDS OF Method as_type: Procedure_type; *> Override <: METHOD_OVERRIDE; Procedure_type <: TYPE_SPEC; <* FIELDS OF Procedure_type as_formal_param_s: SEQUENCE OF Formal_param; as_result_type: M3TYPE_NULL; as_raises: RAISEES_NULL *>As withVar_decl
s, only one ofas_formal_type
andas_default
may be NIL.
Formal_param <: SRC_NODE_C; <* FIELDS OF Formal_param as_id_s: SEQUENCE OF FORMAL_ID; as_formal_type: M3TYPE_NULL; as_default: EXP_NULL *> RAISEES <: SRC_NODE_C; RAISEES_NULL = RAISEES; Raisees_some <: RAISEES; <* FIELDS OF Raisees_some as_raisees_s: SEQUENCE OF Qual_used_id *> Raisees_any <: RAISEES; (* RAISES ANY *)Opaque types have no direct correspondence in the concrete syntax. In effect they encode the<:
in aSubtype_decl
, and provide a unique node for each declaration, which is convenient for subsequent semantic analysis. Theas_type
attribute encodes theM3TYPE
that actually appeared to the right of the<:
.
Opaque_type <: TYPE_SPEC; <* FIELDS OF Opaque_type as_type: M3TYPE; *>\subsection{Expression productions}There is no analogue of
ConstExpr
in the abstract syntax.
EXP <: EXP_TYPE; EXP_NULL = EXP;InM3AST_LX
, the classLITERAL
was declared as a subtype ofSRC_NODE
. At this point we {\it reveal} thatLITERAL
is actually a subtype ofEXP
. We also introduce distinct subtypes ofLITERAL
to denote the different cases. Note that sinceEXP
is defined as a subtype ofSRC_NODE_C
, literals will inherit thelx_node_s
attribute, but the value will be the empty sequence.
LITERAL = M3AST_LX.LITERAL; REVEAL M3AST_LX.LITERAL <: EXP; TYPE NUMERIC_LITERAL <: M3AST_LX.LITERAL; Integer_literal <: NUMERIC_LITERAL; Longint_literal <: NUMERIC_LITERAL; Real_literal <: NUMERIC_LITERAL; LongReal_literal <: NUMERIC_LITERAL; Extended_literal <: NUMERIC_LITERAL; Char_literal <: M3AST_LX.LITERAL; WideChar_literal <: M3AST_LX.LITERAL; Text_literal <: M3AST_LX.LITERAL; WideText_literal <: M3AST_LX.LITERAL;Although we could simply representNIL
by anExp_used_id
, it occurs sufficiently frequently that we choose to denote it by a unique subtype,Nil_literal
Nil_literal <: M3AST_LX.LITERAL;Single identifiers occurring in expressions are really subtypes ofEXP
andUSED_ID
. They are declared as subtypes ofEXP
, with theUSED_ID
attributesmultiply inherited
Exp_used_id <: EXP; <* FIELDS OF Exp_used_id vUSED_ID: USED_ID; *>Procedure call is denoted by aCall
node.
Call <: EXP; <* FIELDS OF Call as_callexp: EXP; as_param_s: SEQUENCE OF Actual *>The built-in functions, e.g.ABS
, could be represented by unique node types, likePlus
. However, to reduce the number of node types, they are represented byCall
nodes. An implementation of this interface is expected to provide appropriate support for determining if aCall
node denotes a built-in function.The desugaring of
NEW(ObjectType, method := P)
is made easier if the applications of NEW are denoted by an independent subtype.
NEWCall <: Call;Since it is legal for an actual parameter to some of the built-in functions to be a type,as_exp_type
is of classEXP_TYPE
. The value ofas_id
will beNIL
for the built-in functions.
Actual <: SRC_NODE_C; <* FIELDS OF Actual as_id: EXP_NULL; as_exp_type: EXP_TYPE *> Index <: EXP; (* a[x,y,z,...] *) <* FIELDS OF Index as_array: EXP; as_exp_s: SEQUENCE OF EXP *>ARRAY
,RECORD
andSET
constructors are not distinguished in the AST, since they are not, in general, distinguished by syntax alone. The different kinds of elements are denoted by the classCONS_ELEM
. Array element propagation is denoted a node of typePropagate
.
Constructor <: EXP; <* FIELDS OF Constructor as_type: M3TYPE; as_element_s: SEQUENCE OF CONS_ELEM; as_propagate: Propagate_NULL *> Propagate <: SRC_NODE_C; Propagate_NULL = Propagate;There are three different kinds of constructor elements, simple expressions, ranges and keyword actuals. We use the already declared typesRANGE_EXP
andActual
as the corresponding attribute types.
CONS_ELEM <: SRC_NODE_C; RANGE_EXP_elem <: CONS_ELEM; <* FIELDS OF RANGE_EXP_elem as_range_exp: RANGE_EXP; *> Actual_elem <: CONS_ELEM; <* FIELDS OF Actual_elem as_actual: Actual *>The binary and unary operators are encode as subtypes of theBINARY
andUNARY
classes. Selection,``.'', is not treated as a binary operator. It is defined as a separate subtype ofEXP
, because it is almost always processed in a different manner to the other binary operations.
BINARY <: EXP; <* FIELDS OF BINARY as_exp1: EXP; as_exp2: EXP *> Plus <: BINARY; (* + *) Minus <: BINARY; (* - *) Times <: BINARY; (* * *) Rdiv <: BINARY; (* / *) Textcat <: BINARY; (* & *) Div <: BINARY; (* DIV *) Mod <: BINARY; (* MOD *) Eq <: BINARY; (* = *) Ne <: BINARY; (* # *) Gt <: BINARY; (* > *) Lt <: BINARY; (* < *) Ge <: BINARY; (* >= *) Le <: BINARY; (* <= *) And <: BINARY; (* AND *) Or <: BINARY; (* OR *) In <: BINARY; (* IN *) UNARY <: EXP; <* FIELDS OF UNARY as_exp: EXP *> Not <: UNARY; (* NOT *) Unaryplus <: UNARY; (* + *) Unaryminus <: UNARY; (* - *) Deref <: UNARY; (* ^ *) Select <: EXP; (* . *) <* FIELDS OF Select as_exp: EXP; as_id: Exp_used_id *>\subsubsection{Statements}The
STM
class captures all possible statement productions.
STM <: SRC_NODE_C;Statements partition into two groups, those witha sequence of statements
as an attribute, e.g.WHILE
, and those which do not, e.g.RAISE
. The classSTM_WSS
contains the former group. Some statements contain a component that, although it cannot appear where aSTM
can, also containsa sequence of statements
, e.g. theELSE
clause in aCASE
statement. These nodes are grouped into the classSUBSTM_WSS
.
STM_WSS <: STM; <* FIELDS OF STM_WSS as_stm_s: SEQUENCE OF STM; *> SUBSTM_WSS <: SRC_NODE_C; <* FIELDS OF SUBSTM_WSS as_stm_s: SEQUENCE OF STM; *> Assign_st <: STM; <* FIELDS OF Assign_st as_lhs_exp: EXP; as_rhs_exp: EXP *> Call_st <: STM; <* FIELDS OF Call_st as_call: Call; *> Case_st <: STM; <* FIELDS OF Case_st as_exp: EXP; as_case_s: SEQUENCE OF Case; as_else: Else_stm_NULL; *> Case <: SUBSTM_WSS; <* FIELDS OF Case as_case_label_s: SEQUENCE OF RANGE_EXP; *> Else_stm <: SUBSTM_WSS; Else_stm_NULL = Else_stm; Eval_st <: STM; <* FIELDS OF Eval_st as_exp: EXP; *> Exit_st <: STM; Raise_st <: STM; <* FIELDS OF Raise_st as_qual_id: Qual_used_id; as_exp_void: EXP_NULL *> Typecase_st <: STM; <* FIELDS OF Typecase_st as_exp: EXP; as_tcase_s: SEQUENCE OF Tcase; as_else: Else_stm_NULL; *> Tcase <: SUBSTM_WSS; <* FIELDS OF Tcase as_type_s: SEQUENCE OF M3TYPE; as_id: Tcase_id_NULL *> Handler <: SUBSTM_WSS; <* FIELDS OF Handler as_qual_id_s: SEQUENCE OF Qual_used_id; as_id: Handler_id_NULL *> Return_st <: STM; <* FIELDS OF Return_st as_exp: EXP_NULL; *> For_st <: STM_WSS; <* FIELDS OF For_st as_id: For_id; as_from: EXP; as_to: EXP; as_by: By_NULL; *> By <: SRC_NODE_C; <* FIELDS OF By as_exp: EXP; *> By_NULL = By; If_st <: STM_WSS; <* FIELDS OF If_st as_exp: EXP; as_elsif_s: SEQUENCE OF Elsif; as_else: Else_stm_NULL; *> Elsif <: SUBSTM_WSS; <* FIELDS OF Elsif as_exp: EXP; *> Lock_st <: STM_WSS; <* FIELDS OF Lock_st as_exp: EXP; *> Loop_st <: STM_WSS; <* FIELDS OF Loop_st *> Repeat_st <: STM_WSS; <* FIELDS OF Repeat_st as_exp: EXP; *> Try_st <: STM_WSS; <* FIELDS OF Try_st as_try_tail: TRY_TAIL; *> TRY_TAIL <: SUBSTM_WSS; Try_except <: TRY_TAIL; <* FIELDS OF Try_except as_handler_s: SEQUENCE OF Handler; as_else: Else_stm_NULL *> Try_finally <: TRY_TAIL; While_st <: STM_WSS; <* FIELDS OF While_st as_exp: EXP; *> With_st <: STM_WSS; <* FIELDS OF With_st as_binding_s: SEQUENCE OF Binding; *> Binding <: SRC_NODE_C; <* FIELDS OF Binding as_id: With_id; as_exp: EXP *> Block <: STM_WSS; <* FIELDS OF Block as_decl_s: SEQUENCE OF DECL_REVL; *> Block_NULL = Block;Syntax errors are handled in part by new subtypes of a class namedBad_Class
. I.e. a syntactically incorrect AST may contain an instance ofBad_Class
, wherever an attribute of typeClass
could appear.
Bad_EXP <: EXP; Bad_M3TYPE <: M3TYPE; Bad_STM <: STM; END M3AST_AS.