/*
* 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 =