/******** * Debugging functions. */ #include #include #include "std-macros.h" #include "clist.h" #include "parse-tree.h" #include "tokens.h" #include "sym.h" #include "sym-aux.h" #include "translator.h" #include "debug.h" #include "token-mapping.h" /* * Set a breakpoint at the given line in the given scope */ ValueStruct stopat_(/*scope, line, */ t) nodep t; /* For error messaging */ { char *scope; int line; SymtabEntry *sym; Symtab *symt; nodep codep, stmt; int l, fline; /* * Extract actuals. */ InitGetTos(); GetStackPointer(&scope); GetStackInt(&line); /* * Disallow line numbers < 1. This could happen at typechk time, but we * have a general problem in this regard, since we cant have a non-special * compiled proc cleanly have a special typechk function. Maybe we'll * work this out someday. */ if (line < 1) { lerror(t, "Non-positive line numbers are senseless.\n"); return; } /* * Look up the scope in callING envir and complain if not defined. */ PopSymtab(); if (not (sym = LookupString(scope))) { lerror(t, "Scope %s is not defined.\n", *scope); PushSymtab(); return; } PushSymtab(); switch (sym->Class) { case C_Module: symt = sym->Info.Proc.Symtab; codep = sym->Info.Module.Code.Tree; break; case C_Proc: symt = sym->Info.Module.Symtab; codep = sym->Info.Proc.Code.Tree; break; default: lerror(t, "Breakpoints can only be set in procedures or modules.\n"); return; } /* * Find the tree node of the given line, relative to the first line of the * scope. */ if (not codep) { lerror(t, "Scope %s has no executable lines.\n", scope); return; } if (not (stmt = FindLine(line + codep->header.loc.line - 1, codep))) { lerror(t, "Cannot set breakpoint at line %d of scope %s.\n", line, scope); return; } /* * Set the breakpoint flag in the found node. Also record for future list * or delete. */ SetNodeFlag(stmt, StopAt); PutList(BrkptList, NewBrkItem(line, *scope, stmt)); } /* * Build a new BrkptItem to record break point just set. */ BrkptItem *NewBrkItem(line, scope, stmt) int line; char *scope; nodep stmt; { BrkptItem *item = (BrkptItem *) malloc(sizeof(BrkptItem)); item->Line = line; item->ScopeName = scope; item->Node = stmt; return item; } /* * Recursively traverse a stmts tree, looking for a particular line. Note that * the given line has been normalized by adding the start line number of the * given stmt list. Given this, here's the strategy: * * (1) chk if current node has given line number, in which case return it * (2) chk if given line is between current node and next node, in which * case, recursively descend into current node * (3) move to next line * (4) quit if we run out of tree before we find the given line */ nodep FindLine(line, t) nodep t; { nodep stmt, stmt2, next; for (stmt = t; stmt; stmt = next) { if (line == stmt->header.loc.line) return stmt; next = stmt->components.stmt.next; if ((not next) or (line <= next->header.loc.line)) { switch (stmt->header.name) { case 0: break; case YASSMNT: case YIF: if (stmt2 = FindLine(line, stmt->components.stmt.kind.ifstmt.thenpart)) return stmt2; if (stmt2 = FindLine(line, stmt->components.stmt.kind.ifstmt.elsifparts)) return stmt2; if (stmt2 = FindLine(line, stmt->components.stmt.kind.ifstmt.elsepart)) return stmt2; break; /* case YELSIF: printf("ELSIF_PART:\n"); pp1(t->components.stmt.kind.elsif.expr,level+1); pp1(t->components.stmt.kind.elsif.thenpart,level+1); break; case YCASE: printf("CASE_STMT_NODE:\n"); for (i=2*level+1; i>0; printf(" "), i--); printf("EXPR:\n"); pp1(t->components.stmt.kind.casestmt.expr,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("CASES:\n"); pp1(t->components.stmt.kind.casestmt.cases,level+1); if (t->components.stmt.kind.casestmt.elsepart) { for (i=2*level+1; i>0; printf(" "), i--); printf("ELSE_PART:\n"); pp1(t->components.stmt.kind.casestmt.elsepart,level+1); } break; case YOF: printf(" CASE LABEL LIST:\n"); pp1(t->components.stmt.kind.ofpart.labellist, level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("CASE STMT SEQ:\n"); pp1(t->components.stmt.kind.ofpart.stmtseq, level+1); break; case YWHILE: printf("WHILE_STMT_NODE:\n"); for (i=2*level+1; i>0; printf(" "), i--); printf("EXPR:\n"); pp1(t->components.stmt.kind.whilestmt.expr,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("BODY:\n"); pp1(t->components.stmt.kind.whilestmt.body,level+1); break; case YREPEAT: printf("REPEAT_STMT_NODE:\n"); pp1(t->components.stmt.kind.repeatstmt.expr,level+1); pp1(t->components.stmt.kind.repeatstmt.body,level+1); break; case YLOOP: printf("LOOP_STMT_NODE:\n"); pp1(t->components.stmt.kind.loopstmt.body,level+1); break; case YFOR: printf("FOR_STMT_NODE:\n"); for (i=2*level+1; i>0; printf(" "), i--); printf("START EXPR:\n"); pp1(t->components.stmt.kind.forstmt.startexpr,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("END EXPR:\n"); pp1(t->components.stmt.kind.forstmt.endexpr,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("BY EXPR:\n"); pp1(t->components.stmt.kind.forstmt.byexpr,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("BODY:\n"); pp1(t->components.stmt.kind.forstmt.body,level+1); break; case YWITH: printf("WITH_STMT_NODE:\n"); for (i=2*level+1; i>0; printf(" "), i--); printf("EXPR:\n"); pp1(t->components.stmt.kind.withstmt.desig,level+1); for (i=2*level+1; i>0; printf(" "), i--); printf("BODY:\n"); pp1(t->components.stmt.kind.withstmt.body,level+1); break; */ } } } return null; } ValueStruct status_(t) nodep t; { BrkptItem *item; int n; if (ListLen(BrkptList) == 0) { lerror(t, "No breakpoints set.\n"); return; } printf ("No.\tLine\tScope\n=================================\n"); for (n=1; item = (BrkptItem *) EnumList(BrkptList); n++) { printf(" %d\t %d\t%s\n", n, item->Line, item->ScopeName); } } ValueStruct delete_(t) nodep t; { int num, n; BrkptItem *item; InitGetTos(); GetStackInt(&num); if (num < 1) { lerror(t, "Non-positive breakpoint numbers are senseless.\n"); return; } for (n = num, item = (BrkptItem *) EnumList(BrkptList); n and item; n--) ; if (not item) { lerror(t, "There are fewer than %d breakpoints set.\n", num); return; } DelListNth(BrkptList, num); } ValueStruct delete_int(t){} ValueStruct delete_string_int(t){} ValueStruct cont_(t) nodep t; { ContinueFlag = true; } /* * Throw all the back to the top-most-level of the interp, nuking all pending * breakpoints. */ ValueStruct reset_(t) nodep t; { longjmp(Reset, 0); } ChkBreak(t) nodep t; { SymtabEntry *sym; int curline, startline; if ChkNodeFlag(t, StopAt) { sym = CurSymtab->ParentEntry; curline = t->header.loc.line; startline = (sym->Class == C_Module) ? sym->Info.Module.Code.Tree->header.loc.line : sym->Info.Proc.Code.Tree->header.loc.line; printf("Stopped at %s, line %d.\n", sym->Symbol, curline - startline + 1); BreakLev++; PushErrorCounter(&CurSymtab->Errors); /* Subtle -- see below */ TopLevel(); PopErrorCounter(); /* Ibid. */ BreakLev--; /* * Explanation of the subtlety: During non-conversational execution, * errors are counted at the global module level, for convenient * presentation to the user. However, when we set a conversational * breakpoint, we need to count errors at the local proc level, when we * are within a breakpoint in that proc. The real problem is that the * type checker relies on the fact that the &CurSymtab->Errors is * always the current error counter, else it doesnt catch that errors * have occured during a typechk. The root of the problem is the * indirect use of ErrorCounter, and the whole SetErrorCounter * business. For now we'll leave it, but it's a certain target for * fixing. */ } } /* * One-time only debugging initialization. */ InitDebug() { BreakLev = 0; ContinueFlag = false; BrkptList = NewList(); } /* * Should be replaced with load of def module. */ InstallDebugProcs() { SymtabEntry *p, *sym; Symtab *symt; int o; /* * procedure stopat(scope: array of char; line: cardinal); */ symt = (p = InstallProc("stopat", stopat_, false, null))->Info.Proc.Symtab; o = symt->Offset = sizeof(char *); /* For open array parm */ InstallFormal(p, "line", CardType, 0, o); sym = InstallFormal(p, "scope", BuildOpenArrayType(CharType, null), 0, 0); SetSymFlag(sym, arrayParm); symt->Offset += TypeSize(CardType) + /* For card parm */ sizeof(char *); /* For display */ /* * procedure cont; */ symt = InstallProc("cont", cont_, false, null)->Info.Proc.Symtab; symt->Offset = sizeof(char *); /* * procedure reset; */ symt = InstallProc("reset", reset_, false, null)->Info.Proc.Symtab; symt->Offset = sizeof(char *); /* * procedure delete(c: integer); */ symt = (p = InstallProc("delete", delete_, false, null))-> Info.Proc.Symtab; InstallFormal(p, "num", IntType, 0, 0); symt->Offset = sizeof(int) + /* For int parm */ sizeof(char *); /* For display */ /* * procedure status; */ symt = InstallProc("status", status_, false, null)->Info.Proc.Symtab; symt->Offset = sizeof(char *); }