/* * 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/tnc/node.c,v 1.8 2005/09/21 16:59:15 stefanf Exp $ */ #include "config.h" #include "fmm.h" #include "msgcat.h" #include "types.h" #include "node.h" #include "table.h" #include "tdf.h" #include "utility.h" /* * LIST OF FREE NODES * * Nodes are allocated from this list. */ static node *free_nodes = null; /* * CREATE A NEW NODE * * A new node is created and its fields cleared. */ node * new_node(void) { node *p = free_nodes; if (p == null) { int i, m = 1000; p = xalloc (sizeof (*p) * m); for (i = 0 ; i < m - 1 ; i++) { (p + i)->bro = p + (i + 1); (p + i)->son = null; } (p + (m - 1))->bro = null; (p + (m - 1))->son = null; free_nodes = p; } free_nodes = p->bro; p->cons = null; p->son = null; p->bro = null; p->shape = null; return (p); } /* * FREE A NODE * * The node p is recursively returned to the free list. */ void free_node(node *p) { while (p) { node *q = p->bro; if (p->son) free_node (p->son); p->bro = free_nodes; free_nodes = p; p = q; } return; } /* * FORM THE COMPLETION OF A NODE * * The completion of the node p is created. This consists of p itself * and the list of all local variable sorts created during the * construction of p, as recorded by the removals list. */ node * completion(node *p) { node *q = new_node (); construct *v = make_construct (SORT_completion); v->next = removals; removals = null; q->cons = v; q->son = p; return (q); } /* * AUXILIARY EQUALITY ROUTINE * * This routine checks the nodes p and q for equality modulo the * lists of local variables ap and aq (which are known to correspond). */ static boolean eq_node_aux(node *p, node *q, construct *ap, construct *aq, int args) { while (p != null && q != null) { if (p->cons != q->cons) { sortname s = p->cons->sortnum; if (s != q->cons->sortnum) return (0); switch (s) { case SORT_bytestream : case SORT_option : { /* Just check son */ break; } case SORT_tdfbool : case SORT_small_tdfint : case SORT_repeat : { /* Check value or number of repeats */ if (p->cons->encoding != q->cons->encoding) { return (0); } break; } case SORT_tdfint : case SORT_tdfstring : { /* Check value */ if (!streq (p->cons->name, q->cons->name)) { return (0); } break; } default : { /* Check lists of local variables */ boolean ok = 0; construct *xp = ap; construct *xq = aq; while (xp && !ok) { if (xp == p->cons && xq == q->cons) ok = 1; xp = xp->next; xq = xq->next; } if (!ok) return (0); break; } } } if (!eq_node_aux (p->son, q->son, ap, aq, 1)) return (0); if (!args) return (1); p = p->bro; q = q->bro; } if (p == q) return (1); return (0); } /* * CHECK TWO LISTS OF CONSTRUCTS * * The lists of local variables ap and aq are checked to have the * same length and corresponds sorts in each position. */ static boolean eq_cons_list(construct *ap, construct *aq) { while (ap != null && aq != null) { if (ap->sortnum != aq->sortnum) return (0); ap = ap->next; aq = aq->next; } if (ap == aq) return (1); return (0); } /* * FLAG : SHOULD WE CHECK EQUALITY OF NODES? * * This should be set to 1 to suppress the check in eq_node. */ BoolT dont_check = 0; /* * ARE TWO NODES EQUAL? * * The nodes p and q are checked for equality. */ boolean eq_node(node *p, node *q) { construct *ap = null; construct *aq = null; if (dont_check) return (1); if (p == q) return (1); if (p == null || q == null) return (0); if (p->cons->sortnum == SORT_completion) { ap = p->cons->next; p = p->son; } if (q->cons->sortnum == SORT_completion) { aq = q->cons->next; q = q->son; } if (!eq_cons_list (ap, aq)) return (0); return (eq_node_aux (p, q, ap, aq, 0)); } /* * LIST OF FREE CONSTRUCTS * * Constructs are allocated from this list. */ static construct *free_constructs = null; /* * CREATE A NEW CONSTRUCT * * A new construct is allocated. Its fields are not initialized. */ construct * new_construct(void) { construct *p = free_constructs; if (p == null) { int i, m = 100; p = xalloc (sizeof (*p) * m); for (i = 0 ; i < m - 1 ; i++) (p + i)->next = p + (i + 1); (p + (m - 1))->next = null; free_constructs = p; } free_constructs = p->next; p->alias = null; p->next = null; return (p); } /* * CREATE A NEW CONSTRUCT OF A GIVEN SORT * * A new construct is allocated. Its fields are initialized for a * construct of sort s. */ construct * make_construct(sortname s) { construct *p = new_construct (); p->sortnum = s; if (s >= 0) { p->encoding = (sort_count [s])++; } else { p->encoding = 0; } p->name = null; p->ename = null; p->next = null; switch (s) { case SORT_al_tag : { /* Initialize alignment tag */ al_tag_info *q = get_al_tag_info (p); q->def = null; break; } case SORT_tag : { /* Initialize tag */ tag_info *q = get_tag_info (p); q->var = 3; q->vis = 0; q->dec = null; q->def = null; break; } case SORT_token : { /* Initialize token */ tok_info *q = get_tok_info (p); q->dec = 0; q->res = SORT_unknown; q->args = null; q->sig = null; q->def = null; q->pars = null; q->depth = 0; break; } } return (p); } /* * FREE A LIST OF CONSTRUCTS * * The list of constructed pointed to by p is returned to free. */ void free_construct(construct **p) { construct *q = *p; if (q) { while (q->next) q = q->next; q->next = free_constructs; free_constructs = *p; } *p = null; return; } /* * SET THE SORT OF A TOKEN * * The token construct p is set to have result sort rs and argument * sorts args. */ void set_token_sort(construct *p, sortname rs, char *args, node *sig) { tok_info *info = get_tok_info (p); if (info->res != SORT_unknown) { boolean error = 0; if (info->res != rs) error = 1; if (args) { if (info->args == null || !streq (args, info->args)) { error = 1; } } else { if (info->args) error = 1; } if (error) { MSG_token_declared_inconsistently (p->name); } } info->res = rs; info->args = args; info->sig = sig; return; } /* * SET TAG TYPE * * The tag construct p is set to be a variable or an identity, depending * on the flag is_var. */ void set_tag_type(construct *p, int is_var) { tag_info *info = get_tag_info (p); if (info->var != 3) { if (info->var != is_var) { MSG_tag_declared_inconsistently (p->name); } } #if 0 info->var = is_var; #endif return; } /* * CREATE A COPY OF A CONSTRUCT * * This routine creates a copy of the construct p. This is used during * token expansion to ensure that tags and labels which are local to a * token definition are handled correctly. */ void copy_construct(construct *p) { sortname s = p->sortnum; construct *q = make_construct (s); if (s == SORT_tag) { tag_info *pi = get_tag_info (p); tag_info *qi = get_tag_info (q); qi->var = pi->var; qi->vis = pi->vis; } q->name = p->name; p->alias = q; (sort_removed [s])++; return; } /* * SKIP TEXT ENCLOSED IN SQUARE BRACKETS * * The decode string s is analysed and a pointer to the first ']' * which is not balanced by a '[' is returned. */ char * skip_text(char *s) { int n = 0; while (*s) { if (*s == '[') n++; if (*s == ']') { if (n == 0) return (s); n--; } s++; } MSG_FATAL_illegal_decoding_string (); return (NULL); /* not reached */ } /* * LOCAL IDENTIFIER PREFIX * * All tag, token and alignment tags with this prefix are treated as if * they were declared local. */ char *local_prefix = ""; /* * IS AN IDENTIFIER LOCAL? * * This routine checks whether the identifier name s begins with the * local identifier prefix above. */ boolean is_local_name(char *s) { char *t = local_prefix; while (*s == *t) { s++; t++; } if (*t == 0) return (1); return (0); }