/* * 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 * * 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/tools/tspec/syntax.sid,v 1.10 2005/10/31 09:01:43 stefanf Exp $ */ %types% /* * TYPES * * The types are fairly self-explanatory. Note that distinctions are * made in the parser type system which do not exist in the underlying * program. */ BOOLEAN; COMMAND; COMMAND_KEY; IDENTIFIER; STRING; SUBSET_KEY; TYPE; TYPE_KEY; TYPE_LIST; TYPE_QUAL; TYPE_SPEC; VERSION; %terminals% /* * TERMINALS * * The terminals are arranged in five groups; the names and strings, the * commands (beginning with '+'), the types, the special macro names * (beginning with '~'), and the punctuators and operators. */ name: () -> (:STRING); number: () -> (:STRING); string: () -> (:STRING); variable: () -> (:STRING); comment: () -> (:STRING); insert: () -> (:STRING); build-insert: () -> (:STRING); base-api; constant; define; else; endif; enumerate; exp; field; func; if; ifdef; ifndef; implement; info; macro; nat; set; statement; !subset; token; type; typedef; use; arith; char; const; double; enum; extern; float; int; long; lvalue; restrict; scalar; short; signed; struct; union; unsigned; void; volatile; weak; building; promote; protect; special; open-brace; close-brace; open-round; close-round; open-square; close-square; assign; colon; comma; dot; !dot-dot; ellipsis; equal; exclaim; minus; or; question; semicolon; star; eof; !unknown; %productions% /* * BUILT-IN TYPES * * These rules describe the built-in types. Illegal combinations of * keywords are detected by the action . */ : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : () -> (:TYPE_SPEC); : (:TYPE_SPEC, :TYPE_SPEC) -> (:TYPE_SPEC); type-keyword: () -> (b: TYPE_SPEC) = { char; b = ; || short; b = ; || int; b = ; || long; b = ; || signed; b = ; || unsigned; b = ; || float; b = ; || double; b = ; || void; b = ; }; builtin-type: () -> (b: TYPE_SPEC) = { a = type-keyword; { d = builtin-type; c = (a, d); || c = a; }; b = c; }; /* * SIMPLE TYPES * * These rules describes the simple, unqualified, types. */ : (:TYPE_SPEC) -> (:TYPE); : (:STRING, :TYPE_KEY) -> (:TYPE); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); type-key: () -> (tag: TYPE_KEY) = { tag = ; || struct; tag = ; || union; tag = ; || enum; tag = ; }; simple-type: () -> (t: TYPE) = { b = builtin-type; t = (b); || tag = type-key; nm = name; t = (nm, tag); }; /* * QUALIFIED TYPES * * These rules describe the type qualifiers and the qualified types. */ : () -> (:TYPE_QUAL); : (:TYPE_QUAL) -> (:TYPE_QUAL); : (:TYPE_QUAL) -> (:TYPE_QUAL); : (:TYPE_QUAL) -> (:TYPE_QUAL); : (:TYPE, :TYPE_QUAL) -> (:TYPE); type-qualifier: () -> (:TYPE_QUAL); type-qualifier-opt: () -> (cv: TYPE_QUAL) = { cv = ; || cv = type-qualifier; }; type-qualifier: () -> (cv: TYPE_QUAL) = { const; a = type-qualifier-opt; cv = (a); || restrict; a = type-qualifier-opt; cv = (a); || volatile; a = type-qualifier-opt; cv = (a); }; qualified-type: () -> (t: TYPE) = { t = simple-type; || cv = type-qualifier; s = simple-type; t = (s, cv); || s = simple-type; cv = type-qualifier; t = (s, cv); }; /* * LVALUE QUALIFIERS * * This rule describes the lvalue and rvalue type qualifiers. */ : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); object-qualifier: () -> (lv: TYPE_KEY) = { lvalue; lv = ; || lv = ; }; /* * CONSTANT EXPRESSIONS * * This rule describes the constant expressions. These comprise the * numbers, the NAT token names, plus some simple operations on these * values. More complex expressions can be expressed using an insert. */ : () -> (:STRING); : (:STRING) -> (:STRING); : (:STRING) -> (:STRING); : (:STRING) -> (:STRING); constant-value: () -> (s: STRING) = { s = number; || s = insert; || a = name; s = (a); || minus; a = constant-value; s = (a); || exclaim; a = constant-value; s = (a); }; /* * POINTER TYPE OPERATOR * * This rule describes the pointer type operator. */ : (:TYPE_QUAL) -> (:TYPE); ptr-operator: () -> (t: TYPE) = { star; cv = type-qualifier-opt; t = (cv); }; /* * ARRAY TYPE OPERATOR * * This rule describes the array type operator. */ : (:STRING) -> (:TYPE); array-operator: () -> (t: TYPE) = { open-square; { a = constant-value; || a = ; }; close-square; t = (a); }; /* * BITFIELD TYPE OPERATOR * * This rule describes the bitfield type operator. */ : (:STRING) -> (:TYPE); bitfield-operator: () -> (t: TYPE) = { colon; a = constant-value; t = (a); }; /* * FUNCTION TYPE OPERATOR * * These rules describe the function type operator. */ : (:TYPE_LIST) -> (:TYPE); : (:TYPE, :TYPE) -> (:TYPE); : () -> (:TYPE_LIST); : () -> (:TYPE_LIST); : () -> (:TYPE_LIST); : (:TYPE, :TYPE_LIST) -> (:TYPE_LIST); : (:STRING) -> (); abstract-declarator: () -> (:STRING, :TYPE); parameter-declaration: () -> (t: TYPE) = { s = qualified-type; (nm, p) = abstract-declarator; t = (p, s); (nm); }; parameter-list: () -> (p: TYPE_LIST) = { t = parameter-declaration; { comma; q = parameter-list; || comma; ellipsis; q = ; || q = ; }; p = (t, q); }; function-operator: () -> (t: TYPE) = { open-round; p = parameter-list; close-round; t = (p); || open-round; close-round; p = ; t = (p); }; /* * MACRO TYPE OPERATOR * * These rules describe the macro type operator. This is similar to the * function type operator except that each parameter may be specified * as an lvalue and there are no ellipsis parameters. */ : (:TYPE, :TYPE_KEY) -> (:TYPE); : (:TYPE_LIST) -> (:TYPE); macro-param-declaration: () -> (t: TYPE) = { lv = object-qualifier; s = qualified-type; (nm, p) = abstract-declarator; u = (p, s); t = (u, lv); (nm); }; macro-param-list: () -> (p: TYPE_LIST) = { t = macro-param-declaration; { comma; q = macro-param-list; || q = ; }; p = (t, q); }; macro-operator: () -> (t: TYPE) = { open-round; p = macro-param-list; close-round; t = (p); || open-round; close-round; p = ; t = (p); }; /* * MACRO DEFINITION PARAMETER LISTS * * These rules describe the macro definition parameter lists. These * comprise a simple list of identifier names. */ : () -> (:STRING); : () -> (:STRING); : (:STRING, :STRING) -> (:STRING); define-param-list: () -> (p: STRING) = { n = name; comma; q = define-param-list; p = (n, q); || p = name; }; define-param-clause: () -> (p: STRING) = { open-round; p = define-param-list; close-round; || open-round; close-round; p = ; || p = ; }; /* * OBJECT DECLARATORS * * These rules describe the object declarators. These consist of an * identifier qualified using pointer, array and function type * operators. */ : () -> (:TYPE); declarator: () -> (:IDENTIFIER, :TYPE); identifier: () -> (:IDENTIFIER); direct-declarator: () -> (id: IDENTIFIER, t: TYPE) = { id = identifier; t = ; || (id, p) = direct-declarator; s = function-operator; t = (p, s); || (id, p) = direct-declarator; s = array-operator; t = (p, s); || open-round; (id, t) = declarator; close-round; }; declarator: () -> (id: IDENTIFIER, t: TYPE) = { (id, t) = direct-declarator; || p = ptr-operator; (id, s) = declarator; t = (s, p); }; /* * MACRO DECLARATORS * * These rules describe the macro declarators. These are a restricted * subset of the declarators in which only pointer operators are allowed. */ macro-declarator: () -> (id: IDENTIFIER, t: TYPE) = { id = identifier; t = ; || p = ptr-operator; (id, s) = macro-declarator; t = (s, p); }; /* * ABSTRACT DECLARATORS * * These rules describe the abstract declarators, as used in function * parameter declarations. For simplicity, the case of a list of * function parameters without a declarator has been omitted; function * parameters should be pointers to functions, rather than functions, * anyway. */ : () -> (:STRING); direct-abstract-declarator: () -> (nm: STRING, t: TYPE) = { nm = ; t = ; || nm = name; t = ; || (nm, p) = direct-abstract-declarator; s = array-operator; t = (p, s); || open-round; (nm, t) = abstract-declarator; close-round; || open-round; (nm, p) = abstract-declarator; close-round; s = function-operator; t = (p, s); }; abstract-declarator: () -> (nm: STRING, t: TYPE) = { (nm, t) = direct-abstract-declarator; || p = ptr-operator; (nm, s) = abstract-declarator; t = (s, p); }; /* * IDENTIFIER NAMES * * These rules describe the identifier names. These comprise the actual * internal name, plus an optional external name (the external and internal * names are equal if this is not given). Either name may have an * associated version number. */ : (:STRING) -> (:STRING); : (:STRING) -> (:STRING); : () -> (:VERSION); : (:STRING) -> (:VERSION); : (:STRING, :VERSION, :STRING, :VERSION) -> (:IDENTIFIER); name-version: () -> (v: VERSION) = { dot; n = number; v = (n); || v = ; }; internal-name: () -> (nm: STRING, v: VERSION) = { a = name; v = name-version; nm = (a); }; external-name: () -> (nm: STRING, v: VERSION) = { a = name; v = name-version; b = (a); nm = (b); || nm = string; v = name-version; }; identifier: () -> (id: IDENTIFIER) = { (nm, v) = internal-name; tnm = (nm); id = (nm, v, tnm, v); || (nm, v) = internal-name; or; (tnm, tv) = external-name; id = (nm, v, tnm, tv); }; /* * SUBSET NAMES * * These rules describe the specification subset names. These consist * of between one and three components, giving the API name, the header * file within that API, and the subset of that header. */ : () -> (:COMMAND_KEY); : () -> (:COMMAND_KEY); : (:STRING) -> (:STRING); : (:STRING, :STRING) -> (:STRING); : (:STRING, :STRING, :STRING) -> (:STRING); implement-command: () -> (cmd: COMMAND_KEY) = { implement; cmd = ; || use; cmd = ; }; subset-name: () -> (s: STRING) = { a = string; s = (a); || a = string; comma; b = string; s = (a, b); || a = string; comma; b = string; comma; c = string; s = (a, b, c); }; use-subset-name: () -> (s: STRING) = { open-round; a = string; close-round; comma; b = string; s = (a, b); }; /* * SUBSET USAGE KEYS * * This rule describes the subset usage keys. These are used to indicate * whether a file inclusion refers to the specification output, the * library building output, or both. */ : () -> (:SUBSET_KEY); : () -> (:SUBSET_KEY); : () -> (:SUBSET_KEY); : () -> (:SUBSET_KEY); : (:SUBSET_KEY) -> (:SUBSET_KEY); subset-key: () -> (key: SUBSET_KEY) = { key = ; || open-round; question; question; close-round; key = ; || open-round; exclaim; question; close-round; key = ; || open-round; question; exclaim; close-round; key = ; || open-round; exclaim; exclaim; close-round; key = ; }; /* * CONDITIONAL COMPILATION COMMANDS * * These rules describe the conditional compilation commands. */ : () -> (:STRING); : (:STRING, :STRING) -> (:STRING); : (:STRING) -> (:COMMAND); : (:STRING) -> (:COMMAND); : (:STRING) -> (:COMMAND); : (:COMMAND, :STRING, :COMMAND, :COMMAND) -> (:COMMAND); ifdef-macro-name: () -> (c: STRING) = { c = name; || building; c = ; || protect; open-round; a = string; comma; b = string; close-round; c = (a, b); }; if-command: () -> (c: COMMAND, s: STRING) = { if; s = constant-value; c = (s); || ifdef; s = ifdef-macro-name; c = (s); || ifndef; s = ifdef-macro-name; c = (s); }; /* * ENUMERATION COMMANDS * * These rules describe the enumeration commands. Each enumeration type * consists of a list of enumerator names, each of which may be associated * with a value. */ : () -> (:COMMAND); : (:COMMAND, :COMMAND) -> (:COMMAND); : (:IDENTIFIER, :STRING) -> (:COMMAND); : () -> (:TYPE_KEY); enum-command: () -> (tag: TYPE_KEY) = { tag = ; || enum; tag = ; }; enumerator: () -> (c: COMMAND) = { id = identifier; { equal; s = constant-value; || s = ; }; c = (id, s); }; enumerator-list: () -> (c: COMMAND) = { a = enumerator; { comma; b = enumerator-list; || b = ; }; c = (a, b); }; /* * EXPRESSION COMMANDS * * These rules describe the expression commands. Each expression command * consists of an lvalue specifier, a qualified type plus a list of * declarators. */ : () -> (:COMMAND_KEY); : () -> (:COMMAND_KEY); : () -> (:COMMAND_KEY); : (:COMMAND_KEY, :IDENTIFIER, :TYPE) -> (:COMMAND); exp-command: () -> (cmd: COMMAND_KEY) = { constant; cmd = ; || exp; cmd = ; || exp; open-round; const; close-round; cmd = ; || exp; open-round; extern; close-round; cmd = ; }; exp-declarator-list: (cmd: COMMAND_KEY, s: TYPE, lv: TYPE_KEY) -> (c: COMMAND) = { (id, p) = declarator; u = (p, s); t = (u, lv); a = (cmd, id, t); { comma; b = exp-declarator-list (cmd, s, lv); || b = ; }; c = (a, b); }; /* * FIELD COMMANDS * * These rules describe the field commands. Each field consists of a * qualified type and a list of declarators. Conditional compilation * of fields is allowed. */ : () -> (:BOOLEAN); : () -> (:BOOLEAN); : () -> (:IDENTIFIER); : (:IDENTIFIER, :TYPE, :TYPE) -> (:COMMAND); field-exact: () -> (e: BOOLEAN) = { assign; e = ; || e = ; }; field-declarator: () -> (id: IDENTIFIER, t: TYPE) = { (id, t) = declarator; || id = identifier; t = bitfield-operator; || t = bitfield-operator; id = ; }; field-declarator-list: (m: TYPE, s: TYPE) -> (c: COMMAND) = { (id, p) = field-declarator; t = (p, s); a = (id, m, t); { comma; b = field-declarator-list (m, s); || b = ; }; c = (a, b); }; field-list: (m: TYPE) -> (c: COMMAND) = { c = ; || t = qualified-type; a = field-declarator-list (m, t); semicolon; b = field-list (m); c = (a, b); || (i, s) = if-command; a = field-list (m); { else; b = field-list (m); || b = ; }; endif; c1 = (i, s, a, b); c2 = field-list (m); c = (c1, c2); }; /* * FUNCTION COMMANDS * * This rule describes the various function command keys. */ : () -> (:COMMAND_KEY); : () -> (:COMMAND_KEY); : () -> (:COMMAND_KEY); func-command: () -> (cmd: COMMAND_KEY) = { func; cmd = ; || func; open-round; extern; close-round; cmd = ; || func; open-round; weak; close-round; cmd = ; }; /* * INTEGER CONSTANT COMMANDS * * This rule describes the integer constant commands. This consists of * a simple list of identifiers. */ : (:IDENTIFIER) -> (:COMMAND); nat-declarator-list: () -> (c: COMMAND) = { id = identifier; a = (id); { comma; b = nat-declarator-list; || b = ; }; c = (a, b); }; /* * TYPE COMMANDS * * These rules describe the type commands. These comprise a list of * identifiers, each preceded by an optional type command key. */ : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : () -> (:TYPE_KEY); : (:TYPE_KEY, :IDENTIFIER) -> (:COMMAND); type-command: () -> (tag: TYPE_KEY) = { tag = ; || open-round; int; close-round; tag = ; || open-round; signed; close-round; tag = ; || open-round; unsigned; close-round; tag = ; || open-round; float; close-round; tag = ; || open-round; arith; close-round; tag = ; || open-round; scalar; close-round; tag = ; || open-round; struct; close-round; tag = ; || open-round; union; close-round; tag = ; || struct; tag = ; || union; tag = ; }; type-declarator-list: () -> (c: COMMAND) = { tag = type-command; id = identifier; a = (tag, id); { comma; b = type-declarator-list; || b = ; }; c = (a, b); }; /* * SUBSET COMMAND * * These rules describes the subset command. This is the main entry point * into the grammar. */ : (:STRING) -> (:COMMAND); : (:COMMAND, :COMMAND) -> (:COMMAND); : () -> (); command-list: () -> (:COMMAND); subset-command: () -> (c: COMMAND) = { set; s = subset-name; assign; a = (s); open-brace; b = command-list; close-brace; c = (a, b); }; specification: () -> (c: COMMAND) = { c = subset-command; semicolon; eof; ## ; c = ; }; /* * SPECIFICATION COMMANDS * * This rule describes the main group of commands; those which introduce * a specification item. */ : () -> (:COMMAND); : (:IDENTIFIER, :STRING, :STRING) -> (:COMMAND); : (:TYPE_KEY, :IDENTIFIER, :COMMAND) -> (:COMMAND); : (:COMMAND_KEY, :IDENTIFIER, :TYPE) -> (:COMMAND); : (:IDENTIFIER, :TYPE) -> (:COMMAND); : (:IDENTIFIER, :TYPE) -> (:COMMAND); : (:IDENTIFIER, :TYPE) -> (:COMMAND); : (:IDENTIFIER, :STRING) -> (:COMMAND); : (:IDENTIFIER, :TYPE) -> (:COMMAND); : (:COMMAND_KEY, :STRING, :SUBSET_KEY) -> (:COMMAND); : (:IDENTIFIER, :TYPE_KEY) -> (:TYPE, :COMMAND); : (:TYPE, :COMMAND, :COMMAND, :BOOLEAN) -> (:COMMAND); : (:STRING) -> (:TYPE); : (:COMMAND_KEY, :TYPE_KEY) -> (:TYPE_KEY); spec-command: () -> (c: COMMAND) = { base-api; c = ; || define; id = identifier; p = define-param-clause; s = constant-value; c = (id, p, s); || enumerate; tag = enum-command; id = identifier; assign; open-brace; e = enumerator-list; close-brace; c = (tag, id, e); || cmd = exp-command; lv1 = object-qualifier; lv = (cmd, lv1); t = qualified-type; c = exp-declarator-list (cmd, t, lv); || field; tag = type-command; id = identifier; e = field-exact; (t, a) = (id, tag); open-brace; b = field-list (t); close-brace; c = (t, a, b, e); || cmd = func-command; s = qualified-type; (id, p) = declarator; t = (p, s); c = (cmd, id, t); || macro; lv = object-qualifier; s = qualified-type; (id, p) = macro-declarator; u = (p, s); v = (u, lv); { q = macro-operator; || q = ; }; t = (q, v); c = (id, t); || nat; c = nat-declarator-list; || statement; id = identifier; { t = macro-operator; || t = ; }; c = (id, t); || token; id = identifier; s = insert; c = (id, s); || type; c = type-declarator-list; || typedef; s = qualified-type; (id, p) = declarator; t = (p, s); c = (id, t); || typedef; promote; open-round; t = qualified-type; close-round; id = identifier; c = (id, t); || typedef; special; open-round; s = string; close-round; t = (s); id = identifier; c = (id, t); || cmd = implement-command; s = subset-name; key = subset-key; c = (cmd, s, key); || use; cmd = ; s = use-subset-name; key1 = subset-key; key = (key1); c = (cmd, s, key); || c = subset-command; }; /* * TEXTUAL COMMANDS * * This rule describes the second group of commands; those which are * concerned with textual substitution. */ : (:STRING) -> (:COMMAND); : (:STRING) -> (:COMMAND); : (:STRING) -> (:COMMAND); text-command: () -> (c: COMMAND) = { (i, s) = if-command; a = command-list; { else; b = command-list; || b = ; }; endif; c = (i, s, a, b); || s = comment; c = (s); || s = insert; c = (s); || s = build-insert; c = (s); }; /* * VARIABLE COMMANDS * * This rule describes the third group of commands; those which affect the * program environment, but do not actually introduce a specified item. */ : (:STRING, :STRING) -> (); : (:STRING, :STRING) -> (); : (:STRING, :STRING) -> (); variable-command: () -> () = { info; s = string; || nm = variable; equal; s = string; (nm, s); || nm = variable; equal; s = number; (nm, s); || nm = variable; equal; minus; s = number; (nm, s); }; /* * COMMAND LISTS * * These rules describe the lists of commands. */ command-list: () -> (c: COMMAND) = { c = ; || a = spec-command; semicolon; b = command-list; c = (a, b); || a = text-command; b = command-list; c = (a, b); || variable-command; semicolon; c = command-list; }; %entry% specification;