/* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ /* $Id$ */ /* DUMP ROUTINES */ #include "parameters.h" #ifdef DEBUG #include #include #include #include "arith.h" #include "stack.h" #include "def.h" #include "idf.h" #include "type.h" #include "proto.h" #include "struct.h" #include "field.h" #include "print.h" #include "Lpars.h" #include "label.h" #include "expr.h" /*#include "static.h"*/ #include "declar.h" /* Some routines (symbol2str, type2str, qual2str) which should have * yielded strings are written to yield a pointer to a transient piece * of memory, containing the string, since this is the only reasonable * thing to do in C. `Transient' means that the result may soon * disappear, which is generally not a problem, since normally it is * consumed immediately. Sometimes we need more than one of them, and * MAXTRANS is the maximum number we will need simultaneously. */ #define MAXTRANS 6 extern char options[]; extern struct idf *idf_hashtable[]; extern char *symbol2str(); enum sdef_kind {selector, field}; /* parameter for dumpsdefs */ static int dumplevel; /* Forward declarations */ static void dumpstack(void); static char *next_transient(void); static char *qual2str(int); static char *type2str(register struct type *); static void p1_indent(register int); static void dumpdefs(register struct def *, int); void dumpidf(register struct idf *, int); void dumptags(register struct tag *); void dumptype(register struct type *); void dumpsdefs(register struct sdef *, enum sdef_kind); static void p1_expr(int, register struct expr *); void newline(void) { register int dl = dumplevel; print("\n"); while (dl >= 2) { print("\t"); dl -= 2; } if (dl) print(" "); } void dumpidftab(char msg[], int opt) { /* Dumps the identifier table in readable form (but in arbitrary order). Unless opt & 1, macros are not dumped. Unless opt & 2, reserved identifiers are not dumped. Unless opt & 4, universal identifiers are not dumped. */ print(">>> DUMPIDF, %s (start)", msg); dumpstack(); idfappfun(dumpidf, opt); newline(); print(">>> DUMPIDF, %s (end)\n", msg); } static void dumpstack(void) { /* Dumps the identifier stack, starting at the top. */ register struct stack_level *stl = local_level; while (stl) { register struct stack_entry *se = stl->sl_entry; newline(); print("%3d: ", stl->sl_level); while (se) { print("%s ", se->se_idf->id_text); se = se->next; } stl = stl->sl_previous; } print("\n"); } void dumpidf(register struct idf *idf, int opt) { /* All information about the identifier idf is divulged in a hopefully readable format. */ int started = 0; if (!idf) return; if ((opt&2) && idf->id_reserved) { if (!started++) { newline(); print("%s:", idf->id_text); } print(" reserved: %d;", idf->id_reserved); } if (idf->id_def && ((opt&4) || idf->id_def->df_level)) { if (!started++) { newline(); print("%s:", idf->id_text); } dumpdefs(idf->id_def, opt); } if (idf->id_sdef) { if (!started++) { newline(); print("%s:", idf->id_text); } dumpsdefs(idf->id_sdef, selector); } if (idf->id_tag) { if (!started++) { newline(); print("%s:", idf->id_text); } dumptags(idf->id_tag); } } void dumpdefs(register struct def *def, int opt) { dumplevel++; while (def && ((opt&4) || def->df_level)) { newline(); print("L%d: %s %s%stype%s %lo; ", def->df_level, symbol2str(def->df_sc), def->df_initialized ? "init'd " : "", def->df_used ? "used " : "", def->df_sc == ENUM ? ", =" : " at", def->df_address ); print("%s, line %u", def->df_file ? def->df_file : "NO_FILE", def->df_line); dumptype(def->df_type); def = def->next; } dumplevel--; } void dumptags(register struct tag *tag) { dumplevel++; while (tag) { register struct type *tp = tag->tg_type; register int fund = tp->tp_fund; newline(); print("L%d: %s %s", tag->tg_level, fund == STRUCT ? "struct" : fund == UNION ? "union" : fund == ENUM ? "enum" : "", tp->tp_idf->id_text ); if (is_struct_or_union(fund)) { print(" {"); dumpsdefs(tp->tp_sdef, field); newline(); print("}"); } print(";"); tag = tag->next; } dumplevel--; } void dumpsdefs(register struct sdef *sdef, enum sdef_kind sdk) { /* Since sdef's are members of two chains, there are actually two dumpsdefs's, one following the chain of all selectors belonging to the same idf, starting at idf->id_sdef; and the other following the chain of all selectors belonging to the same struct, starting at stp->tp_sdef. */ dumplevel++; while (sdef) { newline(); print("L%d: ", sdef->sd_level); #ifndef NOBITFIELD if (sdk == selector) #endif /* NOBITFIELD */ print("selector %s at offset %lu in %s;", type2str(sdef->sd_type), sdef->sd_offset, type2str(sdef->sd_stype) ); #ifndef NOBITFIELD else print("field %s at offset %lu;", type2str(sdef->sd_type), sdef->sd_offset ); #endif /* NOBITFIELD */ sdef = (sdk == selector ? sdef->next : sdef->sd_sdef); } dumplevel--; } void dumpproto(register struct proto *pl) { register struct type *type; register int argcnt = 0; newline(); print("dump proto type list (start)"); newline(); while (pl) { print("%d: %s", argcnt++, pl->pl_flag & PL_FORMAL ? (pl->pl_flag & PL_VOID ? "void" : "formal") : (pl->pl_flag & PL_ELLIPSIS ? "ellipsis" : "unknown" )); newline(); if ( (type = pl->pl_type) ){ dumptype(type); newline(); } if (pl->pl_idf) { dumplevel++; print("idf:"); dumpidf(pl->pl_idf, 7); dumplevel--; } newline(); pl = pl->next; } print("dump proto type list (end)\n"); } void dumptype(register struct type *tp) { int ops = 1; dumplevel++; newline(); if (!tp) { print(""); newline(); dumplevel--; return; } print("(@%lx, #%ld, &%d) ", tp, (long)tp->tp_size, tp->tp_align); while (ops) { print("%s", qual2str(tp->tp_typequal)); switch (tp->tp_fund) { case POINTER: print("pointer to "); break; case ARRAY: print("array [%ld] of ", tp->tp_size); break; case FUNCTION: print("function "); if (tp->tp_proto) { print("with prototype"); dumplevel++; dumpproto(tp->tp_proto); dumplevel--; newline(); } print("yielding "); break; default: print("%s%s ", tp->tp_unsigned ? "unsigned " : "", symbol2str(tp->tp_fund)); if (tp->tp_idf) print("%s ", tp->tp_idf->id_text); #ifndef NOBITFIELD if (tp->tp_fund == FIELD && tp->tp_field) { struct field *fd = tp->tp_field; print("[s=%ld,w=%ld] of ", fd->fd_shift, fd->fd_width); } else #endif /* NOBITFIELD */ ops = 0; break; } if (ops) tp = tp->tp_up; } dumplevel--; } static char *type2str(register struct type *tp) { /* Yields a pointer to a one-line description of the type tp. */ char *buf = next_transient(); int ops = 1; buf[0] = '\0'; if (!tp) { sprint(buf, ""); return buf; } sprint(buf, "%s(@%lx, #%ld, &%d) ", buf, tp, (long)tp->tp_size, tp->tp_align); while (ops) { sprint(buf, "%s%s", buf, qual2str(tp->tp_typequal)); switch (tp->tp_fund) { case POINTER: sprint(buf, "%spointer to ", buf); break; case ARRAY: sprint(buf, "%sarray [%ld] of ", buf, tp->tp_size); break; case FUNCTION: sprint(buf, "%sfunction yielding ", buf); break; default: sprint(buf, "%s%s%s ", buf, tp->tp_unsigned ? "unsigned " : "", symbol2str(tp->tp_fund) ); if (tp->tp_idf) sprint(buf, "%s %s ", buf, tp->tp_idf->id_text); #ifndef NOBITFIELD if (tp->tp_fund == FIELD && tp->tp_field) { struct field *fd = tp->tp_field; sprint(buf, "%s [s=%ld,w=%ld] of ", buf, fd->fd_shift, fd->fd_width); } else #endif /* NOBITFIELD */ ops = 0; break; } if (ops) tp = tp->tp_up; } return buf; } static char *qual2str(int qual) { char *buf = next_transient(); *buf = '\0'; if (qual == 0) sprint(buf, "(none)"); if (qual & TQ_CONST) sprint(buf, "%sconst ", buf); if (qual & TQ_VOLATILE) sprint(buf, "%svolatile ", buf); return qual == 0 ? "" : buf; } GSTATIC char trans_buf[MAXTRANS][300]; static char * /* the ultimate transient buffer supplier */ next_transient(void) { static int bnum; if (++bnum == MAXTRANS) bnum = 0; return trans_buf[bnum]; } void print_expr(char msg[], struct expr *expr) { /* Provisional routine to print an expression preceded by a message msg. */ if (options['x']) { print("\n%s: ", msg); print("(L=line, T=type, r/lV=r/lvalue, F=flags, D=depth)\n"); p1_expr(0, expr); } } static void p1_expr(int lvl, register struct expr *expr) { p1_indent(lvl); if (!expr) { print("NILEXPR\n"); return; } print("expr: L=%u, T=%s, %cV, F=%03o, D=%d, %s: ", expr->ex_line, type2str(expr->ex_type), expr->ex_lvalue ? 'l' : 'r', expr->ex_flags & 0xFF, expr->ex_depth, expr->ex_class == Value ? "Value" : expr->ex_class == String ? "String" : expr->ex_class == Float ? "Float" : expr->ex_class == Oper ? "Oper" : expr->ex_class == Type ? "Type" : "UNKNOWN CLASS" ); switch (expr->ex_class) { struct oper *o; case Value: switch (expr->VL_CLASS) { case Const: print("(Const) "); break; case Name: print("(Name) %s + ", expr->VL_IDF->id_text); break; case Label: print("(Label) .%lu + ", expr->VL_LBL); break; default: print("(Unknown) "); break; } print("%s\n", writh2str(expr->VL_VALUE, expr->ex_type->tp_unsigned)); break; case String: { print( "\"%s\"\n", bts2str(expr->SG_VALUE, expr->SG_LEN-1, next_transient()) ); break; } case Float: { char buf[FLT_STRLEN]; flt_flt2str(&(expr->FL_ARITH), buf, FLT_STRLEN); print("%s\n", buf); break; } case Oper: o = &expr->ex_object.ex_oper; print("\n"); p1_expr(lvl+1, o->op_left); p1_indent(lvl); print("%s <%s>\n", symbol2str(o->op_oper), type2str(o->op_type) ); p1_expr(lvl+1, o->op_right); break; case Type: print("\n"); break; default: print("UNKNOWN CLASS\n"); break; } } static void p1_indent(register int lvl) { while (lvl--) print(" "); } #endif /* DEBUG */