summaryrefslogtreecommitdiff
path: root/src/rtt/rttsym.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtt/rttsym.c')
-rw-r--r--src/rtt/rttsym.c722
1 files changed, 722 insertions, 0 deletions
diff --git a/src/rtt/rttsym.c b/src/rtt/rttsym.c
new file mode 100644
index 0000000..9e1901b
--- /dev/null
+++ b/src/rtt/rttsym.c
@@ -0,0 +1,722 @@
+/*
+ * rttsym.c contains symbol table routines.
+ */
+#include "rtt.h"
+
+#define HashSize 149
+
+/*
+ * Prototype for static function.
+ */
+static void add_def (struct node *dcltor);
+static void add_s_prm (struct token *ident, int param_num, int flags);
+static void dcl_typ (struct node *dcl);
+static void dcltor_typ (struct node *dcltor, struct node *tqual);
+
+word lbl_num = 0; /* next unused label number */
+struct lvl_entry *dcl_stk; /* stack of declaration contexts */
+
+char *str_rslt; /* string "result" in string table */
+struct init_tend *tend_lst = NULL; /* list of tended descriptors */
+struct sym_entry *decl_lst = NULL; /* declarations from "declare {...}" */
+struct sym_entry *v_len = NULL; /* entry for length of varargs */
+int il_indx = 0; /* data base symbol table index */
+
+static struct sym_entry *sym_tbl[HashSize]; /* symbol table */
+
+/*
+ * The following strings are put in the string table and used for
+ * recognizing valid tended declarations.
+ */
+static char *block = "block";
+static char *descrip = "descrip";
+
+/*
+ * init_sym - initialize symbol table.
+ */
+void init_sym()
+ {
+ static int first_time = 1;
+ int hash_val;
+ register struct sym_entry *sym;
+ int i;
+
+ /*
+ * Initialize the symbol table and declaration stack. When called for
+ * the first time, put strings in string table.
+ */
+ if (first_time) {
+ first_time = 0;
+ for (i = 0; i < HashSize; ++i)
+ sym_tbl[i] = NULL;
+ dcl_stk = NewStruct(lvl_entry);
+ dcl_stk->nest_lvl = 1;
+ dcl_stk->next = NULL;
+ block = spec_str(block);
+ descrip = spec_str(descrip);
+ }
+ else {
+ for (hash_val = 0; hash_val < HashSize; ++ hash_val) {
+ for (sym = sym_tbl[hash_val]; sym != NULL &&
+ sym->nest_lvl > 0; sym = sym_tbl[hash_val]) {
+ sym_tbl[hash_val] = sym->next;
+ free((char *)sym);
+ }
+ }
+ }
+ dcl_stk->kind_dcl = OtherDcl;
+ dcl_stk->parms_done = 0;
+ }
+
+/*
+ * sym_lkup - look up a string in the symbol table. Return NULL If it is not
+ * there.
+ */
+struct sym_entry *sym_lkup(image)
+char *image;
+ {
+ register struct sym_entry *sym;
+
+ for (sym = sym_tbl[(unsigned int)(unsigned long)image % HashSize];
+ sym != NULL;
+ sym = sym->next)
+ if (sym->image == image)
+ return sym;
+ return NULL;
+ }
+
+/*
+ * sym_add - add a symbol to the symbol table. For some types of entries
+ * it is illegal to redefine them. In that case, NULL is returned otherwise
+ * the entry is returned.
+ */
+struct sym_entry *sym_add(tok_id, image, id_type, nest_lvl)
+int tok_id;
+char *image;
+int id_type;
+int nest_lvl;
+ {
+ register struct sym_entry **symp;
+ register struct sym_entry *sym;
+
+ symp = &sym_tbl[(unsigned int)(unsigned long)image % HashSize];
+ while (*symp != NULL && (*symp)->nest_lvl > nest_lvl)
+ symp = &((*symp)->next);
+ while (*symp != NULL && (*symp)->nest_lvl == nest_lvl) {
+ if ((*symp)->image == image) {
+ /*
+ * Redeclaration:
+ *
+ * An explicit typedef may be given for a built-in typedef
+ * name. A label appears in multiply gotos and as a label
+ * on a statement. Assume a global redeclaration is for an
+ * extern. Return the entry for these situations but don't
+ * try too hard to detect errors. If actual errors are not
+ * caught here, the C compiler will find them.
+ */
+ if (tok_id == TypeDefName && ((*symp)->tok_id == C_Integer ||
+ (*symp)->tok_id == TypeDefName))
+ return *symp;
+ if (id_type == Label && (*symp)->id_type == Label)
+ return *symp;
+ if ((*symp)->nest_lvl == 1)
+ return *symp;
+ return NULL; /* illegal redeclarations */
+ }
+ symp = &((*symp)->next);
+ }
+
+ /*
+ * No entry exists for the symbol, create one, fill in its fields, and add
+ * it to the table.
+ */
+ sym = NewStruct(sym_entry);
+ sym->tok_id = tok_id;
+ sym->image = image;
+ sym->id_type = id_type;
+ sym->nest_lvl = nest_lvl;
+ sym->ref_cnt = 1;
+ sym->il_indx = -1;
+ sym->may_mod = 0;
+ if (id_type == Label)
+ sym->u.lbl_num = lbl_num++;
+ sym->next = *symp;
+ *symp = sym;
+
+ return sym; /* success */
+ }
+
+/*
+ * lbl - make sure the label is in the symbol table and return a node
+ * referencing the symbol table entry.
+ */
+struct node *lbl(t)
+struct token *t;
+ {
+ struct sym_entry *sym;
+ struct node *n;
+
+ sym = sym_add(Identifier, t->image, Label, 2);
+ if (sym == NULL)
+ errt2(t, "conflicting definitions for ", t->image);
+ n = sym_node(t);
+ if (n->u[0].sym != sym)
+ errt2(t, "conflicting definitions for ", t->image);
+ return n;
+ }
+
+/*
+ * push_cntxt - push a level of declaration context (this may or may not
+ * be level of declaration nesting).
+ */
+void push_cntxt(lvl_incr)
+int lvl_incr;
+ {
+ struct lvl_entry *entry;
+
+ entry = NewStruct(lvl_entry);
+ entry->nest_lvl = dcl_stk->nest_lvl + lvl_incr;
+ entry->kind_dcl = OtherDcl;
+ entry->parms_done = 0;
+ entry->tended = NULL;
+ entry->next = dcl_stk;
+ dcl_stk = entry;
+ }
+
+/*
+ * pop_cntxt - end a level of declaration context
+ */
+void pop_cntxt()
+ {
+ int hash_val;
+ int old_lvl;
+ int new_lvl;
+ register struct sym_entry *sym;
+ struct lvl_entry *entry;
+
+ /*
+ * Move the top entry of the stack to the free list.
+ */
+ old_lvl = dcl_stk->nest_lvl;
+ entry = dcl_stk;
+ dcl_stk = dcl_stk->next;
+ free((char *)entry);
+
+ /*
+ * If this pop reduced the declaration nesting level, remove obsolete
+ * entries from the symbol table.
+ */
+ new_lvl = dcl_stk->nest_lvl;
+ if (old_lvl > new_lvl) {
+ for (hash_val = 0; hash_val < HashSize; ++ hash_val) {
+ for (sym = sym_tbl[hash_val]; sym != NULL &&
+ sym->nest_lvl > new_lvl; sym = sym_tbl[hash_val]) {
+ sym_tbl[hash_val] = sym->next;
+ free_sym(sym);
+ }
+ }
+ unuse(tend_lst, old_lvl);
+ }
+ }
+
+/*
+ * unuse - mark tended slots in at the given level of declarations nesting
+ * as being no longer in use, and leave the slots available for reuse
+ * for declarations that occur in pararallel compound statements.
+ */
+void unuse(t_lst, lvl)
+struct init_tend *t_lst;
+int lvl;
+ {
+ while (t_lst != NULL) {
+ if (t_lst->nest_lvl >= lvl)
+ t_lst->in_use = 0;
+ t_lst = t_lst->next;
+ }
+ }
+
+/*
+ * free_sym - remove a reference to a symbol table entry and free storage
+ * related to it if no references remain.
+ */
+void free_sym(sym)
+struct sym_entry *sym;
+ {
+ if (--sym->ref_cnt <= 0) {
+ switch (sym->id_type) {
+ case TndDesc:
+ case TndStr:
+ case TndBlk:
+ free_tree(sym->u.tnd_var.init); /* initializer expression */
+ }
+ free((char *)sym);
+ }
+ }
+
+/*
+ * alloc_tnd - allocated a slot in a tended array for a variable and return
+ * its index.
+ */
+int alloc_tnd(typ, init, lvl)
+int typ;
+struct node *init;
+int lvl;
+ {
+ register struct init_tend *tnd;
+
+ if (lvl > 2) {
+ /*
+ * This declaration occurs in an inner compound statement. There
+ * may be slots created for parallel compound statement, but were
+ * freed and can be reused here.
+ */
+ tnd = tend_lst;
+ while (tnd != NULL && (tnd->in_use || tnd->init_typ != typ))
+ tnd = tnd->next;
+ if (tnd != NULL) {
+ tnd->in_use = 1;
+ tnd->nest_lvl = lvl;
+ return tnd->t_indx;
+ }
+ }
+
+ /*
+ * Allocate a new tended slot, compute its index in the array, and
+ * set initialization and other information.
+ */
+ tnd = NewStruct(init_tend);
+
+ if (tend_lst == NULL)
+ tnd->t_indx = 0;
+ else
+ tnd->t_indx = tend_lst->t_indx + 1;
+ tnd->init_typ = typ;
+ /*
+ * The initialization from the declaration will only be used to
+ * set up the tended location if the declaration is in the outermost
+ * "block". Otherwise a generic initialization will be done during
+ * the set up and the one from the declaration will be put off until
+ * the block is entered.
+ */
+ if (lvl == 2)
+ tnd->init = init;
+ else
+ tnd->init = NULL;
+ tnd->in_use = 1;
+ tnd->nest_lvl = lvl;
+ tnd->next = tend_lst;
+ tend_lst = tnd;
+ return tnd->t_indx;
+ }
+
+/*
+ * free_tend - put the list of tended descriptors on the free list.
+ */
+void free_tend()
+ {
+ register struct init_tend *tnd, *tnd1;
+
+ for (tnd = tend_lst; tnd != NULL; tnd = tnd1) {
+ tnd1 = tnd->next;
+ free((char *)tnd);
+ }
+ tend_lst = NULL;
+ }
+
+/*
+ * dst_alloc - the conversion of a parameter is encountered during
+ * parsing; make sure a place is allocated to act as the destination.
+ */
+void dst_alloc(cnv_typ, var)
+struct node *cnv_typ;
+struct node *var;
+ {
+ struct sym_entry *sym;
+
+ if (var->nd_id == SymNd) {
+ sym = var->u[0].sym;
+ if (sym->id_type & DrfPrm) {
+ switch (cnv_typ->tok->tok_id) {
+ case C_Integer:
+ sym->u.param_info.non_tend |= PrmInt;
+ break;
+ case C_Double:
+ sym->u.param_info.non_tend |= PrmDbl;
+ break;
+ }
+ }
+ }
+ }
+
+/*
+ * strt_def - the start of an operation definition is encountered during
+ * parsing; establish an new declaration context and make "result"
+ * a special identifier.
+ */
+void strt_def()
+ {
+ struct sym_entry *sym;
+
+ push_cntxt(1);
+ sym = sym_add(Identifier, str_rslt, RsltLoc, dcl_stk->nest_lvl);
+ sym->u.referenced = 0;
+ }
+
+/*
+ * add_def - update the symbol table for the given declarator.
+ */
+static void add_def(dcltor)
+struct node *dcltor;
+ {
+ struct sym_entry *sym;
+ struct token *t;
+ int tok_id;
+
+ /*
+ * find the identifier within the declarator.
+ */
+ for (;;) {
+ switch (dcltor->nd_id) {
+ case BinryNd:
+ /* ')' or '[' */
+ dcltor = dcltor->u[0].child;
+ break;
+ case ConCatNd:
+ /* pointer direct-declarator */
+ dcltor = dcltor->u[1].child;
+ break;
+ case PrefxNd:
+ /* ( ... ) */
+ dcltor = dcltor->u[0].child;
+ break;
+ case PrimryNd:
+ t = dcltor->tok;
+ if (t->tok_id == Identifier || t->tok_id == TypeDefName) {
+ /*
+ * We have found the identifier, add an entry to the
+ * symbol table based on information in the declaration
+ * context.
+ */
+ if (dcl_stk->kind_dcl == IsTypedef)
+ tok_id = TypeDefName;
+ else
+ tok_id = Identifier;
+ sym = sym_add(tok_id, t->image, OtherDcl, dcl_stk->nest_lvl);
+ if (sym == NULL)
+ errt2(t, "redefinition of ", t->image);
+ }
+ return;
+ default:
+ return;
+ }
+ }
+ }
+
+/*
+ * id_def - a declarator has been parsed. Determine what to do with it
+ * based on information put in the declaration context while parsing
+ * the "storage class type qualifier list".
+ */
+void id_def(dcltor, init)
+struct node *dcltor;
+struct node *init;
+ {
+ struct node *chld0, *chld1;
+ struct sym_entry *sym;
+
+ if (dcl_stk->parms_done)
+ pop_cntxt();
+
+ /*
+ * Look in the declaration context (the top of the declaration stack)
+ * to see if this is a tended declaration.
+ */
+ switch (dcl_stk->kind_dcl) {
+ case TndDesc:
+ case TndStr:
+ case TndBlk:
+ /*
+ * Tended variables are either simple identifiers or pointers to
+ * simple identifiers.
+ */
+ chld0 = dcltor->u[0].child;
+ chld1 = dcltor->u[1].child;
+ if (chld1->nd_id != PrimryNd || (chld1->tok->tok_id != Identifier &&
+ chld1->tok->tok_id != TypeDefName))
+ errt1(chld1->tok, "unsupported tended declaration");
+ if (dcl_stk->kind_dcl == TndDesc) {
+ /*
+ * Declared as full tended descriptor - must not be a pointer.
+ */
+ if (chld0 != NULL)
+ errt1(chld1->tok, "unsupported tended declaration");
+ }
+ else {
+ /*
+ * Must be a tended pointer.
+ */
+ if (chld0 == NULL || chld0->nd_id != PrimryNd)
+ errt1(chld1->tok, "unsupported tended declaration");
+ }
+
+ /*
+ * This is a legal tended declaration, make a symbol table entry
+ * for it and allocated a tended slot. Add the symbol table
+ * entry to the list of tended variables in this context.
+ */
+ sym = sym_add(Identifier, chld1->tok->image, dcl_stk->kind_dcl,
+ dcl_stk->nest_lvl);
+ if (sym == NULL)
+ errt2(chld1->tok, "redefinition of ", chld1->tok->image);
+ sym->u.tnd_var.blk_name = dcl_stk->blk_name;
+ sym->u.tnd_var.init = init;
+ sym->t_indx = alloc_tnd(dcl_stk->kind_dcl, init, dcl_stk->nest_lvl);
+ sym->u.tnd_var.next = dcl_stk->tended;
+ dcl_stk->tended = sym;
+ ++sym->ref_cnt;
+ return;
+ default:
+ add_def(dcltor); /* ordinary declaration */
+ }
+ }
+
+/*
+ * func_def - a function header has been parsed. Add the identifier for
+ * the function to the symbol table.
+ */
+void func_def(head)
+struct node *head;
+ {
+ /*
+ * If this is really a function header, the current declaration
+ * context indicates that a parameter list has been completed.
+ * Parameter lists at other than at nesting level 2 are part of
+ * nested declaration information and do not show up here. The
+ * function parameters must remain in the symbol table, so the
+ * context is just updated, not popped.
+ */
+ if (!dcl_stk->parms_done)
+ yyerror("invalid declaration");
+ dcl_stk->parms_done = 0;
+ if (dcl_stk->next->kind_dcl == IsTypedef)
+ yyerror("a typedef may not be a function definition");
+ add_def(head->u[1].child);
+ }
+
+/*
+ * s_prm_def - add symbol table entries for a parameter to an operation.
+ * Undereferenced and/or dereferenced versions of the parameter may be
+ * specified.
+ */
+void s_prm_def(u_ident, d_ident)
+struct token *u_ident;
+struct token *d_ident;
+ {
+ int param_num;
+
+ if (params == NULL)
+ param_num = 0;
+ else
+ param_num = params->u.param_info.param_num + 1;
+ if (u_ident != NULL)
+ add_s_prm(u_ident, param_num, RtParm);
+ if (d_ident != NULL)
+ add_s_prm(d_ident, param_num, DrfPrm);
+ }
+
+/*
+ * add_s_prm - add a symbol table entry for either a dereferenced or
+ * undereferenced version of a parameter. Put it on the current
+ * list of parameters.
+ */
+static void add_s_prm(ident, param_num, flags)
+struct token *ident;
+int param_num;
+int flags;
+ {
+ struct sym_entry *sym;
+
+ sym = sym_add(Identifier, ident->image, flags, dcl_stk->nest_lvl);
+ if (sym == NULL)
+ errt2(ident, "redefinition of ", ident->image);
+ sym->u.param_info.param_num = param_num;
+ sym->u.param_info.non_tend = 0;
+ sym->u.param_info.cur_loc = PrmTend;
+ sym->u.param_info.parm_mod = 0;
+ sym->u.param_info.next = params;
+ sym->il_indx = il_indx++;
+ params = sym;
+ ++sym->ref_cnt;
+ }
+
+/*
+ * var_args - a variable length parameter list for an operation is parsed.
+ */
+void var_args(ident)
+struct token *ident;
+ {
+ struct sym_entry *sym;
+
+ /*
+ * The last parameter processed represents the variable part of the list;
+ * update the symbol table entry. It may be dereferenced or undereferenced
+ * but not both.
+ */
+ sym = params->u.param_info.next;
+ if (sym != NULL && sym->u.param_info.param_num ==
+ params->u.param_info.param_num)
+ errt1(ident, "only one version of variable parameter list allowed");
+ params->id_type |= VarPrm;
+
+ /*
+ * Add the identifier for the length of the variable part of the list
+ * to the symbol table.
+ */
+ sym = sym_add(Identifier, ident->image, VArgLen, dcl_stk->nest_lvl);
+ if (sym == NULL)
+ errt2(ident, "redefinition of ", ident->image);
+ sym->il_indx = il_indx++;
+ v_len = sym;
+ ++v_len->ref_cnt;
+ }
+
+/*
+ * d_lst_typ - the end of a "declare {...}" is encountered. Go through a
+ * declaration list adding storage class, type qualifier, declarator
+ * and initializer information to the symbol table entry for each
+ * identifier. Add the entry onto the list associated with the "declare"
+ */
+void d_lst_typ(dcls)
+struct node *dcls;
+ {
+ if (dcls == NULL)
+ return;
+ for ( ; dcls != NULL && dcls->nd_id == LstNd; dcls = dcls->u[0].child)
+ dcl_typ(dcls->u[1].child);
+ dcl_typ(dcls);
+ }
+
+/*
+ * dcl_typ - go through the declarators of a declaration adding the storage
+ * class, type qualifier, declarator, and initializer information to the
+ * symbol table entry of each identifier. Add the entry onto the list
+ * associated with the current "declare {...}".
+ */
+static void dcl_typ(dcl)
+struct node *dcl;
+ {
+ struct node *tqual;
+ struct node *dcltors;
+
+ if (dcl == NULL)
+ return;
+ tqual = dcl->u[0].child;
+ for (dcltors = dcl->u[1].child; dcltors->nd_id == CommaNd;
+ dcltors = dcltors->u[0].child)
+ dcltor_typ(dcltors->u[1].child, tqual);
+ dcltor_typ(dcltors, tqual);
+ }
+
+/*
+ * dcltor_typ- find the identifier in the [initialized] declarator and add
+ * the storage class, type qualifer, declarator, and initialization
+ * information to its symbol table entry. Add the entry onto the list
+ * associated with the current "declare {...}".
+ */
+static void dcltor_typ(dcltor, tqual)
+struct node *dcltor;
+struct node *tqual;
+ {
+ struct sym_entry *sym;
+ struct node *part_dcltor;
+ struct node *init = NULL;
+ struct token *t;
+
+ if (dcltor->nd_id == BinryNd && dcltor->tok->tok_id == '=') {
+ init = dcltor->u[1].child;
+ dcltor = dcltor->u[0].child;
+ }
+ part_dcltor = dcltor;
+ for (;;) {
+ switch (part_dcltor->nd_id) {
+ case BinryNd:
+ /* ')' or '[' */
+ part_dcltor = part_dcltor->u[0].child;
+ break;
+ case ConCatNd:
+ /* pointer direct-declarator */
+ part_dcltor = part_dcltor->u[1].child;
+ break;
+ case PrefxNd:
+ /* ( ... ) */
+ part_dcltor = part_dcltor->u[0].child;
+ break;
+ case PrimryNd:
+ t = part_dcltor->tok;
+ if (t->tok_id == Identifier || t->tok_id == TypeDefName) {
+ /*
+ * The identifier has been found, update its symbol table
+ * entry.
+ */
+ sym = sym_lkup(t->image);
+ sym->u.declare_var.tqual = tqual;
+ sym->u.declare_var.dcltor = dcltor;
+ sym->u.declare_var.init = init;
+ ++sym->ref_cnt;
+ sym->u.declare_var.next = decl_lst;
+ decl_lst = sym;
+ }
+ return;
+ default:
+ return;
+ }
+ }
+ }
+
+/*
+ * tnd_char - indicate in the current declaration context that a tended
+ * character (pointer?) declaration has been found.
+ */
+void tnd_char()
+ {
+ dcl_stk->kind_dcl = TndStr;
+ dcl_stk->blk_name = NULL;
+ }
+
+/*
+ * tnd_strct - indicate in the current declaration context that a tended
+ * struct declaration has been found and indicate the struct type.
+ */
+void tnd_strct(t)
+struct token *t;
+ {
+ char *strct_nm;
+
+ strct_nm = t->image;
+ free_t(t);
+
+ if (strct_nm == descrip) {
+ dcl_stk->kind_dcl = TndDesc;
+ dcl_stk->blk_name = NULL;
+ return;
+ }
+ dcl_stk->kind_dcl = TndBlk;
+ dcl_stk->blk_name = strct_nm;
+ }
+
+/*
+ * tnd_strct - indicate in the current declaration context that a tended
+ * union (pointer?) declaration has been found.
+ */
+void tnd_union(t)
+struct token *t;
+ {
+ /*
+ * Only union block pointers may be tended.
+ */
+ if (t->image != block)
+ yyerror("unsupported tended type");
+ free_t(t);
+ dcl_stk->kind_dcl = TndBlk;
+ dcl_stk->blk_name = NULL;
+ }