/* * 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/c/syntax/syntax.sid,v 1.16 2005/10/16 07:47:45 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% BOOL; BTYPE; CONDITION; COUNT; CV; DECL; DSPEC; EXP; IDENTIFIER; KEY; LEX; LIST-EXP; NAMESPACE; NUMBER; OFFSET; TYPE; /* * LIST OF TERMINALS * * This list of terminals corresponds to that given in symbols.h. It can * be automatically generated using the routine sid_terminals defined in * debug.c (q.v). */ %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; }; /* * LEXICAL TOKENS * * These actions give the lexical token numbers for various symbols. */ : () -> (: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) -> (); : () -> (); : () -> (); 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. */ : () -> (:IDENTIFIER); : () -> (:IDENTIFIER); any-identifier: () -> (id: IDENTIFIER) = { id = identifier; || id = type-name; || id = statement-name; }; any-identifier-opt: () -> (id: IDENTIFIER) = { id = any-identifier; || id = ; }; id-entry: () -> (id: IDENTIFIER) = { id = any-identifier; ## ; id = ; }; operator-id: () -> (id: IDENTIFIER) = { ; id = ; }; /* * LITERAL EXPRESSIONS * * These rules describe the literal expressions. These are the integer * and floating point literals and the character and string literals. * Concatenation of adjacent string literals has already been performed. */ 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; }; literal: () -> (e: EXP) = { e = integer-literal; || e = character-literal; || e = floating-literal; || e = string-literal; }; /* * 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); : (:IDENTIFIER) -> (:EXP); expression: () -> (:EXP); primary-expression: () -> (e: EXP) = { e = literal; || id = identifier; 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 = ; }; /* * 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. */ : (:NAMESPACE, :IDENTIFIER) -> (:IDENTIFIER); field-id-expression: (ns: NAMESPACE) -> (id: IDENTIFIER) = { uid = any-identifier; id = (ns, uid); }; /* * 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); : (:EXP) -> (:EXP, :TYPE, :NAMESPACE); : (:EXP, :TYPE, :NAMESPACE, :IDENTIFIER) -> (:EXP); : (:EXP) -> (:EXP, :TYPE, :NAMESPACE); : (:EXP, :TYPE, :NAMESPACE, :IDENTIFIER) -> (:EXP); : () -> (); : () -> (:COUNT); : () -> (:COUNT); : (:COUNT) -> (:COUNT); : (:COUNT) -> (:COUNT); : () -> (); : () -> (); type-id: () -> (:TYPE, :COUNT); type-id-false: () -> (:TYPE, :COUNT); type-id-true: () -> (:TYPE, :COUNT); 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; e = (a, p); close-round; || a = postfix-expression; (b, t, ns) = (a); dot; id = field-id-expression (ns); e = (b, t, ns, id); ; || a = postfix-expression; (b, t, ns) = (a); arrow; id = field-id-expression (ns); e = (b, t, ns, id); ; || a = postfix-expression; plus-plus; e = (a); || a = postfix-expression; minus-minus; e = (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); : () -> (:EXP); : (:LEX, :TYPE, :EXP, :COUNT) -> (:EXP); : (:LEX, :EXP, :COUNT) -> (:TYPE); unary-expression: () -> (:EXP); cast-expression: () -> (:EXP); 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 = unary-expression; e = (a); || minus-minus; a = unary-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); }; /* * 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. */ : (:TYPE, :EXP, :COUNT) -> (:EXP); : (: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); }; /* * 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 = cast-expression; || a = multiplicative-expression; star; b = cast-expression; e = (a, b); || a = multiplicative-expression; div; b = cast-expression; e = (a, b); || a = multiplicative-expression; rem; b = cast-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 = conditional-expression; e = (c, a, b); }; /* * 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 = unary-expression; assign; b = assignment-expression; e = (a, b); || a = unary-expression; op = ; assignment-operator; b = assignment-expression; e = (op, a, b); }; 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. */ : (: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) -> (:BOOL); : (:EXP) -> (); : () -> (:EXP); : () -> (:BOOL); : () -> (:BOOL); : () -> (); declaration-statement: (:BOOL) -> (:EXP); statement-seq-opt: (c: EXP, d: BOOL) -> (e: EXP) = { a = statement; b = (c, a); db = ; e = statement-seq-opt (b, db); || a = declaration-statement (d); b = (c, a); e = statement-seq-opt (b, d); || e = c; }; compound-statement: () -> (e: EXP) = { c = ; open-brace; d = (c); a = statement-seq-opt (c, d); close-brace; e = (a); ; }; function-body: () -> (e: EXP) = { c = ; ; open-brace; d = (c); b = statement-seq-opt (c, d); r = ; a = (b, r); close-brace; e = (a); ; }; function-definition-entry: () -> (e: EXP) = { e = function-body; ## ; e = ; }; /* * 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; d = (c); e = statement-seq-opt (c, d); 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) -> (:BOOL); : () -> (:EXP); declaration: () -> (); declaration-statement: (d: BOOL) -> (e: EXP) = { ? = (d); declaration; e = ; ; }; /* * 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); : () -> (:CONDITION); : (:CONDITION) -> (); selection-statement: () -> (e: EXP) = { if; x = ; r = ; open-round-x; c = expression; a = (c); close-round; bs = ; b = scoped-statement (bs); (r); d = (a, b); { else; ; fs = ; f = scoped-statement (fs); ## f = ; }; (r); e = (d, f); (x); ; || switch; r = ; open-round; c = expression; a = (c); close-round; { exhaustive; ex = ; || ex = ; }; bs = ; b = scoped-statement (bs); (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); for-init-statement: () -> (e: EXP) = { e = expression-statement; || declaration; e = ; ; ; }; for-cond-statement: () -> (e: EXP) = { { a = expression; || a = ; }; b = (a); e = (b); semicolon; }; for-end-statement: () -> (e: EXP) = { a = expression; b = (a); e = (b); || e = ; }; iteration-statement: () -> (e: EXP) = { while; x = ; r = ; open-round; c0 = expression; c = (c0); a = (c); close-round; bs = ; b = scoped-statement (bs); (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 = for-cond-statement; ds = ; b = for-end-statement; h = (g, c, b); close-round; (ds); d = scoped-statement (ds); (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; }; /* * 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. */ token-statement: () -> (e: EXP) = { id = statement-name; a = (id); e = (a); || a = complex-stmt; e = (a); }; /* * 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; }; /* * 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 = control-statement; || e = token-statement; || e = asm-definition; }; 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) -> (:BTYPE); : () -> (:TYPE); : () -> (:TYPE); : (:IDENTIFIER) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:BTYPE, :TYPE, :CV) -> (:TYPE); class-specifier: () -> (:TYPE); enum-specifier: () -> (: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 = ; }; type-specifier: () -> (bt: BTYPE, t: TYPE) = { bt = base-type-specifier; t = ; || id = type-name; t = (id); bt = ; || t = complex-type; bt = ; || t = class-specifier; bt = ; || t = enum-specifier; bt = ; }; /* * CLASS MEMBER SPECIFIERS * * These rules describe the class member specifiers. */ member-declaration: () -> (); member-specification-opt: () -> () = { member-declaration; member-specification-opt; || $; }; /* * 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. */ : (:IDENTIFIER, :KEY) -> (:IDENTIFIER, :BOOL); : (:IDENTIFIER, :BOOL) -> (:IDENTIFIER); : (:IDENTIFIER, :KEY) -> (:TYPE); : () -> (:KEY); : () -> (:KEY); : () -> (:KEY); class-key: () -> (key: KEY) = { struct; key = ; || union; key = ; }; class-specifier: () -> (t: TYPE) = { key = class-key; { id = any-identifier-opt; (p, f) = (id, key); open-brace; member-specification-opt; close-brace; tid = (p, f); t = (tid); ; || id = any-identifier; t = (id, key); }; }; /* * 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. */ : () -> (); : (:IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER) -> (:IDENTIFIER); : (:IDENTIFIER) -> (); : (:IDENTIFIER, :IDENTIFIER, :EXP) -> (); enumerator-definition: (e: IDENTIFIER) -> () = { id = any-identifier; (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: () -> (t: TYPE) = { enum; { id = any-identifier-opt; p = (id); open-brace; { enumerator-list (p); || $; }; close-brace; tid = (p); t = (tid); || id = any-identifier; key = ; t = (id, key); }; }; /* * 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. */ : () -> (:BOOL); : () -> (); type-qualifier: () -> (bt: BTYPE, t: TYPE, cv: CV) = { (bt, t) = type-specifier; cv = ; || cv = cv-qualifier; bt = ; t = ; }; type-specifier-seq: () -> (bt: BTYPE, t: TYPE, cv: CV) = { (b1, t1, cv1) = type-qualifier; { (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) = { ? = ; (b1, t1, cv1) = type-qualifier; ; { (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 'typedef' * 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 = ; || register; ds = ; || typedef; ds = ; }; /* * FUNCTION SPECIFIERS * * This rule describes the function specifier 'inline'. */ : () -> (:DSPEC); function-specifier: () -> (ds: DSPEC) = { inline; ds = ; }; /* * DECLARATION SPECIFIERS * * These rules describes the declaration specifiers. These consist of * the type specifiers, the cv-qualifiers, and the storage class * specifiers. Like type specifiers, declaration specifiers can be * formed into lists which are only turned into complete types and * declaration specifiers later. */ : () -> (:DSPEC); : (:DSPEC, :DSPEC) -> (:DSPEC); : (:DSPEC) -> (); : () -> (:BOOL); decl-specifier: () -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { { ds = storage-class-specifier; || ds = function-specifier; }; (ds); bt = ; t = ; cv = ; || cv = cv-qualifier; bt = ; t = ; ds = ; || (bt, t) = type-specifier; cv = ; ds = ; }; decl-specifier-seq: () -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { (b1, t1, cv1, ds1) = decl-specifier; ; { (b2, t2, cv2, ds2) = decl-specifier-seq; bt = (b1, b2); t = (t1, t2); cv = (cv1, cv2); ds = (ds1, ds2); || bt = b1; t = t1; cv = cv1; ds = ds1; }; }; check-decl-specifier-seq: () -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { ? = ; (b1, t1, cv1, ds1) = decl-specifier; ; { (b2, t2, cv2, ds2) = check-decl-specifier-seq; 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: () -> (bt: BTYPE, t: TYPE, cv: CV, ds: DSPEC) = { (bt, t, cv, ds) = check-decl-specifier-seq; || 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); ptr-operator: () -> (p: TYPE) = { star; cv = cv-qualifier-seq-opt; p = (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. */ : (:EXP) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : (:BOOL) -> (:TYPE); : (:BOOL) -> (:TYPE); : () -> (:TYPE); : () -> (:TYPE); : (:TYPE) -> (); : (:IDENTIFIER) -> (); : () -> (); declarator-aux: () -> (:TYPE, :IDENTIFIER); parameter-declaration-list: () -> (:BOOL); parameter-id-list: () -> (); declarator-tail: (id: IDENTIFIER) -> (t: TYPE) = { open-round; (id); { ell = parameter-declaration-list; s = (ell); close-round; || parameter-id-list; s = ; close-round; || s = ; close-round; }; t = s; ; || open-square; { e = constant-expression; || e = ; }; t = (e); close-square; || weak; open-round; (id); { ell = parameter-declaration-list; || ell = ; }; t = (ell); close-round; ; }; direct-declarator: () -> (t: TYPE, id: IDENTIFIER) = { id = any-identifier; t = ; (id); || (p, id) = direct-declarator; q = declarator-tail (id); t = (p, q); || open-round; (t, id) = declarator-aux; (t); close-round; }; declarator-aux: () -> (t: TYPE, id: IDENTIFIER) = { (t, id) = direct-declarator; || p = ptr-operator; (q, id) = declarator-aux; t = (q, p); }; declarator: (p: TYPE) -> (t: TYPE, id: IDENTIFIER) = { (q, id) = declarator-aux; 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 = ; (id); { ell = parameter-declaration-list; s = (ell); || s = ; }; close-round; t = s; ; || open-square; { e = constant-expression; || e = ; }; t = (e); close-square; || weak; open-round; id = ; (id); { ell = parameter-declaration-list; || ell = ; }; t = (ell); close-round; ; }; 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. */ : () -> (:BOOL); parameter-declarator-aux: () -> (:TYPE, :IDENTIFIER); parameter-declarator-aux-opt: () -> (:TYPE, :IDENTIFIER); direct-parameter-declarator: () -> (t: TYPE, id: IDENTIFIER) = { ? = ; id = any-identifier; t = ; (id); || (p, id) = direct-parameter-declarator; q = abstract-declarator-tail; 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) -> (:DECL); : () -> (:DECL); parameter-declaration: () -> (d: DECL) = { (bt, t1, cv, ds1) = decl-specifier-seq; (t2, ds) = (bt, t1, cv, ds1); (t, id) = parameter-declarator-opt (t2); d = (ds, t, id); }; parameter-declaration-list: () -> (ell: BOOL) = { ellipsis; ell = ; || d = parameter-declaration; { comma; ell = parameter-declaration-list; || ell = ; }; }; parameter-entry: (s: TYPE, p: NUMBER) -> (d: DECL) = { d = parameter-declaration; ## ; d = ; }; template-type-param: () -> (d: DECL) = { ; d = ; }; /* * NON-PROTOTYPE PARAMETER LISTS * * This rules describes the list of function parameter names which * occur in a non-prototype function definition. */ : (:IDENTIFIER) -> (); : (:IDENTIFIER) -> (); first-parameter-id: () -> (id: IDENTIFIER) = { id = identifier; || id = statement-name; }; second-parameter-id: () -> (id: IDENTIFIER) = { id = first-parameter-id; || id = type-name; (id); }; parameter-id-tail: () -> () = { comma; id = second-parameter-id; (id); (id); parameter-id-tail; || $; }; parameter-id-list: () -> () = { id = first-parameter-id; (id); (id); parameter-id-tail; }; /* * 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; c = constant-expression; t = (q, bt, c); }; }; type-id-entry: () -> (t: TYPE) = { t = token-type-id; (t); ## ; t = ; }; /* * INITIALISERS * * These rules describe the initialisers. This includes the assignment * style and aggregate initialisers. */ : (:LIST-EXP) -> (:EXP); 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; || open-brace; { p = initialiser-list (d); || p = ; }; close-brace; e = (p); }; initialiser-opt: (d: DECL) -> (e: EXP) = { 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) -> () = { (t, id) = declarator (p); d = (ds, bt, t, id); e = initialiser-opt (d); (d, e); }; init-declarator-list: (ds: DSPEC, bt: BTYPE, t: TYPE) -> () = { init-declarator (ds, bt, t); { comma; init-declarator-list (ds, bt, t); || $; }; }; /* * 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. */ : (:EXP) -> (); : (:EXP) -> (); : () -> (); : () -> (); declaration-seq-opt: () -> (); declaration-cond-body: () -> () = { open-brace; ds = ; t = ; declaration-seq-opt (); 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) -> (); : () -> (); external-declaration: () -> (:EXP); declaration-elem: () -> () = { e = external-declaration; (e); || declaration-cond; || semicolon; ; }; declaration-seq-opt: () -> () = { declaration-elem; declaration-seq-opt; || $; }; /* * DECLARATIONS * * This rule describes the declarations. */ : (:DSPEC, :BTYPE, :TYPE, :CV) -> (); declaration: () -> () = { (bt, t1, cv, ds1) = check-decl-specifier-seq; { (t, ds) = (bt, t1, cv, ds1); init-declarator-list (ds, bt, t); || (ds1, bt, t1, cv); }; semicolon; }; declaration-entry: (t: TYPE, ds: DSPEC) -> () = { declaration; ## ; }; /* * EXTERNAL DECLARATIONS * * This rule describes the external declarations. Note that the normal * declaration rule has been unrolled once to allow it to be combined * with the function-definition rule. */ : (:TYPE) -> (:BOOL); : (:DSPEC, :TYPE, :IDENTIFIER) -> (:DECL); : (:DECL) -> (:BOOL); : (:DECL, :EXP, :BOOL) -> (); external-declaration: () -> (e: EXP) = { (bt, t1, cv, ds1) = check-decl-specifier-seq-opt; (t, ds) = (bt, t1, cv, ds1); (s, id) = declarator (t); { d = (ds, bt, s, id); a = initialiser-opt (d); (d, a); { comma; init-declarator-list (ds, bt, t); || $; }; semicolon; || ? = (s); d = (ds, s, id); b = (d); a = function-body; (d, a, b); ; }; e = ; || (bt, t, cv, ds) = check-decl-specifier-seq; (ds, bt, t, cv); semicolon; e = ; || e = asm-definition; }; /* * 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'. */ : (:TYPE, :IDENTIFIER) -> (); : (:TYPE, :IDENTIFIER) -> (); : (:TYPE, :BTYPE, :EXP, :IDENTIFIER) -> (:TYPE); member-declarator: (p: TYPE, q: BTYPE) -> () = { (t, id) = declarator (p); (t, id); || id = any-identifier-opt; (id); colon; c = constant-expression; t = (p, q, c, id); (t, id); }; member-declarator-list: (p: TYPE, q: BTYPE) -> () = { member-declarator (p, q); { comma; member-declarator-list (p, q); || $; }; }; /* * CLASS MEMBER DECLARATION * * This rule describes the class member declarations. */ : (:BTYPE, :TYPE, :CV) -> (); member-declaration: () -> () = { (bt, p, cv) = check-type-specifier-seq; t = (bt, p, cv); member-declarator (t, bt); { semicolon; || comma; member-declarator-list (t, bt); semicolon; }; || (bt, p, cv) = check-type-specifier-seq; (bt, p, cv); semicolon; }; /* * 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; 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;