/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* 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/tnc/de_capsule.c,v 1.9 2005/09/21 20:30:00 stefanf Exp $
*/
#include "config.h"
#include "fmm.h"
#include "msgcat.h"
#include "tdf_types.h"
#include "tdf_stream.h"
#include "types.h"
#include "de_types.h"
#include "de_capsule.h"
#include "de_unit.h"
#include "decode.h"
#include "file.h"
#include "names.h"
#include "node.h"
#include "table.h"
#include "tdf.h"
#include "utility.h"
/*
* FLAG : DECODE STATUS
*
* A value of 0 indicates that we are decoding the names at the start
* of the capsule, 1 that we are decoding the linkage information, and
* 2 that we are decoding a main equation body.
*/
int decode_status = -1;
/*
* FLAG : ONLY DECODE TOKEN DECLARATIONS
*
* This flag is true if we are only interested in the token
* declarations in a capsule.
*/
boolean extract_tokdecs = 0;
/*
* THE ARRAY OF ALL VARIABLE SORTS
*
* The array vars of size no_var gives all variable sorts. The
* indexes in this array of the alignment tags, tags and tokens are
* given by al_tag_var, tag_var, tok_var respectively.
*/
static unsigned long no_var;
static var_sort *vars;
long al_tag_var, tag_var, tok_var;
/*
* LIST OF UNUSED CONSTRUCTS
*
* All unused constructs in a capsule are formed into a list for
* later reuse.
*/
static construct *garbage = null;
/*
* CURRENT BINDINGS
*
* The current bindings are held in crt_binding. spare_binding, if not
* null, contains a binding suitable for reuse.
*/
binding *crt_binding;
static binding *spare_binding = null;
/*
* CREATE A NEW BINDING
*
* A new binding with space for no_var variable sorts is created and
* cleared.
*/
static binding *
new_binding(void)
{
binding *b;
unsigned long i, n = no_var;
if (n == 0) return (null);
if (spare_binding) {
b = spare_binding;
spare_binding = null;
for (i = 0 ; i < n ; i++) b [i].max_no = 0;
return (b);
}
b = xalloc (sizeof (*b) * n);
for (i = 0 ; i < n ; i++) {
b [i].max_no = 0;
b [i].sz = 0;
b [i].table = null;
}
return (b);
}
/*
* FREE A BINDING
*
* The binding b is returned to free.
*/
static void
free_binding(binding *b)
{
spare_binding = b;
return;
}
/*
* SET THE SIZE OF AN ENTRY IN A BINDING
*
* The size of the table of the vth variable sort in the binding bt
* is set to n.
*/
static void
set_binding_size(binding *bt, unsigned long v, long n)
{
binding *b;
construct **p;
long i, m = n + 10;
if (v >= no_var)
MSG_FATAL_illegal_binding_sort ();
b = bt + v;
b->max_no = n;
if (b->sz < m) {
p = xrealloc (b->table, sizeof (construct *) * m);
b->sz = m;
b->table = p;
} else {
p = b->table;
}
for (i = 0 ; i < b->sz ; i++) p [i] = null;
return;
}
/*
* COMPLETE A BINDING
*
* The unused entries in the binding b are filled in.
*/
static void
complete_binding(binding *b)
{
unsigned long v;
for (v = 0 ; v < no_var ; v++) {
unsigned long i;
binding *bv = b + v;
sortname s = vars [v].sortnum;
for (i = 0 ; i < bv->max_no ; i++) {
if (bv->table [i] == null) {
construct *p = make_construct (s);
if (extract_tokdecs) {
/* This construct is unused - free it */
(sort_count [s])--;
p->next = garbage;
garbage = p;
} else {
/* Make up an internal name */
long n = p->encoding;
char *nm = xalloc (32);
IGNORE sprintf (nm, "~~%s_%ld", vars [v].name, n);
p->name = nm;
if (add_to_var_hash (p, s))
MSG_FATAL_var_already_defined (nm);
}
bv->table [i] = p;
}
}
}
return;
}
/*
* SET AN ENTRY IN A BINDING
*
* The nth entry of the vth variable sort of the binding bt is set to
* the construct p.
*/
static void
set_binding(binding *bt, unsigned long v, unsigned long n, construct *p)
{
binding *b;
if (v >= no_var)
MSG_FATAL_illegal_binding_sort ();
b = bt + v;
if (n >= b->max_no)
MSG_FATAL_object_number_too_big (n, vars [v].name);
if (b->table [n])
MSG_FATAL_object_already_bound (n, vars [v].name);
b->table [n] = p;
return;
}
/*
* FIND AN ENTRY IN A BINDING
*
* The nth entry of the vth variable sort of the binding bt is returned.
*/
construct *
find_binding(binding *bt, unsigned long v, unsigned long n)
{
binding *b;
if (v >= no_var)
MSG_FATAL_illegal_binding_sort ();
b = bt + v;
if (n >= b->max_no)
MSG_FATAL_object_number_too_big (n, vars [v].name);
return (b->table [n]);
}
/*
* DECODE AN ALIGNED STRING
*
* An aligned string (in an external name) is decoded and returned
* as an array of characters.
*/
static char *
de_aligned_string(void)
{
TDFIDENT ts;
tdf_de_tdfident (tdfr, &ts);
if (ts.size != 8) MSG_FATAL_only_8bit_strings_allowed ();
return (ts.ints.chars);
}
/*
* FLAG INDICATING SKIP PASS
*
* This flag is true if we are in the skip pass of a set of equations
* (primarily token definitions).
*/
boolean in_skip_pass = 0;
/*
* DECODE A SET OF EQUATIONS
*
* A set of equations with decoding routine f is decoded. If f is null
* the equations are stepped over, otherwise they are decoded.
*/
typedef void (*equation_func)(void) ;
static void
de_equation(equation_func f)
{
unsigned long i, n;
binding *old_binding = null;
/* Read new bindings */
n = tdf_de_tdfintl (tdfr);
if (n) {
if (n != no_var) MSG_FATAL_number_of_local_variables_wrong ();
old_binding = crt_binding;
crt_binding = new_binding ();
for (i = 0 ; i < n ; i++) {
long sz = tdf_int ();
set_binding_size (crt_binding, i, sz);
}
n = tdf_de_tdfintl (tdfr);
if (n != no_var) MSG_FATAL_number_of_linkage_units_wrong ();
for (i = 0 ; i < n ; i++) {
long j, no_links = tdf_int ();
for (j = 0 ; j < no_links ; j++) {
unsigned long inner = tdf_de_tdfintl (tdfr);
unsigned long outer = tdf_de_tdfintl (tdfr);
construct *p = find_binding (old_binding, i, outer);
set_binding (crt_binding, i, inner, p);
}
}
complete_binding (crt_binding);
} else {
n = tdf_de_tdfintl (tdfr);
if (n) MSG_FATAL_number_of_linkage_units_wrong ();
}
/* Read the actual equation */
n = BYTESIZE * tdf_de_tdfintl (tdfr);
tdf_de_align (tdfr);
if (f == null) {
tdf_skip_bits (tdfr, n);
} else {
tdf_pos end_posn = tdf_stream_tell (tdfr) + n;
decode_status = 2;
(*f) ();
tdf_de_align (tdfr);
decode_status = 1;
if (tdf_stream_tell (tdfr) != end_posn) MSG_FATAL_unit_length_wrong ();
}
/* Restore the old bindings */
if (old_binding) {
free_binding (crt_binding);
crt_binding = old_binding;
}
return;
}
/*
* DECODE A CAPSULE
*
* An entire TDF capsule is decoded.
*/
void
de_capsule(void)
{
unsigned long i, n;
unsigned long no_eqn;
char **eqns;
/* Reset variables */
al_tag_var = -1;
tag_var = -2;
tok_var = -3;
spare_binding = null;
have_version = 0;
decode_status = 0;
/* Read magic number */
de_magic (tdf_cap_magic);
/* Read equation names */
no_eqn = tdf_de_tdfintl (tdfr);
eqns = xalloc (sizeof (char *) * no_eqn);
for (i = 0 ; i < no_eqn ; i++) eqns [i] = de_aligned_string ();
/* Read variable sort names */
no_var = tdf_de_tdfintl (tdfr);
vars = xalloc (sizeof (var_sort) * no_var);
crt_binding = new_binding ();
for (i = 0 ; i < no_var ; i++) {
char *s = de_aligned_string ();
long sz = tdf_int ();
vars [i].name = s;
if (streq (s, LINK_al_tag)) {
vars [i].sortnum = SORT_al_tag;
al_tag_var = i;
} else if (streq (s, LINK_tag)) {
vars [i].sortnum = SORT_tag;
tag_var = i;
} else if (streq (s, LINK_token)) {
vars [i].sortnum = SORT_token;
tok_var = i;
} else {
vars [i].sortnum = SORT_unknown;
}
set_binding_size (crt_binding, i, sz);
}
/* Read external names */
decode_status = 1;
n = tdf_int ();
if (n != no_var) MSG_FATAL_number_of_variable_sorts_wrong ();
for (i = 0 ; i < no_var ; i++) {
static int un = 0;
sortname si = vars [i].sortnum;
long j, no_links = tdf_int ();
boolean reject = 0;
if (extract_tokdecs && i != tok_var) reject = 1;
for (j = 0 ; j < no_links ; j++) {
construct *p, *q;
unsigned long id = tdf_de_tdfintl (tdfr);
n = de_external_bits ();
tdf_de_align (tdfr);
p = make_construct (si);
if (extract_tokdecs) {
(sort_count [ si ])--;
p->encoding = -1;
}
if (n == ENC_string_extern) {
/* Simple external name */
boolean name_ok = 1;
node *ns = de_node ("=");
if (reject) {
free_node (ns);
} else {
/* Check that name is a valid identifier */
char *nm = ns->cons->name;
if (alpha (*nm)) {
long k;
for (k = 1 ; k < ns->cons->encoding ; k++) {
char c = nm [k];
if (!alphanum (c)) name_ok = 0;
}
} else {
name_ok = 0;
}
if (name_ok) {
/* Use external name as internal name */
p->name = nm;
if (!is_local_name (nm)) {
p->ename = new_node ();
p->ename->cons = &false_cons;
}
} else {
/* Make up internal name */
p->name = xalloc (32);
IGNORE sprintf (p->name, "~~extern_%d", un++);
if (!is_local_name (nm)) {
p->ename = new_node ();
p->ename->cons = &true_cons;
p->ename->son = ns;
}
}
}
} else if (n == ENC_unique_extern) {
/* Unique external name */
node *nu = de_node ("%[=]");
if (reject) {
free_node (nu);
} else {
/* Make up internal name */
p->name = xalloc (32);
IGNORE sprintf (p->name, "~~extern_%d", un++);
p->ename = new_node ();
p->ename->cons = &true_cons;
p->ename->son = nu;
}
} else if (n == ENC_chain_extern) {
/* Chain external name */
node *nc = de_node ("=i");
if (reject) {
free_node (nc);
} else {
/* Make up internal name */
p->name = xalloc (32);
IGNORE sprintf (p->name, "~~extern_%d", un++);
p->ename = new_node ();
p->ename->cons = &true_cons;
p->ename->son = nc;
}
} else {
MSG_FATAL_illegal_EXTERN_value (n);
}
/* Add construct to tables */
if (reject) {
set_binding (crt_binding, i, id, p);
p->next = garbage;
garbage = p;
} else {
q = add_to_var_hash (p, si);
if (q) {
if (!extract_tokdecs) {
(sort_count [ si ])--;
if (q->encoding == -1) {
q->encoding = (sort_count [ si ])++;
}
}
set_binding (crt_binding, i, id, q);
p->next = garbage;
garbage = p;
} else {
set_binding (crt_binding, i, id, p);
}
}
}
}
/* Complete the bindings */
complete_binding (crt_binding);
/* Read the equations */
n = tdf_int ();
if (n != no_eqn) MSG_FATAL_number_of_equations_wrong ();
for (i = 0 ; i < no_eqn ; i++) {
char *eq = eqns [i];
long j, no_units = tdf_int ();
if (no_units) {
boolean skip_pass = 0;
equation_func f = null;
/* Find equation decoding routine */
if (extract_tokdecs) {
if (streq (eq, LINK_tokdec_props)) {
f = de_tokdec;
} else if (streq (eq, LINK_tokdef_props)) {
f = de_tokdef;
in_skip_pass = 1;
}
} else {
if (streq (eq, LINK_al_tagdef_props)) {
f = de_aldef;
} else if (streq (eq, LINK_tagdec_props)) {
f = de_tagdec;
} else if (streq (eq, LINK_tagdef_props)) {
f = de_tagdef;
} else if (streq (eq, LINK_tokdec_props)) {
f = de_tokdec;
} else if (streq (eq, LINK_tokdef_props)) {
f = de_tokdef;
skip_pass = 1;
} else if (streq (eq, LINK_version_props)) {
f = de_version;
}
}
/* Skip pass */
if (skip_pass) {
tdf_pos old_posn = tdf_stream_tell (tdfr);
in_skip_pass = 1;
for (j = 0 ; j < no_units ; j++) de_equation (f);
in_skip_pass = 0;
tdf_stream_seek (tdfr, old_posn);
}
/* Main pass */
for (j = 0 ; j < no_units ; j++) de_equation (f);
in_skip_pass = 0;
}
}
/* Free unused constructs */
free_construct (&garbage);
return;
}
/*
* NAME OF CURRENT CAPSULE
*
* The current capsule of a library is recorded to use in error messages.
*/
char *capname = null;
/*
* DECODE A TDF LIBRARY
*/
void
de_library(void)
{
tdf_pos old_posn;
long i, no_cap;
boolean old_extract = extract_tokdecs;
de_magic (tdf_lib_magic);
IGNORE tdf_int ();
no_cap = tdf_int ();
old_posn = tdf_stream_tell (tdfr);
/* First pass - extract all token declaration */
extract_tokdecs = 1;
for (i = 0 ; i < no_cap ; i++) {
tdf_pos end_posn;
long n;
decode_status = 0;
capname = de_aligned_string ();
n = BYTESIZE * tdf_int ();
tdf_de_align (tdfr);
end_posn = tdf_stream_tell (tdfr) + n;
de_capsule ();
tdf_de_align (tdfr);
if (tdf_stream_tell (tdfr) != end_posn)
MSG_FATAL_capsule_length_wrong ();
capname = null;
}
/* Second pass - if the first pass didn't do everything */
extract_tokdecs = old_extract;
if (extract_tokdecs) return;
tdf_stream_seek (tdfr, old_posn);
for (i = 0 ; i < no_cap ; i++) {
tdf_pos end_posn;
long n;
decode_status = 0;
capname = de_aligned_string ();
n = BYTESIZE * tdf_int ();
tdf_de_align (tdfr);
end_posn = tdf_stream_tell (tdfr) + n;
de_capsule ();
tdf_de_align (tdfr);
if (tdf_stream_tell (tdfr) != end_posn)
MSG_FATAL_capsule_length_wrong ();
capname = null;
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1