/* * FILE: table.c * AUTH: Michael John Radwin * * DESC: stubgen symbol table goodies * * DATE: 1996/08/14 22:04:47 * $Id: table.c,v 1.1 2003-09-21 22:46:55 ocoursiere Exp $ * * Copyright (c) 1996-1998 Michael John Radwin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "table.h" #include "util.h" #include #include #include #include static const char rcsid[] = "$Id: table.c,v 1.1 2003-09-21 22:46:55 ocoursiere Exp $"; /* global table */ static syntaxelem_t etable[NELEMS]; static int eindex; /* initializes all of the tables to default values. */ void init_tables() { memset(etable, 0, sizeof(syntaxelem_t) * NELEMS); eindex = 0; #if 0 syntaxelem_t *elt; for(elt = etable; elt < &etable[NELEMS]; elt++) { elt->name = NULL; elt->ret_type = NULL; elt->args = NULL; elt->templ = NULL; elt->parent = NULL; elt->children = NULL; elt->throw_decl = NULL; elt->const_flag = 0; elt->kind = 73; } #endif } /* recursively frees all syntaxelem_t's. */ void free_tables() { syntaxelem_t *elt; for (elt = etable; elt < &etable[NELEMS]; elt++) { if (elt->name) { free(elt->name); free(elt->ret_type); free_args(elt->args); if (elt->throw_decl) free(elt->throw_decl); if (elt->templ) free(elt->templ); } } } /* recursively frees the argument list and assoicated fields */ void free_args(arg_t *args) { arg_t *a; for (a = args; a != NULL; ) { arg_t *next_arg = a->next; free(a->type); if (a->name) free(a->name); if (a->array) free(a->array); free(a); a = next_arg; } } /* compares two arguments for equality. Returns 0 for equal, non-zero if they differ. */ int arg_cmp(arg_t *a1, arg_t *a2) { if (strcmp(a1->type, a2->type) != 0) return 1; if (a1->array) { if (a2->array) { if (strcmp(a1->array, a2->array) != 0) return 1; } else { return 1; } } else if (a2->array) { return 1; } return 0; } /* recursively compares two argument lists for equality. Returns 0 for equal, non-zero if they differ. */ int args_cmp(arg_t *a1, arg_t *a2) { while (a1 != NULL) { if (a2 == NULL) return 1; if (arg_cmp(a1, a2) != 0) return 1; a1 = a1->next; a2 = a2->next; } if (a2 != NULL) return 1; return 0; } /* provides a string rep of this arglist. conses up new memory, so client is responsible for freeing it. */ char * args_to_string(arg_t *args, int indent_length) { arg_t *a; int len = 0; char *str; char *indent_str; if (indent_length <= 0) { indent_str = strdup(", "); indent_length = 2; } else { indent_length += 2; /* room for ",\n" as well */ indent_str = (char *) malloc(indent_length + 1); memset(indent_str, ' ', indent_length); indent_str[0] = ','; indent_str[1] = '\n'; indent_str[indent_length] = '\0'; } for (a = args; a != NULL; a = a->next) { len += strlen(a->type); /* we always have a type */ if (a->name) len += (1 + strlen(a->name)); /* room for ' ' and name */ if (a->array) len += strlen(a->array); if (a != args) len += indent_length; /* room for ", " */ } str = (char *) malloc(len + 1); str[0] = '\0'; for (a = args; a != NULL; a = a->next) { if (a != args) strcat(str, indent_str); strcat(str, a->type); if (a->name) { if (((a->type)[strlen(a->type)-1] != '*') && ((a->type)[strlen(a->type)-1] != '&')) strcat(str, " "); strcat(str, a->name); if (a->array) strcat(str, a->array); /* array hugs variable name */ } else { if (a->array) strcat(str, a->array); /* array hugs type name */ } } free(indent_str); return str; } /* compares a skeleton element to a header element for equality of signatures. this isn't a strict comparison, because the kind and parent fields ought to be different. returns 0 if equal, non-zero if different */ int skel_elemcmp(syntaxelem_t *skel_elem, syntaxelem_t *hdr_elem) { char *tmp_str; int result; assert(hdr_elem->kind == FUNC_KIND); assert(skel_elem->kind == SKEL_KIND); assert(hdr_elem->parent != NULL); if (skel_elem->const_flag != hdr_elem->const_flag) return 1; /* * templ and throw_decl are allowed to be NULL, * so we must not pass them onto strcmp without * a check first. */ if (skel_elem->templ != NULL) { if (hdr_elem->templ == NULL) return 1; else if (strcmp(skel_elem->templ, hdr_elem->templ) != 0) return 1; } else if (hdr_elem->templ != NULL) { return 1; } if (skel_elem->throw_decl != NULL) { if (hdr_elem->throw_decl == NULL) return 1; else if (strcmp(skel_elem->throw_decl, hdr_elem->throw_decl) != 0) return 1; } else if (hdr_elem->throw_decl != NULL) { return 1; } /* * these two won't differ across files, and they're * guaranteed not to be NULL. */ if (strcmp(skel_elem->ret_type, hdr_elem->ret_type) != 0) return 1; /* now make sure the argument signatures match */ if (args_cmp(skel_elem->args, hdr_elem->args) != 0) return 1; /* * the name, of course, is the hard part. we gotta * look at the parent to make a scoped name. */ tmp_str = (char *) malloc(strlen(hdr_elem->parent->name) + strlen(hdr_elem->name) + 3); sprintf(tmp_str, "%s::%s", hdr_elem->parent->name, hdr_elem->name); result = strcmp(skel_elem->name, tmp_str); free(tmp_str); return result; } /* allocates a new element from the table, filling in the apropriate fields */ syntaxelem_t * new_elem(char *ret_type, char *name, arg_t *args, int kind) { syntaxelem_t *se; if (eindex == NELEMS - 1) { fatal(2, "Too many symbols. Please mail mjr@acm.org."); return NULL; } se = &etable[eindex++]; se->ret_type = ret_type; se->name = name; se->args = args; se->kind = kind; return se; } /* given the head of the list, reverses it and returns the new head */ syntaxelem_t * reverse_list(syntaxelem_t *head) { syntaxelem_t *elt = head; syntaxelem_t *prev = NULL; syntaxelem_t *next; while (elt != NULL) { next = elt->next; elt->next = prev; prev = elt; elt = next; } return prev; } arg_t * reverse_arg_list(arg_t *head) { arg_t *a = head; arg_t *prev = NULL; arg_t *next; while (a != NULL) { next = a->next; a->next = prev; prev = a; a = next; } return prev; } const char * string_kind(int some_KIND) { switch(some_KIND) { case IGNORE_KIND: return "IGNORE_KIND"; case FUNC_KIND: return "FUNC_KIND"; case CLASS_KIND: return "CLASS_KIND"; case STRUCT_KIND: return "STRUCT_KIND"; case INLINED_KIND: return "INLINED_KIND"; case SKEL_KIND: return "SKEL_KIND"; case DONE_FUNC_KIND: return "DONE_FUNC_KIND"; case DONE_CLASS_KIND: return "DONE_CLASS_KIND"; default: return "BAD KIND!"; } } #ifdef SGDEBUG void print_se(syntaxelem_t *elt) { char *arg_str = args_to_string(elt->args, 0); log_printf("\nSTUBELEM name: %s\n", elt->name); log_printf(" ret_typ: %s\n", elt->ret_type); log_printf(" args: %s\n", arg_str); log_printf(" parent: %s\n", (elt->parent) ? elt->parent->name : "NULL"); log_printf(" next: %s\n", (elt->next) ? elt->next->name : "NULL"); log_printf(" const: %d\n", elt->const_flag); log_printf(" kind: %s\n", string_kind(elt->kind)); log_printf(" throw: %s\n", (elt->throw_decl)? elt->throw_decl : "NULL"); log_printf(" templ: %s\n\n", (elt->templ)? elt->templ : "NULL"); free(arg_str); } #endif /* SGDEBUG */ /* * we can't use the 'next' field of syntaxelem_t because it is used to * chain together methods. Make a slightly bigger struct so we can * queue these up. */ typedef struct _skelnode { syntaxelem_t *elt; struct _skelnode *next; } skelnode_t; /* the queue of elements found in the .H file, possibly to be expanded */ static skelnode_t *exp_head = NULL; static skelnode_t *exp_tail = NULL; void enqueue_class(syntaxelem_t *elt) { skelnode_t *new_class; new_class = (skelnode_t *)malloc(sizeof(skelnode_t)); new_class->elt = elt; new_class->next = NULL; if (exp_head == NULL) exp_tail = exp_head = new_class; else { exp_tail->next = new_class; exp_tail = new_class; } } syntaxelem_t * dequeue_class() { skelnode_t *old_head = exp_head; syntaxelem_t *to_return = exp_head->elt; assert(exp_head != NULL); exp_head = exp_head->next; free(old_head); return to_return; } int class_queue_empty() { return exp_head == NULL; } /* the list of skeletons found in the .C file, already expanded */ static skelnode_t *skel_head = NULL; void enqueue_skeleton(syntaxelem_t *elt) { skelnode_t *new_class; new_class = (skelnode_t *)malloc(sizeof(skelnode_t)); new_class->elt = elt; new_class->next = skel_head; skel_head = new_class; } syntaxelem_t * find_skeleton(syntaxelem_t *elt) { skelnode_t *node; /* the order of skel_elemcmp(node->elt, elt) is important. */ for (node = skel_head; node != NULL; node = node->next) if (skel_elemcmp(node->elt, elt) == 0) return node->elt; return NULL; } void clear_skeleton_queue() { skelnode_t *node = skel_head; while (node != NULL) { skelnode_t *next_node = node->next; free(node); node = next_node; } skel_head = NULL; }