/* * Copyright (c) 2002, The Tendra Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Crown Copyright (c) 1997, 1998 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/producers/cpp/syntax/syntax.sid,v 1.9 2005/10/16 07:47:46 stefanf Exp $ */ /* * C++ SYNTAX * * This module contains the syntax for the C++ language. */ /* * TYPE DECLARATIONS * * The types BOOL, COUNT and LEX are natural types arising from the * parser. The remaining types directly correspond to types within the * main program, or composite types formed from them. */ %types% ACCESS; ACCESSES; BOOL; BTYPE; CONDITION; COUNT; CV; DECL; DSPEC; EXP; IDENTIFIER; KEY; LEX; LINKAGE; LIST-EXP; LIST-TYPE; NAMESPACE; NUMBER; OFFSET; QUALIFIER; TEMPLATE; TYPE; /* * LIST OF TERMINALS * * This list of terminals corresponds to that given in symbols.h and * psyntax.h. */ %terminals% !unknown; /* Identifiers */ identifier: () -> (:IDENTIFIER); type-name: () -> (:IDENTIFIER); namespace-name: () -> (:IDENTIFIER); statement-name: () -> (:IDENTIFIER); destructor-name: () -> (:IDENTIFIER); template-id: () -> (:IDENTIFIER); template-type: () -> (:IDENTIFIER); /* Nested name specifiers */ nested-name: () -> (:NAMESPACE); full-name: () -> (:NAMESPACE); nested-name-star: () -> (:IDENTIFIER); full-name-star: () -> (:IDENTIFIER); /* Literals */ !char-lit; !wchar-lit; !string-lit; !wstring-lit; !integer-lit; /* Literal expressions */ char-exp: () -> (:EXP); wchar-exp: () -> (:EXP); string-exp: () -> (:EXP); wstring-exp: () -> (:EXP); integer-exp: () -> (:EXP); floating-exp: () -> (:EXP); /* Token applications */ complex-exp: () -> (:EXP); complex-stmt: () -> (:EXP); complex-type: () -> (:TYPE); /* Target-dependent preprocessing directives */ hash-if: () -> (:EXP); hash-elif: () -> (:EXP); hash-else; hash-endif; hash-pragma; /* End of file markers */ !newline; eof; /* Symbols */ and-1; and-eq-1; arrow; assign; !backslash; close-brace-1; close-round; close-square-1; colon; comma; compl-1; div; div-eq; dot; ellipsis; eq; greater; greater-eq; !hash-1; !hash-hash-1; less; less-eq; logical-and-1; logical-or-1; lshift; lshift-eq; minus; minus-eq; minus-minus; not-1; not-eq-1; open-brace-1; open-round; open-square-1; or-1; or-eq-1; plus; plus-eq; plus-plus; question; rem; rem-eq; rshift; rshift-eq; semicolon; star; star-eq; xor-1; xor-eq-1; arrow-star; colon-colon; dot-star; abs; max; min; /* Digraphs */ !close-brace-2; !close-square-2; !hash-2; !hash-hash-2; !open-brace-2; !open-square-2; /* C keywords */ auto; break; case; char; const; continue; default; do; double; else; enum; extern; float; for; goto; if; int; long; register; return; short; signed; sizeof; static; struct; switch; typedef; union; unsigned; void; volatile; while; /* C99 keywords */ restrict; /* C++ keywords */ asm; bool; catch; class; const-cast; delete; dynamic-cast; explicit; export; false; friend; inline; mutable; namespace; new; operator; private; protected; public; reinterpret-cast; static-cast; template; this; throw; true; try; typeid; typename; using; virtual; wchar-t; /* ISO keywords */ !and-2; !and-eq-2; !compl-2; !logical-and-2; !logical-or-2; !not-2; !not-eq-2; !or-2; !or-eq-2; !xor-2; !xor-eq-2; /* TenDRA keywords */ !accept; !after; alignof; !all; !allow; !ambiguous; !analysis; !argument; !arith-cap; !array; !as; !assert; !assignment; !begin; !bitfield; !block; bottom; !cast; !character; !class-cap; !code; !comment; !compatible; !complete; !compute; !conditional; !conversion; !decimal; !decl; !define; !define-cap; !defined; !definition; !depth; !directive; !directory; !disallow; discard; !dollar; !either; !elif; ellipsis-exp; !end; !endif; !environment; !equality; !error; !escape; exhaustive; !exp-cap; !explain; !extend; !external; !extra; fall; !file; !float-cap; !forward; !func-cap; !func-id; !function; !hexadecimal; !hiding; !ident; !identif; !ifdef; !ifndef; !ignore; !implement; !implicit; !import; !include; !includes; !include-next; !incompatible; !incomplete; !indented; !initialization; !integer; !interface; !internal; !into; !int-cap; !keyword; !limit; !line; !linkage; !lit; !longlong; !lvalue; !macro; !main; !member; !member-cap; !name; !nat-cap; !nested; !nline; !no; !no-def; !object; !octal; !of; !off; !on; !option; !overflow; overload; !pointer; !postpone; !pragma; !pragma-2; !precedence; !preserve; !printf; !proc-cap; !promote; !promoted; !prototype; ptrdiff-t; !qualifier; !quote; reachable; !reference; !reject; !representation; !reset; !resolution; !rvalue; !scalar-cap; !scanf; set; size-t; !size-t-2; !sort; !std; !stmt-cap; !string; !struct-cap; !suspend; !tag; !tag-cap; !tendra; !text; !this-name; !token; !type; !type-cap; !typeof; !un-known; !unassert; !undef; !unify; !union-cap; !unmatched; !unpostpone; unreachable; unused; !use; !value; !variable; !variety-cap; !va-args; !volatile-t; vtable; !warning; weak; !writeable; !zzzz; /* Miscellaneous symbols */ !array-op; !builtin-file; !builtin-line; !close-template; !cond-op; !delete-full; !delete-array; !delete-array-full; !func-op; !hash-op; !hash-hash-op; inset-start; inset-end; !macro-arg; !new-full; !new-array; !new-array-full; !open-init; !open-template; !zzzzzz; /* * ALTERNATIVE REPRESENTATIONS * * The ISO keywords and digraphs will have been replaced by their primary * representations by this stage. These rules are effectively identities * for these alternatives. Don't try removing them - SID gets very * confused. */ %productions% close-brace = { close-brace-1; }; close-square = { close-square-1; }; open-brace = { open-brace-1; }; open-square = { open-square-1; }; and = { and-1; }; and-eq = { and-eq-1; }; compl = { compl-1; }; logical-and = { logical-and-1; }; logical-or = { logical-or-1; }; not = { not-1; }; not-eq = { not-eq-1; }; or = { or-1; }; or-eq = { or-eq-1; }; xor = { xor-1; }; xor-eq = { xor-eq-1; }; ellipsis-aux = { ellipsis; || ellipsis-exp; }; /* * LEXICAL TOKENS * * These actions give the lexical token numbers for various symbols. */ : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); : () -> (:LEX); /* * EXPECTED SYMBOLS * * These rules are used when a certain symbol is expected. If it is * not present then the action expected is called with the appropriate * lexical token number. */ : (:LEX) -> (); : () -> (); : () -> (); close-round-x = { close-round; ## t = ; (t); }; close-square-x = { close-square; ## t = ; (t); }; colon-x = { colon; ## t = ; (t); }; open-round-x = { open-round; ## t = ; (t); }; semicolon-x = { semicolon; ## t = ; (t); }; /* * IDENTIFIERS * * The identifier terminal is exclusive - it does not include those * identifiers which are actually type and namespace names. This rule * gives all identifiers and sets the appropriate identifier type. */ any-identifier: () -> (id: IDENTIFIER) = { id = identifier; || id = type-name; || id = namespace-name; || id = statement-name; }; /* * NAMESPACE SPECIFIERS * * The nested-name-specifiers are handled by the terminals nested-name * (corresponding to nested-name-specifier in the specification) and * full-name (corresponding to:: nested-name-specifier). These rules * give various combinations of these specifiers. */ : () -> (:NAMESPACE); : () -> (:NAMESPACE); : (:NAMESPACE) -> (); : (:NAMESPACE) -> (); nonempty-nested-name: () -> (ns: NAMESPACE) = { ns = nested-name; (ns); || ns = full-name; (ns); }; any-nested-name: () -> (ns: NAMESPACE) = { ns = nonempty-nested-name; || colon-colon; ns = ; }; any-nested-name-opt: () -> (ns: NAMESPACE) = { ns = any-nested-name; || ns = ; }; /* * LITERAL EXPRESSIONS * * These rules describe the literal expressions. These are the integer * and floating point literals, the character and string literals, plus * the boolean literals true and false. Concatenation of adjacent string * literals has already been performed. */ : () -> (:EXP); : () -> (:EXP); integer-literal: () -> (e: EXP) = { e = integer-exp; }; character-literal: () -> (e: EXP) = { e = char-exp; || e = wchar-exp; }; floating-literal: () -> (e: EXP) = { e = floating-exp; }; string-literal: () -> (e: EXP) = { e = string-exp; || e = wstring-exp; }; boolean-literal: () -> (e: EXP) = { false; e = ; || true; e = ; }; literal: () -> (e: EXP) = { e = integer-literal; || e = character-literal; || e = floating-literal; || e = string-literal; || e = boolean-literal; }; /* * OPERATOR AND CONVERSION FUNCTION IDENTIFIERS * * These rules describe the overloaded operator and conversion function * names. These consist of 'operator' followed by one of a large number * of operator names (including a few illegal ones which are immediately * reported using error_overload) or a type name. Note the use of the * predicate is_array to distinguish 'operator new []' from 'operator * new [expression]'. The rule operator-id subsumes both the rules * operator-function-id and conversion-function-id from the grammar. */ : () -> (:BOOL); : () -> (:BOOL); : (:BOOL) -> (:BOOL); : (:BOOL) -> (); : () -> (:QUALIFIER, :BOOL); : (:QUALIFIER, :BOOL) -> (); : () -> (); : (:LEX) -> (); : (:LEX) -> (:IDENTIFIER); : (:TYPE, :BOOL) -> (:IDENTIFIER); : () -> (:IDENTIFIER); conversion-type-id: () -> (:TYPE); operator-name: () -> (op: LEX) = { op = ; { and; || and-eq; || arrow; || arrow-star; || assign; || comma; || compl; || div; || div-eq; || eq; || greater; || greater-eq; || less; || less-eq; || logical-and; || logical-or; || lshift; || lshift-eq; || minus; || minus-eq; || minus-minus; || not; || not-eq; || or; || or-eq; || plus; || plus-eq; || plus-plus; || rem; || rem-eq; || rshift; || rshift-eq; || star; || star-eq; || xor; || xor-eq; || abs; || max; || min; }; || open-round; close-round-x; op = ; || open-square; close-square-x; op = ; || new; op = ; || delete; op = ; || new; ? = ; open-square; close-square-x; op = ; || delete; ? = ; open-square; close-square-x; op = ; || op = ; { dot; || dot-star; || colon-colon; || colon; || alignof; || sizeof; || typeid; || vtable; }; (op); || question; colon-x; op = ; (op); }; operator-id: () -> (id: IDENTIFIER) = { operator; (i, b) = ; td = ; { t = conversion-type-id; d = (td); tid = (t, d); || op = operator-name; (td); tid = (op); }; (i, b); id = tid; }; /* * IDENTIFIER EXPRESSIONS * * These rules describe the qualified and unqualified identifier * expressions. The identifier qualifiers have been reworked slightly * to make it clear exactly what is being qualified when and by what. */ : () -> (:BOOL); : () -> (:BOOL); : (:NAMESPACE, :IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER) -> (:IDENTIFIER); : (:NAMESPACE, :IDENTIFIER, :BOOL) -> (:IDENTIFIER); : (:NAMESPACE) -> (); : (:NAMESPACE) -> (); : (:NAMESPACE) -> (); : () -> (:IDENTIFIER); unqualified-type: () -> (:IDENTIFIER); any-qualified-type: () -> (:IDENTIFIER); qualified-stmt-name: () -> (:IDENTIFIER); template-opt: (ns: NAMESPACE) -> (t: BOOL) = { (ns); template; t = ; || t = ; }; nested-id: (ns: NAMESPACE) -> (id: IDENTIFIER) = { id = identifier; || id = namespace-name; || id = destructor-name; || id = template-id; || (ns); id = operator-id; (ns); }; unqualified-id: () -> (id: IDENTIFIER) = { uid = identifier; id = (uid); || uid = namespace-name; id = (uid); || uid = operator-id; id = (uid); || uid = destructor-name; id = (uid); || uid = template-id; id = (uid); }; qualified-id: () -> (id: IDENTIFIER) = { ns = nested-name; q = template-opt (ns); uid = nested-id (ns); (ns); id = (ns, uid, q); }; full-qualified-id: () -> (id: IDENTIFIER) = { ns = full-name; q = template-opt (ns); uid = nested-id (ns); (ns); id = (ns, uid, q); }; top-qualified-id: () -> (id: IDENTIFIER) = { colon-colon; ns = ; q = template-opt (ns); uid = nested-id (ns); id = (ns, uid, q); }; id-expression: () -> (id: IDENTIFIER) = { id = unqualified-id; || id = qualified-id; || id = full-qualified-id; || id = top-qualified-id; }; any-qualified-id: () -> (id: IDENTIFIER) = { id = id-expression; || id = unqualified-type; || id = any-qualified-type; || id = qualified-stmt-name; }; id-entry: () -> (id: IDENTIFIER) = { id = any-qualified-id; ## ; id = ; }; /* * PRIMARY EXPRESSIONS * * This rule describes the primary expressions. These include the * literals, the identity expressions, the this expression and the * parenthesised expressions. The assertion expressions are an * extension. */ : () -> (:EXP); : () -> (:EXP); : () -> (); : (:EXP) -> (:EXP); : (:IDENTIFIER) -> (:EXP); expression: () -> (:EXP); primary-expression: () -> (e: EXP) = { e = literal; || this; e = ; || id = id-expression; e = (id); || ellipsis-exp; e = ; || open-round; ; a = expression; e = (a); close-round; || e = complex-exp; }; /* * EXPRESSION LISTS * * These rules describes the lists of expressions. Note that the * constituents are assignment-expressions so that any commas are list * separators rather than comma operators. */ : () -> (:LIST-EXP); : (:EXP, :LIST-EXP) -> (:LIST-EXP); assignment-expression: () -> (:EXP); expression-list: () -> (p: LIST-EXP) = { e = assignment-expression; { comma; q = expression-list; || q = ; }; p = (e, q); }; expression-list-opt: () -> (p: LIST-EXP) = { p = expression-list; || p = ; }; /* * QUALIFIED TYPE NAMES * * These rules describe the qualified and unqualified type names. */ any-type-name: () -> (id: IDENTIFIER) = { id = type-name; || id = template-type; }; unqualified-type: () -> (id: IDENTIFIER) = { tid = any-type-name; id = (tid); }; qualified-type: () -> (id: IDENTIFIER) = { ns = nested-name; tid = any-type-name; (ns); id = (ns, tid); }; full-qualified-type: () -> (id: IDENTIFIER) = { ns = full-name; tid = any-type-name; (ns); id = (ns, tid); }; top-qualified-type: () -> (id: IDENTIFIER) = { colon-colon; tid = any-type-name; ns = ; id = (ns, tid); }; any-qualified-type: () -> (id: IDENTIFIER) = { id = qualified-type; || id = full-qualified-type; || id = top-qualified-type; }; /* * FIELD SELECTOR EXPRESSIONS * * These rules are used to perform field selector look-up following a * '.' or '->' operator. The input namespace gives the class being * selected from (or the null namespace in case of an error). Note * the provisions for dummy destructor calls. */ : () -> (:BTYPE); : (:NAMESPACE) -> (:IDENTIFIER); : (:IDENTIFIER, :BTYPE, :IDENTIFIER, :BTYPE) -> (:IDENTIFIER); any-class-name: () -> (:IDENTIFIER); base-type-specifier: () -> (:BTYPE); field-type-expression: (ns: NAMESPACE) -> (id: IDENTIFIER) = { tid = unqualified-type; id = (ns, tid); || tid = qualified-type; id = (ns, tid); || id = full-qualified-type; || id = top-qualified-type; }; pseudo-destr-prefix: (ns: NAMESPACE) -> (id: IDENTIFIER, bt: BTYPE, cns: NAMESPACE) = { cns = any-nested-name; id = (cns); bt = ; || id = field-type-expression (ns); colon-colon; bt = ; cns = ns; || bt = base-type-specifier; colon-colon; id = ; cns = ns; }; pseudo-destr-suffix: () -> (id: IDENTIFIER, bt: BTYPE) = { id = any-class-name; bt = ; || bt = base-type-specifier; id = ; }; field-id-expression: (ns: NAMESPACE) -> (id: IDENTIFIER) = { uid = nested-id (ns); ; id = (ns, uid); || qid = qualified-id; id = (ns, qid); || id = full-qualified-id; || id = top-qualified-id; || id = field-type-expression (ns); || (id1, bt1, ns1) = pseudo-destr-prefix (ns); (i, b) = ; compl; (id2, bt2) = pseudo-destr-suffix; (i, b); uid = (id1, bt1, id2, bt2); id = (ns1, uid); || compl; (id2, bt2) = pseudo-destr-suffix; ; id = (id2, bt2, id2, bt2); }; /* * POSTFIX EXPRESSIONS * * These rules describes the postfix expressions. These include array * indexing, function calls and function style casts, field selectors, * postfix increment and decrement operations, new style casts and * type identification operators. */ : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP, :LIST-EXP) -> (:EXP); : (:TYPE, :EXP, :COUNT) -> (:EXP); : (:TYPE, :LIST-EXP) -> (:EXP); : (:TYPE, :EXP, :COUNT) -> (:EXP); : (:TYPE, :EXP, :COUNT) -> (:EXP); : (:TYPE, :EXP, :COUNT) -> (:EXP); : (:TYPE, :EXP, :COUNT) -> (:EXP); : (:EXP, :LEX, :COUNT) -> (:EXP); : (:TYPE, :LEX, :COUNT) -> (:EXP); : (:EXP) -> (:EXP, :TYPE, :NAMESPACE); : (:EXP, :TYPE, :NAMESPACE, :IDENTIFIER, :BOOL) -> (:EXP); : (:EXP) -> (:EXP, :TYPE, :NAMESPACE); : (:EXP, :TYPE, :NAMESPACE, :IDENTIFIER, :BOOL) -> (:EXP); : () -> (); : () -> (:COUNT); : () -> (:COUNT); : (:COUNT) -> (:COUNT); : (:COUNT) -> (:COUNT); : () -> (); : () -> (); simple-type-id: () -> (:TYPE); type-id: () -> (:TYPE, :COUNT); type-id-false: () -> (:TYPE, :COUNT); type-id-true: () -> (:TYPE, :COUNT); cast-operand: () -> (t: TYPE, e: EXP, n: COUNT) = { less; (t, n) = type-id; greater; open-round; e = expression; close-round; }; typeid-expression: (op: LEX) -> (e: EXP) = { ; n1 = ; m1 = ; open-round; { a = expression; close-round; n2 = (n1); c = (a, op, n2); || (t, m2) = type-id-true; close-round; c = (t, op, m2); }; ; e = c; }; postfix-expression: () -> (e: EXP) = { e = primary-expression; || a = postfix-expression; open-square; b = expression; close-square; e = (a, b); || a = postfix-expression; open-round; p = expression-list-opt; close-round; e = (a, p); || t = simple-type-id; open-round; p = expression-list-opt; close-round; e = (t, p); || a = postfix-expression; (b, t, ns) = (a); dot; q = template-opt (ns); id = field-id-expression (ns); e = (b, t, ns, id, q); ; || a = postfix-expression; (b, t, ns) = (a); arrow; q = template-opt (ns); id = field-id-expression (ns); e = (b, t, ns, id, q); ; || a = postfix-expression; plus-plus; e = (a); || a = postfix-expression; minus-minus; e = (a); || dynamic-cast; (t, a, n) = cast-operand; e = (t, a, n); || static-cast; (t, a, n) = cast-operand; e = (t, a, n); || reinterpret-cast; (t, a, n) = cast-operand; e = (t, a, n); || const-cast; (t, a, n) = cast-operand; e = (t, a, n); || typeid; op = ; e = typeid-expression (op); || vtable; op = ; e = typeid-expression (op); }; /* * NEW EXPRESSIONS * * These rules describe the new expressions. These consist of a new * operator followed by an optional placement, a type identifier (either * a simplified form or a bracketed full form), and an optional initialiser * list. Note that the second and third components have been combined * as the single rule new-place-and-type. */ : () -> (:EXP); : (:BOOL, :LIST-EXP, :TYPE, :COUNT, :BOOL, :EXP) -> (:EXP); : () -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:TYPE, :LIST-EXP) -> (:EXP); : (:TYPE) -> (:EXP); new-type-id: () -> (:TYPE, :COUNT); new-initialiser-opt: (t: TYPE) -> (e: EXP) = { open-round; p = expression-list-opt; close-round; e = (t, p); || e = (t); }; colon-colon-opt: () -> (b: BOOL) = { colon-colon; b = ; || b = ; }; new-place-and-type: () -> (p: LIST-EXP, t: TYPE, n: COUNT) = { open-round; { p = expression-list; close-round; td = ; { open-round; (s, m) = type-id; close-round; || (s, m) = new-type-id; }; (td); t = s; n = m; || (t, n) = type-id-false; close-round; p = ; }; || (t, n) = new-type-id; p = ; }; new-expression: () -> (e: EXP) = { b = colon-colon-opt; new; td = ; (p, t, n) = new-place-and-type; d = (td); s = ; i = new-initialiser-opt (t); a = (s, i); e = (b, p, t, n, d, a); }; /* * DELETE EXPRESSIONS * * This rule describes the delete expressions. These consist of a * delete operator followed by the expression to be deleted. The * anachronistic form of the 'delete []' operator, in which the array * size had to be given, has been included in the grammar, to be weeded * out by the action anachronism_delete. */ : (:BOOL, :LEX, :EXP) -> (:EXP); : (:EXP) -> (); cast-expression: () -> (:EXP); unary-expression: () -> (:EXP); delete-operator: () -> (op: LEX) = { delete; op = ; || delete; open-square; close-square; op = ; || delete; open-square; e = expression; (e); close-square; op = ; }; delete-expression: () -> (e: EXP) = { b = colon-colon-opt; op = delete-operator; a = cast-expression; e = (b, op, a); }; /* * UNARY EXPRESSIONS * * These rules describe the unary expressions. These include the simple * unary operations (indirection, address, unary plus, unary minus, logical * negation and bitwise complement), the prefix increment and decrement * operations and sizeof expressions, as well as the new and delete * expressions. */ : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:LEX, :EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:LEX, :TYPE, :EXP, :COUNT) -> (:EXP); : (:LEX, :EXP, :COUNT) -> (:TYPE); sizeof-expression: (op: LEX) -> (e: EXP) = { ; n1 = ; m1 = ; { a = unary-expression; n2 = (n1); m2 = (m1); t = (op, a, n2); c = (op, t, a, m2); || open-round; (t, m2) = type-id-true; a = ; c = (op, t, a, m2); close-round; }; ; e = c; }; unary-operator: () -> () = { plus; || minus; || compl; || abs; }; unary-expression: () -> (e: EXP) = { e = postfix-expression; || plus-plus; a = cast-expression; e = (a); || minus-minus; a = cast-expression; e = (a); || star; a = cast-expression; e = (a); || and; a = cast-expression; e = (a); || not; a = cast-expression; e = (a); || op = ; unary-operator; a = cast-expression; e = (op, a); || sizeof; op = ; e = sizeof-expression (op); || alignof; op = ; e = sizeof-expression (op); || e = new-expression; || e = delete-expression; }; /* * CAST EXPRESSIONS * * This rule describes the traditional style cast expressions, consisting * of a bracketed type identifier followed by an expression. The ignore * keyword is an extension which is semantically equivalent to casting * to void. */ : (:EXP) -> (:EXP); cast-expression: () -> (e: EXP) = { e = unary-expression; || open-round; (t, n) = type-id-false; close-round; a = cast-expression; e = (t, a, n); || discard; a = cast-expression; e = (a); }; /* * POINTER MEMBER EXPRESSIONS * * This rule describes the pointer to member expressions, consisting of * the '.*' and '->*' operators. */ : () -> (); : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); pm-expression: () -> (e: EXP) = { e = cast-expression; || a = pm-expression; dot-star; ; b = cast-expression; e = (a, b); || a = pm-expression; arrow-star; ; b = cast-expression; e = (a, b); }; /* * MULTIPLICATIVE EXPRESSIONS * * This rule describes the multiplicative expressions. These include * the division and remainder operations, as well as multiplication. */ : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); multiplicative-expression: () -> (e: EXP) = { e = pm-expression; || a = multiplicative-expression; star; b = pm-expression; e = (a, b); || a = multiplicative-expression; div; b = pm-expression; e = (a, b); || a = multiplicative-expression; rem; b = pm-expression; e = (a, b); }; /* * ADDITIVE EXPRESSIONS * * This rule describes the additive expressions. These include both the * addition and the subtraction operations. */ : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); additive-expression: () -> (e: EXP) = { e = multiplicative-expression; || a = additive-expression; plus; b = multiplicative-expression; e = (a, b); || a = additive-expression; minus; b = multiplicative-expression; e = (a, b); }; /* * SHIFT EXPRESSIONS * * This rule describes the shift expressions. Both left and right shifts * are included. */ : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); shift-expression: () -> (e: EXP) = { e = additive-expression; || a = shift-expression; lshift; b = additive-expression; e = (a, b); || a = shift-expression; rshift; b = additive-expression; e = (a, b); }; /* * RELATIONAL EXPRESSIONS * * These rules describe the relational expressions, less than, greater * than, less than or equal and greater than or equal. */ : (:LEX, :EXP, :EXP) -> (:EXP); relational-operator: () -> () = { less; || greater; || less-eq; || greater-eq; }; relational-expression: () -> (e: EXP) = { e = shift-expression; || a = relational-expression; op = ; relational-operator; b = shift-expression; e = (op, a, b); }; /* * EQUALITY EXPRESSIONS * * These rules describe the equality expressions, equal and not equal. */ : (:LEX, :EXP, :EXP) -> (:EXP); equality-operator: () -> () = { eq; || not-eq; }; equality-expression: () -> (e: EXP) = { e = relational-expression; || a = equality-expression; op = ; equality-operator; b = relational-expression; e = (op, a, b); }; /* * MAXIMUM AND MINIMUM EXPRESSIONS (EXTENSION) * * These rules describes the maximum and minimum expressions. */ : (:LEX, :EXP, :EXP) -> (:EXP); maxmin-operator: () -> () = { max; || min; }; maxmin-expression: () -> (e: EXP) = { e = equality-expression; || a = maxmin-expression; op = ; maxmin-operator; b = equality-expression; e = (op, a, b); }; /* * AND EXPRESSIONS * * This rule describes the bitwise and expressions. */ : (:EXP, :EXP) -> (:EXP); and-expression: () -> (e: EXP) = { e = maxmin-expression; || a = and-expression; and; b = maxmin-expression; e = (a, b); }; /* * EXCLUSIVE OR EXPRESSIONS * * This rule describes the bitwise exclusive or expressions. */ : (:EXP, :EXP) -> (:EXP); exclusive-or-expression: () -> (e: EXP) = { e = and-expression; || a = exclusive-or-expression; xor; b = and-expression; e = (a, b); }; /* * INCLUSIVE OR EXPRESSIONS * * This rule describes the bitwise inclusive or expressions. */ : (:EXP, :EXP) -> (:EXP); inclusive-or-expression: () -> (e: EXP) = { e = exclusive-or-expression; || a = inclusive-or-expression; or; b = exclusive-or-expression; e = (a, b); }; /* * LOGICAL AND EXPRESSIONS * * This rule describes the logical and expressions. */ : (:EXP, :EXP) -> (:EXP); logical-and-expression: () -> (e: EXP) = { e = inclusive-or-expression; || a = logical-and-expression; logical-and; b = inclusive-or-expression; e = (a, b); }; /* * LOGICAL OR EXPRESSIONS * * This rule describes the logical or expressions. */ : (:EXP, :EXP) -> (:EXP); logical-or-expression: () -> (e: EXP) = { e = logical-and-expression; || a = logical-or-expression; logical-or; b = logical-and-expression; e = (a, b); }; /* * CONDITIONAL EXPRESSIONS * * This rule describes the conditional expressions, consisting of the * '?:' operator. */ : (:EXP, :EXP, :EXP) -> (:EXP); conditional-expression: () -> (e: EXP) = { e = logical-or-expression; || c = logical-or-expression; question; a = expression; colon; b = assignment-expression; e = (c, a, b); }; /* * THROW EXPRESSIONS * * This rule describes the throw expressions. These consist of 'throw' * followed by an optional expression. The extension 'throw type-id' * has also been added. */ : (:EXP) -> (:EXP); : (:TYPE, :COUNT) -> (:EXP); throw-expression: () -> (e: EXP) = { throw; { a = assignment-expression; || (t, n) = type-id-false; a = (t, n); || a = ; }; e = (a); }; /* * ASSIGNMENT EXPRESSIONS * * These rules describe the assignment expressions. These include both * simple assignment and the 'operate and becomes' operators like '+='. */ : (:EXP, :EXP) -> (:EXP); : (:LEX, :EXP, :EXP) -> (:EXP); assignment-operator: () -> () = { and-eq; || div-eq; || lshift-eq; || minus-eq; || or-eq; || plus-eq; || rem-eq; || rshift-eq; || star-eq; || xor-eq; }; assignment-expression: () -> (e: EXP) = { e = conditional-expression; || a = logical-or-expression; assign; b = assignment-expression; e = (a, b); || a = logical-or-expression; op = ; assignment-operator; b = assignment-expression; e = (op, a, b); || e = throw-expression; }; expression-entry: () -> (e: EXP) = { e = assignment-expression; ## ; e = ; }; /* * FLOW ANALYSIS EXPRESSIONS (EXTENSION) * * This rule describes the flow analysis expressions, which are an * extension to the standard syntax. These consist of the assignment * expressions, plus operations for setting and discarding values. */ : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); flow-expression: () -> (e: EXP) = { set; open-round; a = expression; e = (a); close-round; || unused; open-round; a = expression; e = (a); close-round; }; inset-flow-expression: () -> (e: EXP) = { inset-start; set; a = expression; e = (a); inset-end; || inset-start; unused; a = expression; e = (a); inset-end; }; inset-flow-statement: () -> (e: EXP) = { inset-start; set; a = expression; e = (a); semicolon; inset-end; || inset-start; unused; a = expression; e = (a); semicolon; inset-end; }; /* * EXPRESSIONS * * This rule describes the top level expressions. These are derived * from the flow-expressions by the addition of the comma operator. */ : (:LIST-EXP) -> (:EXP); comma-expression-head: () -> (e: EXP) = { e = assignment-expression; comma; || e = flow-expression; || e = inset-flow-expression; }; comma-expression-tail: () -> (p: LIST-EXP) = { a = assignment-expression; q = ; p = (a, q); || a = comma-expression-head; q = comma-expression-tail; p = (a, q); }; expression: () -> (e: EXP) = { e = assignment-expression; || a = comma-expression-head; q = comma-expression-tail; p = (a, q); e = (p); }; /* * INITIALISER EXPRESSIONS * * An initialiser expression consists of an assignment expression * with all its temporary variables bound to it. */ initialiser-expression: () -> (e: EXP) = { e = assignment-expression; }; /* * CONSTANT EXPRESSIONS * * This rule describes the constant expressions. Lexically these are * identical to the conditional-expressions, but with restrictions on * the permitted operands. Constant expressions are identified by * evaluation - whenever a valid constant expression is encountered it * is evaluated to give an integer literal expression. */ : (:EXP) -> (:EXP); constant-expression: () -> (e: EXP) = { a = conditional-expression; e = (a); }; /* * LABELLED STATEMENTS * * This rule describes the labelled statements. These include the case * and default statements as well as the simple labels. Note that the * statements following the labels are only the first component of the * label body. Actually imposing some structure on the labelled statements * is the most difficult part of the statement processing. */ : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : () -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:IDENTIFIER) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : () -> (); : () -> (); : () -> (); statement: () -> (:EXP); fall-check: () -> () = { fall; ; || fall; semicolon; ; || $; }; labelled-statement: () -> (e: EXP) = { fall-check; case; c = constant-expression; a = (c); ; colon; b = statement; e = (a, b); || fall-check; default; a = ; ; colon; b = statement; e = (a, b); || id = any-identifier; ; ; a = (id); colon; b = statement; e = (a, b); }; /* * EXPRESSION STATEMENTS * * This rule describes the expression statements, consisting of an optional * expression followed by a semicolon. There is an ambiguity between empty * expression statements (i.e. just a semicolon) and empty declaration * statements. We have resolved this by explicitly making declaration * statements non-empty. */ : (:EXP) -> (:EXP); : () -> (:EXP); : () -> (:BOOL); : (:BOOL) -> (); block-expression: () -> (e: EXP) = { e = expression; || e = flow-expression; }; expression-statement: () -> (e: EXP) = { a = block-expression; r = ; e = (a); ; semicolon; || a = inset-flow-statement; r = ; e = (a); ; || semicolon; e = ; }; /* * COMPOUND STATEMENTS * * These rules describe the compound statements, consisting of a list of * statements enclosed within braces. Note that compound statements * automatically define a local scope. */ : () -> (:EXP); : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP) -> (); : (:EXP) -> (); statement-seq-opt: (c: EXP) -> (e: EXP) = { a = statement; b = (c, a); e = statement-seq-opt (b); || e = c; }; compound-statement: () -> (e: EXP) = { c = ; open-brace; (c); a = statement-seq-opt (c); close-brace; e = (a); ; }; /* * LOCAL STATEMENT SCOPES * * Several statements, in addition to the compound statements, form local * scopes (for example, the body of an iteration statement). This rule * describes such scopes, the initial scope expression begin passed in as * c to avoid predicate problems. Note that local scopes which are also * compound statements are treated differently from other (simple) * statements. */ simple-statement: () -> (:EXP); scoped-stmt-body: (c: EXP) -> (e: EXP) = { open-brace; (c); e = statement-seq-opt (c); close-brace; || a = simple-statement; e = (c, a); }; scoped-statement: (c: EXP) -> (e: EXP) = { a = scoped-stmt-body (c); e = (a); ; ## ; e = (c); ; }; /* * DECLARATION STATEMENTS * * This rule describes the (non-empty) declaration statements, consisting * of just a declaration. See expression-statement for a discussion of * empty statements. The look-ahead required to distinguish declaration- * statements from expression-statements is implemented using the predicate * is_decl_statement. */ : () -> (:BOOL); : () -> (:DSPEC); : () -> (:TYPE); : (:EXP) -> (:EXP); declaration-basic: (:TYPE, :DSPEC) -> (); declaration-nonempty: (:TYPE, :DSPEC) -> (:EXP); declaration-statement: () -> (e: EXP) = { ? = ; ds = ; t = ; a = declaration-nonempty (t, ds); e = (a); ; }; simple-declaration: () -> (e: EXP) = { ? = ; ds = ; t = ; declaration-basic (t, ds); a = ; e = (a); }; /* * TARGET DEPENDENT CONDITIONAL COMPILATIONS * * These rules describe the unresolved target dependent conditional * compilations. Note that these must be structured, as opposed to the * normal unstructured preprocessing directives. Any braces required * to make the lists of statements in target dependent conditional * bodies into compound statements are automatically inserted by the * preprocessor. */ : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP) -> (); : () -> (); : (:EXP) -> (); target-condition-head: () -> (e: EXP, p: EXP, r: BOOL) = { c = hash-if; p = (c); r = ; a = compound-statement; (r); e = (c, a); || (a, p, r) = target-condition-head; c = hash-elif; (c); s = ; b = compound-statement; (r); e = (a, c, b); }; target-condition: () -> (e: EXP) = { (a, p, r) = target-condition-head; { hash-else; ; s = ; b = compound-statement; || b = ; }; (p); hash-endif; (r); e = (a, b); }; /* * SELECTION STATEMENTS * * These rules describe the selection statements, consisting of the if * and switch statements, plus the target dependent conditionals above. * The way that the dangling else problem is dealt with is interesting. * A simple optional else-block leads to an ambiguity, however an * exception handler gives precisely what is required. To paraphrase, * an if statement always has an associated else, except when it doesn't. */ : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : () -> (); : () -> (:EXP); : (:EXP) -> (:EXP); : (:EXP, :EXP, :BOOL) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : () -> (:CONDITION); : (:CONDITION) -> (); condition-declaration: () -> (:EXP); condition: () -> (e: EXP) = { e = expression; || e = condition-declaration; }; selection-statement: () -> (e: EXP) = { if; x = ; r = ; open-round-x; c = condition; a = (c); close-round; bs = ; bc = (bs, c); b = scoped-statement (bc); (r); d = (a, b); { else; ; fs = ; fc = (fs, c); f = scoped-statement (fc); ## f = ; }; (r); e = (d, f); (x); ; || switch; r = ; open-round; c = condition; a = (c); close-round; { exhaustive; ex = ; || ex = ; }; bs = ; bc = (bs, c); b = scoped-statement (bc); (r); e = (a, b, ex); ; || e = target-condition; ; }; /* * ITERATION STATEMENTS * * These rules describe the iteration statements, consisting of the * while, do and for statements. */ : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : () -> (:EXP); : (:EXP, :EXP, :EXP) -> (:EXP); : () -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); : (:EXP, :EXP) -> (:EXP); for-init-statement: () -> (e: EXP) = { e = expression-statement; || e = simple-declaration; }; for-cond-statement: () -> (a: EXP, e: EXP) = { c = condition; a = (c); e = (a); semicolon; || semicolon; a = ; e = (a); }; for-end-statement: () -> (e: EXP) = { a = expression; b = (a); e = (b); || e = ; }; iteration-statement: () -> (e: EXP) = { while; x = ; r = ; open-round; c0 = condition; c = (c0); a = (c); close-round; bs = ; bc = (bs, c); b = scoped-statement (bc); (r); e = (a, b); (x); ; || do; x = ; r = ; a = ; bs = ; b = scoped-statement (bs); while; open-round; c0 = expression; c = (c0); (r); e = (a, b, c); close-round; (x); ; semicolon-x; || for; x = ; r = ; open-round; f = ; a = for-init-statement; g = (f, a); (c, cp) = for-cond-statement; ds = ; b = for-end-statement; h = (g, cp, b); close-round; da = (ds, a); dc = (da, c); (dc); d = scoped-statement (dc); (r); e = (h, d); (x); ; ; }; /* * JUMP STATEMENTS * * This rule describes the jump statements, consisting of the break, * continue, return and goto statements. */ : () -> (:EXP); : () -> (:EXP); : (:EXP) -> (:EXP); : (:IDENTIFIER) -> (:EXP); : (:EXP) -> (:EXP); : () -> (:EXP); jump-label: () -> (e: EXP) = { id = any-identifier; ; e = (id); || case; c = constant-expression; e = (c); || default; e = (); }; jump-statement: () -> (e: EXP) = { break; r = ; e = ; ; semicolon-x; || continue; r = ; e = ; ; semicolon-x; || return; r = ; { a = expression; || a = ; }; e = (a); ; semicolon-x; || goto; r = ; e = jump-label; ; semicolon-x; }; /* * TRY BLOCKS * * These rules describe the try blocks and exception handlers. A try * block consists of 'try' followed by a compound statement, giving the * exception body, and a list of exception handlers (the syntax has been * extended to allow empty lists). Each exception handler consists of * 'catch' followed by an exception declaration and a compound statement, * giving the handler body. */ : (:EXP, :DECL) -> (:EXP); : (:EXP, :EXP) -> (); : () -> (:EXP); : () -> (:EXP); : (:EXP) -> (); : (:EXP, :EXP) -> (:EXP); : (:EXP) -> (:EXP); exception-declaration: (:COUNT) -> (:DECL); handler: (a: EXP) -> () = { catch; c = ; (a); n = ; open-round; d = exception-declaration (n); b = (a, d); close-round; open-brace; (c); e0 = ; e1 = (e0); c1 = (c, e1); e2 = ; c2 = (c1, e2); c3 = statement-seq-opt (c2); close-brace; c4 = (c3); (b, c4); ; }; handler-seq-opt: (a: EXP) -> () = { handler (a); handler-seq-opt (a); || $; }; try-block: () -> (e: EXP) = { try; r = ; a = ; b = compound-statement; c = (a, b); handler-seq-opt (c); (r); e = (c); ; }; /* * FLOW CONTROL STATEMENTS (EXTENSION) * * This rule describes the extensions added to the statements to handle * flow control and variable analysis commands. */ : () -> (); : () -> (); : (:EXP) -> (:EXP); : (:EXP) -> (:EXP); control-statement: () -> (e: EXP) = { reachable; ; a = statement; e = (a); || unreachable; ; a = statement; e = (a); }; /* * TOKENISED STATEMENTS * * This rule describes the tokenised statements. This comprises the * statement names and the complex statements. */ qualified-stmt-name: () -> (id: IDENTIFIER) = { uid = statement-name; id = (uid); || ns = nested-name; uid = statement-name; (ns); id = (ns, uid); || ns = full-name; uid = statement-name; (ns); id = (ns, uid); || colon-colon; uid = statement-name; ns = ; id = (ns, uid); }; token-statement: () -> (e: EXP) = { id = qualified-stmt-name; a = (id); e = (a); || a = complex-stmt; e = (a); }; /* * STATEMENTS * * This rule describes the statements. These consist of the all the * types of statements listing above, including the try blocks. */ simple-statement: () -> (e: EXP) = { e = labelled-statement; || e = expression-statement; || e = selection-statement; || e = iteration-statement; || e = jump-statement; || e = declaration-statement; || e = try-block; || e = control-statement; || e = token-statement; }; statement: () -> (e: EXP) = { e = simple-statement; || e = compound-statement; }; statement-entry: () -> (e: EXP) = { e = statement; ## ; e = ; }; /* * CONST-VOLATILE QUALIFIERS * * These rules describe the lists of const and volatile type qualifiers. */ : () -> (:CV); : () -> (:CV); : () -> (:CV); : () -> (:CV); : (:CV, : CV) -> (:CV); cv-qualifier: () -> (cv: CV) = { const; cv = ; || restrict; cv = ; || volatile; cv = ; }; cv-qualifier-seq: () -> (cv: CV) = { a = cv-qualifier; { cv = a; || b = cv-qualifier-seq; cv = (a, b); }; }; cv-qualifier-seq-opt: () -> (cv: CV) = { cv = ; || cv = cv-qualifier-seq; }; /* * SIMPLE TYPE SPECIFIERS * * These rules describe the simple type specifiers. These comprise the * type names (class names, enumeration names and typedef names) plus the * basic type keywords. size_t and ptrdiff_t have been included for * future convenience only. Each simple type specifier gives a partial * type, which is only completed using type_complete when the entire type * specifier has been given. */ : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : () -> (:BTYPE); : (:BTYPE, :BTYPE) -> (:BTYPE); : () -> (:TYPE); : (:IDENTIFIER) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:BTYPE, :TYPE, :CV) -> (:TYPE); base-type-specifier: () -> (bt: BTYPE) = { char; bt = ; || short; bt = ; || int; bt = ; || long; bt = ; || signed; bt = ; || unsigned; bt = ; || float; bt = ; || double; bt = ; || bool; bt = ; || wchar-t; bt = ; || size-t; bt = ; || ptrdiff-t; bt = ; || void; bt = ; || bottom; bt = ; }; simple-type-specifier: () -> (bt: BTYPE, t: TYPE) = { bt = base-type-specifier; t = ; || id = unqualified-type; t = (id); bt = ; || id = any-qualified-type; t = (id); bt = ; || t = complex-type; bt = ; }; simple-type-id: () -> (t: TYPE) = { (bt, p) = simple-type-specifier; cv = ; t = (bt, p, cv); }; /* * ELABORATED TYPE SPECIFIERS * * This rule describes the elaborated type specifiers, such as 'struct tag'. * Again, type_elaborate only gives a partial type. */ : () -> (:KEY); : () -> (:KEY); : () -> (:KEY); : () -> (:KEY); : () -> (); : (:IDENTIFIER, :KEY) -> (:TYPE); : (:NAMESPACE, :IDENTIFIER) -> (:TYPE); class-key: () -> (key: KEY) = { class; key = ; || struct; key = ; || union; key = ; }; class-or-enum-key: () -> (key: KEY) = { key = class-key; || enum; key = ; }; any-class-name: () -> (id: IDENTIFIER) = { id = any-identifier; || id = template-type; }; elaborated-type-specifier: () -> (t: TYPE) = { key = class-or-enum-key; ; ns = any-nested-name-opt; aid = any-class-name; id = (ns, aid); t = (id, key); || typename; ; ns = any-nested-name-opt; id = any-class-name; t = (ns, id); }; /* * ACCESS SPECIFIERS * * This rule describes the class access specifiers, private, protected * and public. When defining a class the current access specifier is * held in a simple state variable which can be accessed via the actions * access_set and access_get. */ : () -> (:ACCESS); : () -> (:ACCESS); : () -> (:ACCESS); : () -> (:ACCESS); : (:ACCESS) -> (); : () -> (:ACCESS); access-specifier: () -> (a: ACCESS) = { private; a = ; || protected; a = ; || public; a = ; }; /* * TARGET DEPENDENT MEMBER DECLARATION SEQUENCES * * These rules describe the unresolved target dependent conditional * member declarations. See target-condition for details. */ : (:EXP) -> (); : (:EXP) -> (); : () -> (); : () -> (); member-specification-opt: (:TYPE, :DSPEC) -> (); member-cond-body: () -> () = { open-brace; ds = ; t = ; member-specification-opt (t, ds); close-brace; }; member-cond-head: () -> (p: EXP) = { c = hash-if; p = (c); (c); member-cond-body; || p = member-cond-head; c = hash-elif; (c); (c); member-cond-body; }; member-cond: () -> () = { p = member-cond-head; { hash-else; ; ; member-cond-body; || $; }; (p); hash-endif; ; }; /* * CLASS MEMBER SPECIFIERS * * These rules describe the class member specifiers. These consist * of a list of member declarations, which may also contain a number * of access specifiers. */ : (:TYPE, :DSPEC) -> (); member-declaration: (:TYPE, :DSPEC) -> (); member-elem: (t: TYPE, ds: DSPEC) -> () = { member-declaration (t, ds); || b = access-specifier; colon; (b); || (t, ds); member-cond; }; member-specification-opt: (t: TYPE, ds: DSPEC) -> () = { member-elem (t, ds); member-specification-opt (t, ds); || $; }; /* * BASE CLASS SPECIFIERS * * These rules describe the base class specifiers. These are either * empty or a colon followed by a list of class names, each of which * may be qualified by an access specification and by 'virtual'. */ : (:IDENTIFIER, :ACCESS, :BOOL) -> (); : (:BOOL) -> (); base-specifier: () -> () = { { a = access-specifier; v = ; || a = access-specifier; virtual; v = ; || virtual; v = ; a = ; || virtual; v = ; a = access-specifier; || a = ; v = ; }; ns = any-nested-name-opt; aid = any-class-name; id = (ns, aid); (id, a, v); }; base-specifier-list: () -> () = { base-specifier; { comma; base-specifier-list; || $; }; }; base-clause-opt: () -> (t: BOOL) = { colon; base-specifier-list; t = ; || colon; t = ; || t = ; }; /* * CLASS SPECIFIERS * * These rules describe the class (which includes structure and union) * type specifiers. These consist of a class key followed by an optional * class name, a list of base classes, and the class definition body. * This body consists of a list of member declarations enclosed within * braces. Note that the default access specifier for the class is * completely determined by the class key, it is 'private' for 'class' * and 'public' for 'struct' and 'union'. */ : () -> (:BOOL); : () -> (); : () -> (); : (:TYPE) -> (); : (:IDENTIFIER, :KEY, :TYPE) -> (:IDENTIFIER, :BOOL); : (:IDENTIFIER, :BOOL) -> (:IDENTIFIER); class-specifier: (q: TYPE) -> (c: IDENTIFIER) = { key = class-key; ? = ; ; { ns = any-nested-name-opt; aid = any-class-name; id = (ns, aid); || id = ; }; (qu, i) = ; (q); b = ; (p, f) = (id, key, q); s = base-clause-opt; (s); ds = ; t = ; open-brace; member-specification-opt (t, ds); close-brace; ; c = (p, f); (b); (qu, i); ; }; /* * ENUMERATION TYPE SPECIFIERS * * These rules describe the enumeration type specifiers. These consist * of 'enum' followed by an optional identifier and an enumeration * definition body. This body consists of a list of enumerator definitions * enclosed within braces. */ : () -> (); : () -> (:BOOL); : (:IDENTIFIER, :TYPE) -> (:IDENTIFIER); : (:IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER, :IDENTIFIER, :EXP) -> (); : (:IDENTIFIER) -> (); enumerator-definition: (e: IDENTIFIER) -> () = { eid = any-identifier; id = (eid); (id); { assign; c = constant-expression; || c = ; }; (e, id, c); }; enumerator-list: (e: IDENTIFIER) -> () = { enumerator-definition (e); { comma; enumerator-list (e); || comma; comma; ; enumerator-list (e); || comma; ; || $; }; }; enum-specifier: (q: TYPE) -> (e: IDENTIFIER) = { enum; ? = ; ; { ns = any-nested-name-opt; aid = any-class-name; id = (ns, aid); || id = ; }; (qu, i) = ; p = (id, q); open-brace; { enumerator-list (p); || $; }; close-brace; ; e = (p); (qu, i); }; /* * TYPE SPECIFIERS * * These rules describes the type specifiers. These consist of the simple * type specifiers, the class definitions, the enumeration definitions, * the elaborated type specifiers and the const and volatile qualifiers. * Sequences of these specifiers may be combined into a single partial * type using type_join. The partial type is not turned into a real * type until type_complete is applied to it. Note that the rule * check-type-specifier-seq is identical to type-specifier-seq except * that it always calls the predicate is_type_specifier to check what * is coming next. */ : () -> (:BOOL); type-specifier: (s: TYPE) -> (bt: BTYPE, t: TYPE, cv: CV) = { (bt, t) = simple-type-specifier; cv = ; || c = class-specifier (s); t = (c); bt = ; cv = ; || e = enum-specifier (s); t = (e); bt = ; cv = ; || t = elaborated-type-specifier; bt = ; cv = ; || cv = cv-qualifier; bt = ; t = ; }; type-specifier-seq: () -> (bt: BTYPE, t: TYPE, cv: CV) = { s = ; (b1, t1, cv1) = type-specifier (s); { (b2, t2, cv2) = type-specifier-seq; bt = (b1, b2); t = (t1, t2); cv = (cv1, cv2); || bt = b1; t = t1; cv = cv1; }; }; check-type-specifier-seq: () -> (bt: BTYPE, t: TYPE, cv: CV) = { ? = ; s = ; (b1, t1, cv1) = type-specifier (s); { (b2, t2, cv2) = check-type-specifier-seq; bt = (b1, b2); t = (t1, t2); cv = (cv1, cv2); || bt = b1; t = t1; cv = cv1; }; }; /* * STORAGE CLASS SPECIFIERS * * This rule describes the storage class specifiers, including 'mutable' * as well as the more obvious 'static', 'extern' and so on. */ : () -> (:DSPEC); : () -> (:DSPEC); : () -> (:DSPEC); : () -> (:DSPEC); : () -> (:DSPEC); storage-class-specifier: () -> (ds: DSPEC) = { auto; ds = ; || extern; ds = ; || static; ds = ; || mutable; ds = ; || register; ds = ; }; /* * FUNCTION SPECIFIERS * * This rule describes the function specifiers, 'inline', 'virtual' and * 'explicit'. */ : () -> (:DSPEC); : () -> (:DSPEC); : () -> (:DSPEC); : () -> (:DSPEC); function-specifier: () -> (ds: DSPEC) = { inline; ds = ; || virtual; ds = ; || explicit; ds = ; || overload; ds = ; }; /* * DECLARATION SPECIFIERS * * These rules describes the declaration specifiers. These consist of * the type specifiers, the storage class and function specifiers, plus * 'friend' and 'typedef'. Like type specifiers, declaration specifiers * can be formed into lists which are only turned into complete types * and declaration specifiers later. Again check-decl-specifier-seq is * identical to decl-specifier-seq except that it always calls the * predicate is_decl_specifier to check what is coming next. */ : () -> (:DSPEC); : () -> (:DSPEC); : (:DSPEC, :DSPEC) -> (:DSPEC); : (:DSPEC) -> (); : () -> (:BOOL); : () -> (); decl-specifier: (s: TYPE) -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { { ds = storage-class-specifier; || ds = function-specifier; || friend; ds = ; || typedef; ds = ; }; (ds); bt = ; t = ; cv = ; || (bt, t, cv) = type-specifier (s); ds = ; }; decl-specifier-seq: (s: TYPE) -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { (b1, t1, cv1, ds1) = decl-specifier (s); ; { (b2, t2, cv2, ds2) = decl-specifier-seq (s); bt = (b1, b2); t = (t1, t2); cv = (cv1, cv2); ds = (ds1, ds2); || bt = b1; t = t1; cv = cv1; ds = ds1; }; }; check-decl-specifier-seq: (s: TYPE) -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { ? = ; (b1, t1, cv1, ds1) = decl-specifier (s); { (b2, t2, cv2, ds2) = check-decl-specifier-seq (s); bt = (b1, b2); t = (t1, t2); cv = (cv1, cv2); ds = (ds1, ds2); || bt = b1; t = t1; cv = cv1; ds = ds1; }; }; check-decl-specifier-seq-opt: (s: TYPE) -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { (bt, t, cv, ds) = check-decl-specifier-seq (s); || bt = ; t = ; cv = ; ds = ; }; /* * POINTER OPERATORS * * These rules describe the pointer, reference and pointer to member * operators. They build up a partial type, containing the pointer * information, but not what is pointed to. This is only filled in later * by type_inject. The const and volatile qualified references have been * included in the grammar, but are weeded out by type_ref. */ : (:CV) -> (:TYPE); : (:CV) -> (:TYPE); : (:IDENTIFIER, :CV) -> (:TYPE); ptr-operator: () -> (p: TYPE) = { star; cv = cv-qualifier-seq-opt; p = (cv); || and; cv = cv-qualifier-seq-opt; p = (cv); || id = nested-name-star; cv = cv-qualifier-seq-opt; p = (id, cv); || id = full-name-star; cv = cv-qualifier-seq-opt; p = (id, cv); }; /* * DECLARATORS * * These rules describe the declarators. The rule declarator-aux * builds up a partial type, containing pointer, array, and other * type information, but not the base type of what is pointed to etc. * This base type is provided by the rule declarator and filled in * using type_inject. Note also that the function style initialisers * have been included in this rule. They are distinguished from the * parameter declaration clauses by the predicate is_initialiser. This * can lead to initialisers appearing in the wrong places, but they are * easily weeded out using initialiser_bad. */ : (:EXP) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:BOOL, :BOOL, :CV, :LIST-TYPE) -> (:TYPE); : (:IDENTIFIER) -> (); : (:DECL) -> (); : (:IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER) -> (); : () -> (); : () -> (:BOOL); : (:BOOL) -> (); : (:TYPE) -> (); exception-specification-opt: () -> (:LIST-TYPE); declarator-aux: () -> (:TYPE, :IDENTIFIER, :BOOL); parameter-declaration-clause: () -> (:BOOL); declarator-id: () -> (id: IDENTIFIER) = { id = id-expression; || tid = unqualified-type; id = (tid); || tid = any-qualified-type; id = (tid); || id = qualified-stmt-name; }; parameter-tail: (w: BOOL) -> (t: TYPE) = { ell = parameter-declaration-clause; close-round; cv = cv-qualifier-seq-opt; ex = exception-specification-opt; t = (ell, w, cv, ex); }; declarator-tail: (id: IDENTIFIER) -> (t: TYPE, c: BOOL) = { open-round; { w = ; (id); t = parameter-tail (w); ; c = ; || ? = ; c = ; t = ; }; || open-square; { e = constant-expression; || e = ; }; t = (e); close-square; c = ; || weak; open-round; w = ; (id); t = parameter-tail (w); ; c = ; }; direct-declarator: () -> (t: TYPE, id: IDENTIFIER, c: BOOL) = { id = declarator-id; t = ; c = ; (id); || (p, id, b) = direct-declarator; (i, a) = ; (q, c) = declarator-tail (id); (b); t = (p, q); (i, a); || open-round; (t, id, c) = declarator-aux; (c); (t); close-round; }; declarator-aux: () -> (t: TYPE, id: IDENTIFIER, c: BOOL) = { (t, id, c) = direct-declarator; || p = ptr-operator; (q, id, c) = declarator-aux; t = (q, p); }; declarator: (p: TYPE) -> (t: TYPE, id: IDENTIFIER, c: BOOL) = { (q, id, c) = declarator-aux; (p); t = (q, p); }; /* * ABSTRACT DECLARATORS * * These rules describe the abstract declarators. These are identical * to the declarators except that they do not have a declarator-id. * Also initialisers cannot appear in abstract declarators. */ abstract-declarator-aux: () -> (:TYPE); abstract-declarator-tail: () -> (t: TYPE) = { open-round; id = ; w = ; (id); t = parameter-tail (w); ; || open-square; { e = constant-expression; || e = ; }; t = (e); close-square; || weak; open-round; id = ; w = ; (id); t = parameter-tail (w); ; }; direct-abstract-declarator: () -> (t: TYPE) = { t = abstract-declarator-tail; || p = direct-abstract-declarator; q = abstract-declarator-tail; t = (p, q); || open-round; t = abstract-declarator-aux; (t); close-round; }; abstract-declarator-aux: () -> (t: TYPE) = { t = direct-abstract-declarator; || t = ptr-operator; || p = ptr-operator; q = abstract-declarator-aux; t = (q, p); }; abstract-declarator-opt: (p: TYPE) -> (t: TYPE) = { q = abstract-declarator-aux; t = (q, p); || t = p; }; /* * PARAMETER DECLARATOR * * A parameter declarator can be a declarator, an abstract-declarator or * be empty. The easiest way to do this is as a separate set of rules. * A predicate is necessary to distinguish declarator-ids from type names. * Again it is not necessary to include initialisers. */ : () -> (:BOOL); parameter-declarator-aux: () -> (:TYPE, :IDENTIFIER); parameter-declarator-aux-opt: () -> (:TYPE, :IDENTIFIER); direct-parameter-declarator: () -> (t: TYPE, id: IDENTIFIER) = { ? = ; id = declarator-id; t = ; (id); || (p, id) = direct-parameter-declarator; (i, b) = ; q = abstract-declarator-tail; (i, b); t = (p, q); || t = abstract-declarator-tail; id = ; (id); || open-round; (t, id) = parameter-declarator-aux; (t); close-round; }; parameter-declarator-aux: () -> (t: TYPE, id: IDENTIFIER) = { (t, id) = direct-parameter-declarator; || p = ptr-operator; (q, id) = parameter-declarator-aux-opt; t = (q, p); }; parameter-declarator-aux-opt: () -> (t: TYPE, id: IDENTIFIER) = { (t, id) = parameter-declarator-aux; || t = ; id = ; (id); }; parameter-declarator-opt: (p: TYPE) -> (t: TYPE, id: IDENTIFIER) = { (q, id) = parameter-declarator-aux-opt; t = (q, p); }; /* * FUNCTION PARAMETER DECLARATIONS * * These rules describe the function parameter declarations. The rules * differ slightly from those given in the standard, which was clearly * not written with LL(1) parsers in mind, but are equivalent. */ : (:BTYPE, :TYPE, :CV, :DSPEC) -> (:TYPE, :DSPEC); : (:DSPEC, :TYPE, :IDENTIFIER, :NUMBER) -> (:DECL); : (:DECL, :EXP) -> (); : () -> (:NUMBER); : () -> (:DECL); : (:DECL) -> (:EXP); : () -> (); : () -> (); : (:NUMBER) -> (:BOOL); parameter-declaration: (s: TYPE, p: NUMBER) -> (d: DECL) = { (bt, t1, cv1, ds1) = decl-specifier-seq (s); (t2, ds2) = (bt, t1, cv1, ds1); ; (t, id) = parameter-declarator-opt (t2); d = (ds2, t, id, p); { assign; ; { ? = (p); a = (d); || a = initialiser-expression; }; ; e = a; || e = ; }; (d, e); }; parameter-declaration-list: () -> (ell: BOOL) = { ellipsis; ell = ; || s = ; p = ; d = parameter-declaration (s, p); { comma; ell = parameter-declaration-list; || ellipsis; ell = ; || ell = ; }; }; parameter-declaration-clause: () -> (ell: BOOL) = { ell = parameter-declaration-list; || ell = ; }; parameter-entry: (s: TYPE, p: NUMBER) -> (d: DECL) = { d = parameter-declaration (s, p); ## ; d = ; }; /* * TYPE IDENTIFIERS * * This rule describes the type identifiers. There is a predicate to * distinguish type identifiers from expressions in, for example, sizeof * expressions. A count of the number of types defined in the type * identifier is maintained. */ : () -> (:BOOL); : () -> (:BOOL); : (:TYPE, :BTYPE, :EXP) -> (:TYPE); : (:TYPE) -> (); type-id: () -> (t: TYPE, n: COUNT) = { n1 = ; (bt, p, cv) = type-specifier-seq; q = (bt, p, cv); t = abstract-declarator-opt (q); n = (n1); (t); }; type-id-false: () -> (t: TYPE, n: COUNT) = { ? = ; (t, n) = type-id; }; type-id-true: () -> (t: TYPE, n: COUNT) = { ? = ; (t, n) = type-id; }; token-type-id: () -> (t: TYPE) = { (bt, p, cv) = type-specifier-seq; q = (bt, p, cv); t = abstract-declarator-opt (q); }; member-type-id: () -> (t: TYPE) = { (bt, p, cv) = type-specifier-seq; q = (bt, p, cv); { t = abstract-declarator-opt (q); || rem; (i, b) = ; c = constant-expression; t = (q, bt, c); (i, b); }; }; type-id-entry: () -> (t: TYPE) = { t = token-type-id; (t); ## ; t = ; }; /* * CONVERSION TYPE IDENTIFIERS * * These rules describe those type identifiers which can be used in * conversion function identifiers. The predicate is_ptr_operator is * required to resolve 'operator int * (3)' as a function call rather * than a multiplication expression. */ : () -> (:BOOL); conversion-declarator-opt: () -> (t: TYPE) = { ? = ; p = ptr-operator; q = conversion-declarator-opt; t = (q, p); || t = ; }; conversion-type-id: () -> (t: TYPE) = { (bt, p, cv) = check-type-specifier-seq; s = (bt, p, cv); q = conversion-declarator-opt (); t = (q, s); }; /* * NEW TYPE IDENTIFIERS * * These rules describe those type identifiers which can be used in * new expressions. Again it necessary to resolve 'new int * (3)' * correctly by means of a predicate. Note that in array new-declarators * the first array bound is not necessarily a constant-expression, so * that, for example, it is possible to form 'new int [n]' for any integral * expression, n. */ : (:EXP) -> (:TYPE); : () -> (:BOOL); direct-new-declarator: () -> (t: TYPE) = { open-square; a = expression; e = (a); t = (e); close-square; || p = direct-new-declarator; open-square; e = constant-expression; q = (e); t = (p, q); close-square; }; new-declarator-opt: () -> (t: TYPE) = { ? = ; p = ptr-operator; q = new-declarator-opt; t = (q, p); || t = direct-new-declarator; || t = ; }; new-type-id: () -> (t: TYPE, n: COUNT) = { n1 = ; (bt, p, cv) = type-specifier-seq; s = (bt, p, cv); q = new-declarator-opt (); t = (q, s); n = (n1); }; /* * INITIALISERS * * These rules describe the initialisers. This includes the assignment * style and aggregate initialisers, but excludes the function style * initialisers. The latter are included as part of the associated * declarator and passed in to initialiser-opt as c (which is the null * expression if no such initialiser was given). */ : (:LIST-EXP) -> (:EXP); : (:LIST-EXP) -> (:EXP); : (:DECL) -> (); : (:DECL, :ACCESSES) -> (); : (:BOOL) -> (:BOOL); : () -> (); initialiser-clause: (:DECL) -> (:EXP); initialiser-list: (d: DECL) -> (p: LIST-EXP) = { b = initialiser-clause (d); a = (b); { comma; q = initialiser-list (d); || comma; q = ; || q = ; }; p = (a, q); }; initialiser-clause: (d: DECL) -> (e: EXP) = { e = initialiser-expression; (d); || open-brace; { p = initialiser-list (d); || p = ; }; close-brace; e = (p); }; initialiser-exp-list: (d: DECL) -> (p: LIST-EXP) = { e = initialiser-expression; (d); { comma; q = initialiser-exp-list (d); || q = ; }; p = (e, q); }; initialiser-opt: (c: BOOL, d: DECL) -> (e: EXP) = { ? = (c); ; p = initialiser-exp-list (d); e = (p); close-round; || assign; e = initialiser-clause (d); || e = ; }; initialiser-entry: (d: DECL) -> (e: EXP) = { e = initialiser-clause (d); ## ; e = ; }; /* * INITIALISATION DECLARATORS * * These rules describe the declarators with initialisers. In fact the * first element in any init-declarator-list is handled separately in the * rule declaration. See above for the handling of function style * initialisers. */ : (:DSPEC, :BTYPE, :TYPE, :IDENTIFIER) -> (:DECL); : (:DECL, :EXP) -> (); init-declarator: (ds: DSPEC, bt: BTYPE, p: TYPE, r: ACCESSES) -> () = { (t, id, c) = declarator (p); d = (ds, bt, t, id); (d, r); (d); e = initialiser-opt (c, d); (d, e); (d); (d); }; init-declarator-list: (ds: DSPEC, bt: BTYPE, t: TYPE, r: ACCESSES) -> () = { init-declarator (ds, bt, t, r); { comma; ; init-declarator-list (ds, bt, t, r); || $; }; }; /* * CONSTRUCTOR CLASS INITIALISERS * * These rules describe the class initialisers which may be associated * with a constructor definition. These consist of a colon followed by a * list of class names and expressions associated with these classes. */ : () -> (:NAMESPACE); : (:NAMESPACE, :EXP, :BOOL) -> (:EXP); : (:EXP) -> (:EXP, :EXP); : (:NAMESPACE, :IDENTIFIER, :EXP) -> (); : (:EXP, :EXP) -> (:EXP); mem-initialiser: (cns: NAMESPACE) -> () = { ns = any-nested-name-opt; aid = any-class-name; id = (ns, aid); (i, b) = ; open-round; p = expression-list-opt; close-round; (i, b); e = (p); (cns, id, e); || open-round; p = expression-list-opt; close-round; e = (p); id = ; (cns, id, e); }; mem-initialiser-list: (cns: NAMESPACE) -> () = { mem-initialiser (cns); { comma; mem-initialiser-list (cns); || $; }; }; ctor-initialiser-opt: (c: EXP) -> (e: EXP, d: EXP) = { colon; cns = ; { mem-initialiser-list (cns); b = ; || b = ; }; e = (cns, c, b); d = ; || (e, d) = (c); }; /* * FUNCTION DEFINITIONS * * These rules describe the function definitions. The actual declarator * for function-definition has been built into declaration. The rest of * the definition consists of an optional list of constructor class * initialisers, which are only actually valid if the function is a * constructor, plus a compound statement, giving the definition body. */ : () -> (:EXP); function-body: (c: EXP) -> (e: EXP) = { (b, d) = ctor-initialiser-opt (c); open-brace; (b); a = statement-seq-opt (b); e = (a, d); close-brace; }; function-try-block: () -> (e: EXP) = { try; r = ; a = ; b = ; (a); f = function-body (b); c = (f); d = (a, c); handler-seq-opt (d); (r); e = (d); }; function-definition-body: () -> (e: EXP) = { c = ; { a = function-body (c); || b = function-try-block; a = (c, b); }; e = (a); ; }; function-definition-entry: () -> (e: EXP) = { e = function-definition-body; ## ; e = ; }; /* * TARGET DEPENDENT DECLARATION SEQUENCES * * These rules describe the unresolved target dependent conditional * declarations. See target-condition for details. The '#pragma' * directives are included in this rule for convenience. */ declaration-seq-opt: (:TYPE, :DSPEC) -> (); declaration-cond-body: () -> () = { open-brace; ds = ; t = ; declaration-seq-opt (t, ds); close-brace; }; declaration-cond-head: () -> (p: EXP) = { c = hash-if; p = (c); (c); declaration-cond-body; || p = declaration-cond-head; c = hash-elif; (c); (c); declaration-cond-body; }; declaration-cond: () -> () = { p = declaration-cond-head; { hash-else; ; ; declaration-cond-body; || $; }; (p); hash-endif; ; || hash-pragma; }; /* * SEQUENCES OF DECLARATIONS * * These rules describe the declaration sequences, consisting of a simple * list of declarations. */ : (:EXP) -> (); declaration: (:TYPE, :DSPEC) -> (:EXP); declaration-elem: (t: TYPE, ds: DSPEC) -> () = { e = declaration (t, ds); (e); || (t, ds); declaration-cond; ; }; declaration-seq-opt: (t: TYPE, ds: DSPEC) -> () = { declaration-elem (t, ds); declaration-seq-opt (t, ds); || $; }; /* * NAMESPACE DEFINITIONS * * These rules describe the namespace definitions, consisting of 'namespace' * followed by an optional identifier and a list of declarations enclosed * within braces. */ : (:IDENTIFIER) -> (); : () -> (); : () -> (); : () -> (); named-namespace-definition: () -> () = { namespace; nid = any-identifier; id = (nid); (id); (id); ds = ; t = ; open-brace; declaration-seq-opt (t, ds); ; close-brace; }; unnamed-namespace-definition: () -> () = { namespace; ; ds = ; t = ; open-brace; declaration-seq-opt (t, ds); ; close-brace; }; namespace-definition: () -> () = { { named-namespace-definition; || unnamed-namespace-definition; }; ; }; /* * NAMESPACE ALIAS DEFINITIONS * * These rules describe the namespace alias definitions, consisting of * an identification of a new name with an existing namespace. */ : (:IDENTIFIER) -> (:NAMESPACE); : (:IDENTIFIER, :NAMESPACE) -> (); namespace-alias-definition: () -> () = { namespace; nid = any-identifier; id = (nid); (id); assign; pns = any-nested-name-opt; pid = any-class-name; mid = (pns, pid); ns = (mid); ; (id, ns); semicolon-x; }; /* * USING DECLARATIONS * * This rule describes the using declarations, which may be used to bring * an identifier declared in a namespace into scope. */ : (:IDENTIFIER) -> (); : (:TYPE) -> (); using-declaration: () -> () = { using; id = declarator-id; (id); semicolon-x; || using; typename; ; ns = any-nested-name-opt; id = any-class-name; t = (ns, id); (t); semicolon-x; }; /* * USING DIRECTIVES * * This rule describes the using directives, which may be used to bring all * the identifiers declared in a namespace into scope. */ : (:NAMESPACE) -> (); using-directive: () -> () = { using; namespace; pns = any-nested-name-opt; pid = any-class-name; id = (pns, pid); ns = (id); (ns); semicolon-x; }; /* * ASM DEFINITIONS * * This rule describes the asm definitions. These consist of 'asm' followed * by a bracketed string literal and a semicolon. */ : (:EXP, :LIST-EXP) -> (:EXP); asm-definition: () -> (e: EXP) = { asm; open-round; a = string-literal; { comma; p = expression-list; || p = ; }; e = (a, p); close-round; semicolon-x; }; /* * LINKAGE SPECIFICATIONS * * This rule describes the linkage specifications. This is implemented * by a single linkage state variable. The main action is linkage_string, * which translates a string literal into a linkage specifier. The * 'extern' in a linkage specification is distinguished from that in a * declaration specifier by the predicate is_decl_specifier. */ : (:LINKAGE) -> (:LINKAGE); : (:LINKAGE) -> (); : (:EXP) -> (:LINKAGE); : () -> (:DSPEC); linkage-specification: (t: TYPE, ds: DSPEC) -> (e: EXP) = { extern; c = string-literal; a = (c); b = (a); ds0 = ; ds1 = (ds, ds0); { e1 = declaration (t, ds1); (b); || open-brace; (t, ds1); t2 = ; ds2 = ; declaration-seq-opt (t2, ds2); (b); close-brace; e1 = ; }; e = e1; }; /* * DECLARATIONS * * This rule describes the declarations. Note that the empty declaration, * consisting of just a semicolon has been made a separate case (see * expression-statement). The first declarator in a simple declaration * has been factored out of the init-declarator-list and combined with * the function-definition rule. Linkage specifications, namespace and * using declarations and asm-definitions are also classified as * declarations. */ : () -> (:BOOL); : (:DECL) -> (:BOOL); : (:DECL, :EXP, :BOOL) -> (); : (:DSPEC, :TYPE, :BTYPE, :TYPE, :CV) -> (); : () -> (:ACCESSES); : (:ACCESSES) -> (); template-declaration: (:TYPE, :DSPEC) -> (:EXP); declaration-basic: (t: TYPE, ds: DSPEC) -> () = { (bt, t1, cv1, ds1) = check-decl-specifier-seq-opt (t); ds2 = (ds, ds1); (t2, ds3) = (bt, t1, cv1, ds2); t3 = (t, t2); r = ; ; (s, id, c) = declarator (t3); d = (ds3, bt, s, id); (d, r); (d); { e = initialiser-opt (c, d); (d, e); (d); (d); { comma; ; init-declarator-list (ds3, bt, t3, r); || $; }; (r); semicolon; || ? = ; (c); (r); b = (d); e = function-definition-body; (d, e, b); (d); ; }; || (bt, t1, cv1, ds1) = check-decl-specifier-seq (t); ds2 = (ds, ds1); (ds2, t, bt, t1, cv1); ; semicolon; }; declaration-other: () -> (e: EXP) = { e = asm-definition; || namespace-definition; e = ; || namespace-alias-definition; e = ; || using-declaration; e = ; || using-directive; e = ; }; declaration-nonempty: (t: TYPE, ds: DSPEC) -> (e: EXP) = { declaration-basic (t, ds); e = ; || e = template-declaration (t, ds); || e = linkage-specification (t, ds); || (t, ds); e = declaration-other; }; declaration: (t: TYPE, ds: DSPEC) -> (e: EXP) = { e = declaration-nonempty (t, ds); || bt = ; t1 = ; cv = ; (ds, t, bt, t1, cv); semicolon; e = ; }; declaration-entry: (t: TYPE, ds: DSPEC) -> () = { declaration-basic (t, ds); ## ; }; /* * CLASS MEMBER DECLARATORS * * These rules describe the class member declarators. Note that the * rule member-specifier-opt is intended to handle both pure-specifier * and constant-initialiser. Also two types are passed into these * rules, one reflecting the declaration type and the other the sequence * of type-specifiers used to describe this type. This is because * in bitfields 'signed int' is not synonymous with 'int'. */ : (:DSPEC, :BTYPE, :TYPE, :IDENTIFIER, :BOOL) -> (:DECL, :BOOL); : (:DSPEC, :TYPE, :IDENTIFIER) -> (:DECL); : (:TYPE, :BTYPE, :EXP, :IDENTIFIER) -> (:TYPE); : (:DECL, :EXP, :BOOL) -> (); member-specifier-opt: () -> (e: EXP) = { assign; e = constant-expression; || e = ; }; member-declarator: (ds: DSPEC, p: TYPE, q: BTYPE, r: ACCESSES, f: BOOL) -> (d: DECL) = { (t, id, c) = declarator (p); (c); (d, fr) = (ds, q, t, id, f); (d, r); (d); e = member-specifier-opt (); (d, e, fr); (d); || { mid = any-identifier; id = (mid); || id = ; }; (p); (id); (i, b) = ; colon; c = constant-expression; (i, b); t = (p, q, c, id); d = (ds, t, id); (d, r); (d); }; member-declarator-list: (ds: DSPEC, p: TYPE, q: BTYPE, r: ACCESSES, f: BOOL) -> () = { d = member-declarator (ds, p, q, r, f); (d); { comma; n = ; ; member-declarator-list (ds, p, q, r, n); || $; }; }; /* * CLASS MEMBER DECLARATION * * This rule describes the class member declarations. As with the normal * declaration rule, the first member-declarator has been factored out and * combined with the function-definition rule. There is a slight problem * in that member-declarators allow an initialiser, whereas they are not * allowed in a function-definition. However the look-ahead for is_function * actually occurs in declare_member, so a function definition with an * initialiser will be resolved as an initialised function declaration * (which may actually be a legal pure function declaration). Note also * that the qualified-ids used to change the access of a member are a * special case of the first option. */ template-member-decl: (:TYPE, :DSPEC) -> (); : (:DECL) -> (); : (:DSPEC, :TYPE, :BTYPE, :TYPE, :CV) -> (); member-declaration: (t: TYPE, ds: DSPEC) -> () = { (bt, t1, cv1, ds1) = check-decl-specifier-seq-opt (t); ds2 = (ds, ds1); (t2, ds3) = (bt, t1, cv1, ds2); t3 = (t, t2); r = ; f = ; ; d = member-declarator (ds3, t3, bt, r, f); { semicolon; (r); (d); || comma; (d); n = ; ; member-declarator-list (ds3, t3, bt, r, n); (r); semicolon; || ? = ; (r); (d); (d); ; }; || (bt, t1, cv1, ds1) = check-decl-specifier-seq (t); ds2 = (ds, ds1); (ds2, t, bt, t1, cv1); ; semicolon; || t1 = ; bt = ; cv1 = ; (ds, t, bt, t1, cv1); semicolon; || template-member-decl (t, ds); || (t, ds); using-declaration; }; /* * CONDITION DECLARATIONS * * A condition can be a simple declaration. These rules describes those * declarations which are allowed in this situation. */ : () -> (); : () -> (:EXP); : (:TYPE) -> (:TYPE); condition-declarator: () -> (d: DECL) = { (bt, t1, cv1) = check-type-specifier-seq; ds1 = ; (t2, ds) = (bt, t1, cv1, ds1); ; (t3, id, c) = declarator (t2); (c); t = (t3); d = (ds, bt, t, id); (d); }; condition-declaration: () -> (e: EXP) = { ? = ; ; d = condition-declarator; assign; a = initialiser-expression; (d); (d, a); (d); (d); e = ; }; /* * EXCEPTION DECLARATIONS * * This rule describes the exception declarations. Both declarators and * abstract declarators are allowed in these declarations, as with function * parameters. Therefore the same rule is used. */ : (:DSPEC, :TYPE, :IDENTIFIER, :COUNT) -> (:DECL); : () -> (:DECL); exception-declaration: (n1 : COUNT) -> (d: DECL) = { (bt, t1, cv1) = check-type-specifier-seq; ds1 = ; (t2, ds2) = (bt, t1, cv1, ds1); ; (t, id) = parameter-declarator-opt (t2); n2 = (n1); d = (ds2, t, id, n2); || ellipsis-aux; d = ; }; /* * EXCEPTION SPECIFICATIONS * * These rules describe the exception specifications. These consist of * 'throw' followed by a bracketed list of type identifiers. */ : (:TYPE, :COUNT) -> (:TYPE); : () -> (:LIST-TYPE); : (:TYPE, :LIST-TYPE) -> (:LIST-TYPE); : () -> (:LIST-TYPE); : () -> (:LIST-TYPE); type-id-list: () -> (p: LIST-TYPE) = { (s, n) = type-id; t = (s, n); { comma; q = type-id-list; || comma; ; q = ; || q = ; }; p = (t, q); }; exception-specification-opt: () -> (p: LIST-TYPE) = { throw; open-round; { p = type-id-list; || ellipsis; p = ; || p = ; }; close-round; || p = ; }; /* * TEMPLATE DECLARATIONS * * These rules describe the template declarations, including template * specialisations and explicit instantiations. The rule template- * parameter-list is sufficiently awkward to require hand crafting via * the action template_params. */ : (:BOOL) -> (:TEMPLATE); : (:TEMPLATE, :TYPE) -> (:TYPE); : (:TEMPLATE) -> (); export-opt: () -> (x: BOOL) = { export; x = ; || x = ; }; template-declaration: (t: TYPE, ds: DSPEC) -> (e: EXP) = { x = export-opt; template; p = (x); t1 = (p, t); e = declaration (t1, ds); (p); ; }; template-member-decl: (t: TYPE, ds: DSPEC) -> () = { x = export-opt; template; p = (x); t1 = (p, t); member-declaration (t1, ds); (p); ; }; /* * TEMPLATE TYPE PARAMETERS * * These rules describes the template type parameters. */ : (:IDENTIFIER) -> (:DECL); : (:DECL, :TYPE) -> (); : (:TYPE, :IDENTIFIER, :DSPEC) -> (:DECL); : (:DECL, :IDENTIFIER) -> (); template-param-name: () -> (id: IDENTIFIER) = { tid = any-identifier; id = (tid); || id = ; }; template-type-param: () -> (d: DECL) = { { class; || typename; }; id = template-param-name; d = (id); { assign; ; t = token-type-id; ; (t); || t = ; }; (d, t); || template; e = ; p = (e); t = ; ds = ; t1 = (p, t); class; id = template-param-name; d = (t1, id, ds); { assign; ; aid = any-qualified-id; tid = (aid); ; || tid = ; }; (d, tid); (p); ; ## ; d = ; }; /* * TRANSLATION UNITS * * This is the main entry point for the grammar. A translation unit * consists of a (possibly empty) sequence of declarations, followed * by the end of the file. */ translation-unit: (t: TYPE, ds: DSPEC) -> () = { declaration-seq-opt (t, ds); eof; ## ; }; /* * CONDITIONAL COMPILATION CONSTANTS * * This rule is the alternative entry point for the conditions following * #if and #elif preprocessing directives. It consists of a constant * expression. The end of line marker which follows this expression is * handled by the calling routine. */ hash-if-expression: () -> (e: EXP) = { e = constant-expression; ## ; e = ; }; /* * CONSTANT MEMBER DESIGNATORS * * These rules describe the constant member offsets. The entry point * constant-offset is used for reading member token definitions. */ : (:TYPE) -> (:NAMESPACE); : (:OFFSET, :TYPE, :EXP) -> (:OFFSET, :TYPE); : (:OFFSET, :TYPE, :IDENTIFIER, :NAMESPACE) -> (:OFFSET, :TYPE); member-designator: (b: OFFSET, s: TYPE) -> (a: OFFSET, t: TYPE) = { ns = (s); ; id = field-id-expression (ns); (a, t) = (b, s, id, ns); ; }; designator: (b: OFFSET, s: TYPE) -> (a: OFFSET, t: TYPE) = { dot; (a, t) = member-designator (b, s); || open-square; e = constant-expression; (a, t) = (b, s, e); close-square; }; designator-list: (b: OFFSET, s: TYPE) -> (a: OFFSET, t: TYPE) = { (a, t) = designator (b, s); || (c, u) = designator-list (b, s); (a, t) = designator (c, u); }; constant-offset: (b: OFFSET, s: TYPE) -> (a: OFFSET, t: TYPE) = { (c, u) = member-designator (b, s); { a = c; t = u; || (a, t) = designator-list (c, u); }; ## ; a = b; t = s; }; /* * ENTRY POINTS * * There are a large number of entry points for the grammar, the main * one being translation-unit, with others for expressions, types etc. */ %entry% translation-unit, expression-entry, function-definition-entry, declaration-entry, id-entry, operator-id, type-id-entry, token-type-id, member-type-id, parameter-entry, statement-entry, initialiser-entry, hash-if-expression, template-type-param, constant-offset;