%prefixes%
terminal = lex_;
%maps%
/*
* ENTRY POINT
*
* The main entry point for is mapped onto a function named read_spec.
*/
specification -> read_spec;
/*
* TYPE MAPPINGS
*
* These maps give the relationship between the types used in the syntax
* and in the C implementation.
*/
BOOLEAN -> int;
COMMAND -> SID_COMMAND;
COMMAND_KEY -> int;
IDENTIFIER -> SID_IDENTIFIER;
STRING -> SID_STRING;
SUBSET_KEY -> SID_STRING;
TYPE -> SID_TYPE;
TYPE_KEY -> int;
TYPE_LIST -> SID_TYPE;
TYPE_QUAL -> unsigned;
TYPE_SPEC -> unsigned;
VERSION -> int;
%header% @{
/*
* 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.act,v 1.9 2005/10/31 10:17:01 stefanf Exp $
*/
#include "config.h"
#include "cstring.h"
#include "msgcat.h"
#include "object.h"
#include "hash.h"
#include "lex.h"
#include "name.h"
#include "syntax.h"
#include "type.h"
#include "utility.h"
#include "variable.h"
/*
* PARSER TYPES
*
* These types give the implementations of the various types used
* in the syntax.
*/
typedef char *SID_STRING;
typedef type *SID_TYPE;
typedef struct {
char *iname;
char *ename;
int ivers;
int evers;
} SID_IDENTIFIER;
/*
* CURRENT FIELD NAME
*
* The name of the current structure is stored during a +FIELD
* construct.
*/
static char *crt_field_name = null;
static int anon_no = 0;
/*
* CV-QUALIFIER NAMES
*
* This table gives the mapping between the values used to represent
* cv-qualifiers in the parser and the qualifier names used in the
* internal representation.
*/
static char *cv_qualifier [] = {
null, "const", "restrict", "const restrict",
"volatile", "const volatile", "const restrict volatile"
};
/*
* COMPILATION MODE
*
* We allow unreached code in the automatically generated sections.
*/
#ifdef __TenDRA__
#pragma TenDRA begin
#pragma TenDRA unreachable code allow
#pragma TenDRA variable analysis off
#endif
@}, @{
/*
* 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.act,v 1.9 2005/10/31 10:17:01 stefanf Exp $
*/
#ifndef SYNTAX_INCLUDED
#define SYNTAX_INCLUDED
typedef object *SID_COMMAND;
@};
%terminals%
/*
* TERMINALS
*
* The mapping of the terminals is trivial.
*/
name: () -> (s) = @{ @s = token_value; @};
number: () -> (s) = @{ @s = token_value; @};
string: () -> (s) = @{ @s = token_value; @};
variable: () -> (s) = @{ @s = token_value; @};
comment: () -> (s) = @{ @s = token_value; @};
insert: () -> (s) = @{ @s = token_value; @};
build-insert: () -> (s) = @{ @s = token_value; @};
%actions%
/*
* BOOLEAN CONSTANTS
*
* These actions describe the boolean constants.
*/
: () -> (b) = @{ @b = 0; @};
: () -> (b) = @{ @b = 1; @};
/*
* BASIC TYPE SPECIFIERS
*
* These actions describe the basic type specifiers.
*/
: () -> (b) = @{ @b = BTYPE_CHAR; @};
: () -> (b) = @{ @b = BTYPE_SHORT; @};
: () -> (b) = @{ @b = BTYPE_INT; @};
: () -> (b) = @{ @b = BTYPE_LONG; @};
: () -> (b) = @{ @b = BTYPE_SIGNED; @};
: () -> (b) = @{ @b = BTYPE_UNSIGNED; @};
: () -> (b) = @{ @b = BTYPE_FLOAT; @};
: () -> (b) = @{ @b = BTYPE_DOUBLE; @};
: () -> (b) = @{ @b = BTYPE_VOID; @};
: (a, b) -> (c) = @{
while (@a & @b) {
if (@a == BTYPE_LONG && allow_long_long) {
@a = BTYPE_LLONG;
} else {
MSG_duplicate_type_specifier ();
break;
}
}
@c = (@a | @b);
@};
/*
* TYPE KEYS
*
* These actions describe the type keys.
*/
: () -> (t) = @{ @t = TYPE_GENERIC; @};
: () -> (t) = @{ @t = TYPE_STRUCT_TAG; @};
: () -> (t) = @{ @t = TYPE_UNION_TAG; @};
: () -> (t) = @{ @t = TYPE_ENUM_TAG; @};
: () -> (t) = @{ @t = TYPE_STRUCT; @};
: () -> (t) = @{ @t = TYPE_UNION; @};
: () -> (t) = @{ @t = TYPE_ENUM; @};
: () -> (t) = @{ @t = TYPE_INT; @};
: () -> (t) = @{ @t = TYPE_SIGNED; @};
: () -> (t) = @{ @t = TYPE_UNSIGNED; @};
: () -> (t) = @{ @t = TYPE_FLOAT; @};
: () -> (t) = @{ @t = TYPE_ARITH; @};
: () -> (t) = @{ @t = TYPE_SCALAR; @};
: () -> (t) = @{ @t = TYPE_LVALUE; @};
: () -> (t) = @{ @t = TYPE_RVALUE; @};
: (c, a) -> (t) = @{
if (@c == OBJ_CONST) {
if (@a == TYPE_LVALUE) {
MSG_constant_cant_be_lvalue ();
}
@t = TYPE_RVALUE;
} else if (@c == OBJ_EXTERN) {
@t = TYPE_LVALUE;
} else {
@t = @a;
}
@};
/*
* TYPE QUALIFIERS
*
* These actions describe the type qualifiers. const is represented by 1,
* restrict by 2 and volatile by 4.
*/
: () -> (c) = @{
@c = 0;
@};
: (a) -> (c) = @{
if (@a & 1) MSG_duplicate_type_qualifier ();
@c = (@a | 1);
@};
: (a) -> (c) = @{
if (@a & 2) MSG_duplicate_type_qualifier ();
@c = (@a | 2);
@};
: (a) -> (c) = @{
if (@a & 4) MSG_duplicate_type_qualifier ();
@c = (@a | 4);
@};
/*
* TYPE CONSTRUCTORS
*
* These actions describe the type constructors.
*/
: () -> (t) = @{
@t = null;
@};
: (b) -> (t) = @{
@t = basic_type (@b);
@};
: (s, tag) -> (t) = @{
@t = find_type (@s, any_version, @tag, 1);
@};
: (s) -> (t) = @{
@t = special_type (@s);
@};
: (s, p) -> (t) = @{
@t = inject_type (@s, @p);
@};
: (c) -> (t) = @{
@t = make_subtype ((type *) null, TYPE_PTR);
@t->v.str = cv_qualifier [@c];
@};
: (a) -> (t) = @{
@t = make_subtype ((type *) null, TYPE_ARRAY);
@t->v.str = @a;
@};
: (a) -> (t) = @{
@t = make_subtype ((type *) null, TYPE_BITFIELD);
@t->v.str = @a;
@};
: (p) -> (t) = @{
@t = make_subtype ((type *) null, TYPE_PROC);
@t->v.next = @p;
@};
: (p) -> (t) = @{
@t = make_subtype ((type *) null, TYPE_PROC);
@t->v.next = @p;
@};
: (s, c) -> (t) = @{
@t = make_subtype (@s, TYPE_QUALIFIER);
@t->v.str = cv_qualifier [@c];
@};
: (s, lv) -> (t) = @{
@t = make_subtype (@s, @lv);
@};
/*
* TYPE LISTS
*
* These actions describe the parameter type lists.
*/
: () -> (p) = @{
@p = null;
@};
: () -> (p) = @{
MSG_empty_parameter_list ();
@p = null;
@};
: (t, q) -> (p) = @{
@p = make_subtype (@t, TYPE_LIST);
@p->v.next = @q;
@};
: () -> (p) = @{
@p = make_subtype (type_ellipsis, TYPE_LIST);
@p->v.next = null;
@};
: (nm) -> () = @{
UNUSED (@nm);
@};
/*
* CONSTANT EXPRESSIONS
*
* These actions describe the constant expressions.
*/
: () -> (s) = @{
@s = "";
@};
: (a) -> (s) = @{
@s = string_concat ("-", @a);
@};
: (a) -> (s) = @{
@s = string_concat ("!", @a);
@};
: (a) -> (s) = @{
object *p = search_hash (exps, @a, any_version);
if (p == null) {
MSG_undefined_nat (@a);
} else if (p->objtype != OBJ_NAT) {
MSG_not_a_nat (@a);
}
@s = @a;
@};
/*
* CONDITIONAL COMPILATION MACROS
*
* These rules describe the special macros which can be used in
* conditional compilation.
*/
: () -> (s) = @{
@s = BUILDING_MACRO;
@};
: (a, b) -> (s) = @{
@s = macro_name (PROTECT_PREFIX, @a, @b, NULL);
@};
/*
* MACRO DEFINITION PARAMETERS
*
* These rules describe the macro definition parameter lists.
*/
: () -> (p) = @{ @p = null; @};
: () -> (p) = @{ @p = ""; @};
: (n, q) -> (p) = @{
@p = string_printf ("%s, %s", @n, @q);
@};
/*
* IDENTIFIERS
*
* These actions describe the identifier names.
*/
: () -> (nm) = @{
@nm = null;
@};
: (fnm) -> (nm) = @{
if (crt_field_name) {
@nm = string_printf ("%s.%s", crt_field_name, @fnm);
} else {
@nm = @fnm;
}
@};
: (tnm) -> (nm) = @{
@nm = token_name (@tnm);
@};
: (a, va, b, vb) -> (id) = @{
@id.iname = @a;
@id.ivers = @va;
@id.ename = @b;
@id.evers = @vb;
@};
: () -> (id) = @{
char *nm = string_printf ("%s%d", HIDDEN_NAME, anon_no++);
if (crt_field_name) {
nm = string_printf ("%s.%s", crt_field_name, nm);
}
@id.iname = nm;
@id.ivers = no_version;
@id.ename = token_name (nm);
@id.evers = no_version;
@};
: () -> (v) = @{
@v = no_version;
@};
: (n) -> (v) = @{
@v = atoi (@n);
@};
/*
* SUBSET NAMES
*
* These actions describe the subset names.
*/
: () -> (s) = @{ @s = "00"; @};
: () -> (s) = @{ @s = "10"; @};
: () -> (s) = @{ @s = "01"; @};
: () -> (s) = @{ @s = "11"; @};
: (a) -> (s) = @{ @s = string_concat (@a, "G"); @};
: (a) -> (s) = @{
@s = subset_name (@a, NULL, NULL);
@};
: (a, b) -> (s) = @{
@s = subset_name (@a, @b, NULL);
@};
: (a, b, c) -> (s) = @{
if (@b [0] == 0) @b = null;
@s = subset_name (@a, @b, @c);
@};
/*
* COMMAND KEYS
*
* These actions describe the command keys.
*/
: () -> (c) = @{ @c = OBJ_CONST; @};
: () -> (c) = @{ @c = OBJ_EXP; @};
: () -> (c) = @{ @c = OBJ_EXTERN; @};
: () -> (c) = @{ @c = OBJ_FUNC; @};
: () -> (c) = @{ @c = OBJ_EXTERN; @};
: () -> (c) = @{ @c = OBJ_WEAK; @};
: () -> (c) = @{ @c = OBJ_IMPLEMENT; @};
: () -> (c) = @{ @c = OBJ_USE; @};
/*
* COMMANDS
*
* These actions describe the basic command constructs.
*/
: () -> (c) = @{
@c = null;
@};
: (a, b) -> (c) = @{
@c = join_object (@a, @b);
@};
: (s) -> (c) = @{
object *p = make_subset (@s);
info *i = p->u.u_info;
if (i->subset) {
char *nm = subset_name (i->api, i->file, NULL);
object *q = search_hash (subsets, nm, no_version);
update_time (p, q);
}
@c = crt_object;
crt_object = p;
@};
: (a, b) -> (c) = @{
object *p = crt_object;
if (p) p->u.u_info->elements = @b;
@c = make_object (NULL, OBJ_SET);
@c->u.u_obj = p;
crt_object = @a;
@};
: (cmd, s, key) -> (c) = @{
object *p = make_subset (@s);
update_time (crt_object, p);
@c = make_object (@key, @cmd);
@c->u.u_obj = p;
@};
/*
* VARIABLE COMMANDS
*
* These commands describe the variable assignment commands.
*/
: (a, b) -> () = @{
set_string (@a, @b);
@};
: (a, b) -> () = @{
set_integer (@a, atoi (@b));
@};
: (a, b) -> () = @{
set_integer (@a, -atoi (@b));
@};
/*
* SPECIFICATION COMMANDS
*
* These actions describe the constructs for the various specification
* commands.
*/
: () -> (c) = @{
@c = null;
@};
: (s) -> (c) = @{
@c = make_object (@s, OBJ_TEXT_INCL);
@};
: (s) -> (c) = @{
@c = make_object (@s, OBJ_TEXT_INCL);
@};
: (s) -> (c) = @{
@c = make_object (@s, OBJ_TEXT_SRC);
@};
: (id, p, def) -> (c) = @{
char *def;
object *p = make_exp (@id.iname, @id.ivers, OBJ_DEFINE);
if (@p) {
if (*@p) {
def = string_printf ("(%s) %s", @p, @def);
} else {
def = string_printf ("() %s", @def);
}
} else {
def = string_printf (" %s", @def);
}
p->u.u_str = def;
@c = make_token (@id.ename, @id.evers, p, OBJ_EXTERN);
@};
: (tag, id, e) -> (c) = @{
type *t = make_type (@id.iname, @id.ivers, @tag);
t->v.obj2 = @e;
@c = make_token (@id.ename, @id.evers, t->u.obj, OBJ_TYPE);
@};
: (id, s) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, OBJ_ENUMVAL);
p->u.u_str = @s;
@c = make_token (@id.ename, @id.evers, p, OBJ_EXTERN);
@};
: (cmd, id, t) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, @cmd);
p->u.u_type = check_type (@t, @cmd);
@c = make_token (@id.ename, @id.evers, p, @cmd);
@};
: (id, m, t) -> (c) = @{
type *t = check_type (@t, OBJ_FIELD);
field *f = make_field (@id.iname, @id.ivers, @m, t);
@c = make_token (@id.ename, @id.evers, f->obj, OBJ_FIELD);
@};
: (cmd, id, t) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, @cmd);
p->u.u_type = check_type (@t, OBJ_FUNC);
@c = make_token (@id.ename, @id.evers, p, @cmd);
@};
: (id, t) -> (c) = @{
object *p;
int cmd = OBJ_MACRO;
if (@t->id != TYPE_PROC) cmd = OBJ_EXP;
p = make_exp (@id.iname, @id.ivers, cmd);
p->u.u_type = check_type (@t, cmd);
@c = make_token (@id.ename, @id.evers, p, cmd);
@};
: (id) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, OBJ_NAT);
@c = make_token (@id.ename, @id.evers, p, OBJ_NAT);
@};
: (id, t) -> (c) = @{
type *t = make_type (@id.iname, @id.ivers, TYPE_PROMOTE);
type *s = expand_type (@t);
switch (s->id) {
case TYPE_INT :
case TYPE_SIGNED :
case TYPE_UNSIGNED : {
break;
}
default : {
MSG_non_integral_promotion_type ();
break;
}
}
t->v.next = s;
@c = make_token (@id.ename, @id.evers, t->u.obj, OBJ_EXTERN);
@};
: (id, t) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, OBJ_STATEMENT);
p->u.u_type = check_type (@t, OBJ_STATEMENT);
@c = make_token (@id.ename, @id.evers, p, OBJ_STATEMENT);
@};
: (id, s) -> (c) = @{
object *p = make_exp (@id.iname, @id.ivers, OBJ_TOKEN);
p->u.u_str = @s;
@c = make_token (@id.ename, @id.evers, p, OBJ_TOKEN);
@};
: (tag, id) -> (c) = @{
type *t = make_type (@id.iname, @id.ivers, @tag);
@c = make_token (@id.ename, @id.evers, t->u.obj, OBJ_TYPE);
@};
: (id, t) -> (c) = @{
type *t = make_type (@id.iname, @id.ivers, TYPE_DEFINED);
t->v.next = check_type (@t, OBJ_TYPE);
@c = make_token (@id.ename, @id.evers, t->u.obj, OBJ_EXTERN);
@};
/*
* FIELD SPECIFICATION COMMANDS
*
* These actions describe the member specification constructs.
*/
: (id, tag) -> (t, c) = @{
@t = find_type (@id.iname, any_version, @tag, 0);
if (@t == null) {
@t = make_type (@id.iname, @id.ivers, @tag);
@c = make_token (@id.ename, @id.evers, @t->u.obj, OBJ_TYPE);
} else {
@c = null;
}
@t = expand_type (@t);
switch (@t->id) {
case TYPE_STRUCT :
case TYPE_UNION :
case TYPE_STRUCT_TAG :
case TYPE_UNION_TAG : {
break;
}
default : {
MSG_illegal_field_type (@id.iname);
break;
}
}
crt_field_name = @t->u.obj->name;
@};
: (t, a, b, e) -> (c) = @{
if (@e) {
if (@t->v.obj2) {
char *nm = crt_field_name;
MSG_redefinition_of_type (nm);
}
if (@b == null) {
MSG_empty_struct_union_definition ();
} else {
@t->v.obj2 = @b;
}
if (@a == null) {
/* This is a hack, do properly later */
@c = make_object (NULL, OBJ_TYPE);
@c->u.u_type = @t;
if (streq (@c->filename, @t->u.obj->filename)) {
@t->state = 1;
} else {
@t->state = 3;
}
} else {
@c = @a;
}
} else {
@c = join_object (@a, @b);
}
crt_field_name = null;
@};
/*
* CONDITIONAL COMPILATION COMMANDS
*
* These actions describe the conditional compilation constructs.
*/
: (s) -> (c) = @{
@c = make_object (@s, OBJ_IF);
@c->u.u_num = CMD_IF;
@};
: (s) -> (c) = @{
@c = make_object (@s, OBJ_IF);
@c->u.u_num = CMD_IFDEF;
@};
: (s) -> (c) = @{
@c = make_object (@s, OBJ_IF);
@c->u.u_num = CMD_IFNDEF;
@};
: (i, s, a, b) -> (c) = @{
object *p, *q;
p = join_object (@i, @a);
if (@b) {
q = make_object (@s, OBJ_IF);
q->u.u_num = CMD_ELSE;
p = join_object (p, q);
p = join_object (p, @b);
}
q = make_object (@s, OBJ_IF);
q->u.u_num = CMD_ENDIF;
@c = join_object (p, q);
@};
/*
* SYNTAX ERROR
*
* This action describes the error message which is printed if a parse
* error occurs.
*/
: () -> () = @{
MSG_syntax_error ();
@};
%trailer% @{
@}, @{
#endif
@};