/* D E F I N I T I O N M E C H A N I S M */ #include "parameters.h" #include "debug.h" #include #include #include #include #include "LLlex.h" #include "def.h" #include "idf.h" #include "main.h" #include "misc.h" #include "node.h" #include "scope.h" #include "code.h" #include "type.h" #include "lookup.h" #include "error.h" struct def *MkDef(register struct idf *id, register struct scope *scope, long kind) { /* Create a new definition structure in scope "scope", with * id "id" and kind "kind". */ register struct def *df = new_def(); df->df_idf = id; df->df_scope = scope; df->df_kind = kind; df->df_type = error_type; df->df_next = id->id_def; id->id_def = df; /* enter the definition in the list of definitions in this scope */ df->df_nextinscope = scope->sc_def; scope->sc_def = df; return df; } struct def *define(register struct idf *id, register struct scope *scope, long kind) { /* Declare an identifier in a scope, but first check if it already has been defined. If so, then check for the cases in which this is legal, and otherwise give an error message. */ register struct def *df; if ( (df = lookup(id, scope, 0L)) ) { if (df->df_kind == D_INUSE) { if (kind != D_INUSE) { error("\"%s\" already used in this block", id->id_text); } return MkDef(id, scope, kind); } if (df->df_kind == D_ERROR) { /* used in forward references */ df->df_kind = kind; return df; } /* other cases fit in an int (assume at least 2 bytes) */ switch ((int) df->df_kind) { case D_LABEL: /* generate error message somewhere else */ return NULLDEF; case D_PARAMETER: if (kind == D_VARIABLE) /* program parameter declared as variable */ return df; break; case D_FORWTYPE: if (kind == D_FORWTYPE) return df; if (kind == D_TYPE) { /* forward reference resolved */ df->df_kind = D_FTYPE; return df; } else error("identifier \"%s\" must be a type", id->id_text); return NULLDEF; case D_FWPROCEDURE: if (kind == D_PROCEDURE) return df; error("procedure identification \"%s\" expected", id->id_text); return NULLDEF; case D_FWFUNCTION: if (kind == D_FUNCTION) return df; error("function identification \"%s\" expected", id->id_text); return NULLDEF; } if (kind != D_ERROR) /* avoid spurious error messages */ error("identifier \"%s\" already declared", id->id_text); return NULLDEF; } return MkDef(id, scope, kind); } void DoDirective(struct idf *directive, struct node *nd, struct type *tp, struct scopelist *scl, int function) { long kind; /* kind of directive */ int inp; /* internal or external name */ int ext = 0; /* directive = EXTERN */ struct def *df = lookup(directive, PervasiveScope, D_INUSE); if (!df) { if (!is_anon_idf(directive)) node_error(nd, "\"%s\" unknown directive", directive->id_text); return; } if (df->df_kind == D_FORWARD) { kind = function ? D_FWFUNCTION : D_FWPROCEDURE; inp = (proclevel > 1); } else if (df->df_kind == D_EXTERN) { kind = function ? D_FUNCTION : D_PROCEDURE; inp = 0; ext = 1; } else { node_error(nd, "\"%s\" unknown directive", directive->id_text); return; } if ( (df = define(nd->nd_IDF, CurrentScope, kind)) ) { if (df->df_kind != kind) { /* identifier already forward declared */ node_error(nd, "\"%s\" already forward declared", nd->nd_IDF->id_text); return; } df->df_type = tp; df->prc_vis = scl; df->prc_name = gen_proc_name(nd->nd_IDF, inp); if (ext) { if (!(df->df_flags & D_EXTERNAL) && proclevel > 1) tp->prc_nbpar -= pointer_size; /* was added for static link which is not needed now. But make sure this is done only once (look at the D_EXTERNAL flag). */ df->df_flags |= D_EXTERNAL; } df->df_flags |= D_SET; } } struct def *DeclProc(register struct node *nd, struct type *tp, register struct scopelist *scl) { register struct def *df; if ( (df = define(nd->nd_IDF, CurrentScope, D_PROCEDURE)) ) { df->df_flags |= D_SET; if (df->df_kind == D_FWPROCEDURE) { df->df_kind = D_PROCEDURE; /* identification */ /* Simulate a call to open_scope(), which has already * been performed in the forward declaration. */ CurrVis = df->prc_vis; if (tp->prc_params) node_error(nd, "\"%s\" already declared", nd->nd_IDF->id_text); } else { /* normal declaration */ df->df_type = tp; df->prc_name = gen_proc_name(nd->nd_IDF, (proclevel > 1)); /* simulate open_scope() */ CurrVis = df->prc_vis = scl; } routine_label(df); } else CurrVis = scl; /* simulate open_scope() */ return df; } struct def * DeclFunc(register struct node *nd, struct type *tp, register struct scopelist *scl) { register struct def *df; if ( (df = define(nd->nd_IDF, CurrentScope, D_FUNCTION)) ) { df->df_flags &= ~D_SET; if (df->df_kind == D_FUNCTION) { /* declaration */ if (!tp) { node_error(nd, "\"%s\" illegal function declaration", nd->nd_IDF->id_text); tp = construct_type(T_FUNCTION, error_type); } /* simulate open_scope() */ CurrVis = df->prc_vis = scl; df->df_type = tp; df->prc_name = gen_proc_name(nd->nd_IDF, (proclevel > 1)); } else { /* identification */ assert(df->df_kind == D_FWFUNCTION); df->df_kind = D_FUNCTION; CurrVis = df->prc_vis; if (tp) node_error(nd, "\"%s\" already declared", nd->nd_IDF->id_text); } routine_label(df); } else CurrVis = scl; /* simulate open_scope() */ return df; } void EndFunc(register struct def *df) { /* assignment to functionname is illegal outside the functionblock */ df->prc_res = 0; /* Give the error about assignment as soon as possible. The * |= assignment inhibits a warning in the main procedure. */ if (!(df->df_flags & D_SET)) { error("function \"%s\" not assigned", df->df_idf->id_text); df->df_flags |= D_SET; } } void EndBlock(register struct def *block_df) { register struct def *tmp_def = CurrentScope->sc_def; register struct def *df; while (tmp_def) { df = tmp_def; /* The length of a usd_def chain is at most 1. * The while is just defensive programming. */ while (df->df_kind & D_INUSE) df = df->usd_def; if (!is_anon_idf(df->df_idf) && (df->df_scope == CurrentScope)) { if (!(df->df_kind & (D_ENUM | D_LABEL | D_ERROR))) { if (!(df->df_flags & D_USED)) { if (!(df->df_flags & D_SET)) { warning("\"%s\" neither set nor used in \"%s\"", df->df_idf->id_text, block_df->df_idf->id_text); } else { warning("\"%s\" unused in \"%s\"", df->df_idf->id_text, block_df->df_idf->id_text); } } else if (!(df->df_flags & D_SET)) { if (!(df->df_flags & D_LOOPVAR)) warning("\"%s\" not set in \"%s\"", df->df_idf->id_text, block_df->df_idf->id_text); } } } tmp_def = tmp_def->df_nextinscope; } }