home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of the portable Forth environment written in ANSI C.
- * Copyright (C) 1995 Dirk Uwe Zoller
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This file is version 0.9.13 of 17-July-95
- * Check for the latest version of this package via anonymous ftp at
- * roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
- * or sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
- * or ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
- *
- * Please direct any comments via internet to
- * duz@roxi.rz.fht-mannheim.de.
- * Thank You.
- */
- /*
- * debug.c --- analyze compiled code
- * (duz 26Aug93)
- */
-
- #include "forth.h"
- #include "support.h"
- #include "compiler.h"
- #include "term.h"
-
- #include <ctype.h>
- #include <string.h>
-
- #include "missing.h"
-
- /************************************************************************/
- /* decompiler */
- /************************************************************************/
-
- #ifdef WRONG_SPRINTF /* provision for buggy sprintf (SunOS) */
- #define SPRFIX(X) strlen(X)
- #else
- #define SPRFIX(X) X
- #endif
-
- static int debugging, level, maxlevel;
- static long opcounter;
- static short locals[10];
-
- static Xt *
- decompile_word (Xt *ip, char *p, Decomp *d)
- {
- static Decomp default_style = {SKIPS_NOTHING, 0, 0, 0, 0, 0};
- Xt xt = *ip++;
- Semant *s;
- char *nfa, buf[80];
-
- s = to_semant (xt);
- *d = s ? s->decomp : default_style;
- if (*xt == literal_execution_)
- {
- strcpy (p, str_dot (*(Cell *) ip, buf + sizeof buf, BASE));
- return ++ip;
- }
- if (*xt == locals_bar_execution_)
- {
- int i;
-
- locals[level] = *(Cell *) ip;
- p += SPRFIX (sprintf (p, "LOCALS| "));
- for (i = locals[level]; --i >= 0;)
- p += SPRFIX (sprintf (p, "<%c> ", 'A' - 1 + locals[level] - i));
- p += SPRFIX (sprintf (p, "| "));
- return ++ip;
- }
- if (*xt == to_execution_)
- {
- xt = *ip++;
- nfa = to_name (xt);
- sprintf (p, "TO %.*s ", *nfa & 0x1F, nfa + 1);
- return ip;
- }
- if (*xt == plus_to_execution_)
- {
- xt = *ip++;
- nfa = to_name (xt);
- sprintf (p, "+TO %.*s ", *nfa & 0x1F, nfa + 1);
- return ip;
- }
- if (*xt == local_execution_)
- {
- sprintf (p, "<%c> ", 'A' + 1 + locals[level] - (int) *(Cell *) ip);
- return ++ip;
- }
- if (*xt == to_local_execution_)
- {
- sprintf (p, "TO <%c> ", 'A' + 1 + locals[level] - (int) *(Cell *) ip);
- return ++ip;
- }
- if (*xt == plus_to_local_execution_)
- {
- sprintf (p, "+TO <%c> ", 'A' + 1 + locals[level] - (int) *(Cell *) ip);
- return ++ip;
- }
- if (s == NULL)
- {
- nfa = to_name (xt);
- sprintf (p, *nfa & IMMEDIATE ? "POSTPONE %.*s " : "%.*s ",
- *nfa & 0x1F, nfa + 1);
- return ip;
- }
- else
- nfa = s->name;
- switch (d->skips)
- {
- case SKIPS_CELL:
- case SKIPS_OFFSET:
- INC (ip, Cell);
-
- default:
- sprintf (p, "%.*s ", *nfa & 0x1F, nfa + 1);
- return ip;
- case SKIPS_DCELL:
- sprintf (p, "%s. ",
- str_d_dot_r (*(dCell *) ip, buf + sizeof buf, 0, BASE));
- INC (ip, dCell);
-
- return ip;
- case SKIPS_FLOAT:
- #if DFLOAT_ALIGN > CELL_ALIGN
- if (!DFALIGNED (ip))
- ip++;
- #endif
- sprintf (p, "%g ", *(double *) ip);
- INC (ip, double);
-
- return ip;
- case SKIPS_STRING:
- sprintf (p, "%.*s %.*s\" ",
- *nfa & 0x1F, nfa + 1,
- (int) *(Byte *) ip, (Byte *) ip + 1);
- SKIP_STRING;
- return ip;
- case SKIPS_2STRINGS:
- {
- Byte *s1 = (Byte *) ip;
-
- SKIP_STRING;
- sprintf (p, "%.*s %.*s %.*s ",
- *nfa & 0x1F, nfa + 1, (int) *s1, s1 + 1,
- (int) *(Byte *) ip, (Byte *) ip + 1);
- SKIP_STRING;
- return ip;
- }
- }
- }
-
- static void
- decompile_rest (Xt *ip, int nl, int indent)
- {
- char buf[0x80];
- Seman2 *s;
- Decomp d;
-
- start_question_cr_ ();
- for (;;)
- {
- s = (Seman2 *) to_semant (*ip);
- ip = decompile_word (ip, buf, &d);
- indent += d.ind_bef;
- if ((!nl && d.cr_bef) || OUT + strlen (buf) >= cols)
- {
- if (question_cr ())
- break;
- nl = 1;
- }
- if (nl)
- {
- spaces (indent);
- nl = 0;
- }
- outs (buf);
- spaces (d.space);
- indent += d.ind_aft;
- if (d.cr_aft)
- {
- if (question_cr ())
- break;
- nl = 1;
- }
- if (s == &semicolon_semantics)
- break;
- }
- }
-
- void
- decompile (char *nfa, Xt xt)
- {
- char buf[80];
-
- cr_ ();
- if (*xt == create_runtime ||
- *xt == sysvar_runtime)
- {
- outs ("VARIABLE ");
- dot_name (nfa);
- }
- else if (*xt == constant_runtime)
- {
- DOT (*TO_BODY (xt), buf);
- outs ("CONSTANT ");
- dot_name (nfa);
- }
- else if (*xt == value_runtime)
- {
- DOT (*TO_BODY (xt), buf);
- outs ("VALUE ");
- dot_name (nfa);
- }
- else if (*xt == sysconst_runtime)
- {
- DOT (**(Cell **) TO_BODY (xt), buf);
- outs ("CONSTANT ");
- dot_name (nfa);
- }
- else if (*xt == two_constant_runtime)
- {
- DDOTR (*(dCell *) TO_BODY (xt), 0, buf);
- outs (". 2CONSTANT ");
- dot_name (nfa);
- }
- else if (*xt == f_constant_runtime)
- {
- outf ("%g FCONSTANT ", *(double *) dfaligned ((Cell) TO_BODY (xt)));
- dot_name (nfa);
- }
- else if (*xt == f_variable_runtime)
- {
- outf ("%g FVARIABLE ", *(double *) dfaligned ((Cell) TO_BODY (xt)));
- dot_name (nfa);
- }
- else if (*xt == marker_runtime)
- {
- outs ("MARKER ");
- dot_name (nfa);
- }
- else if (*xt == vocabulary_runtime)
- {
- outs ("VOCABULARY ");
- dot_name (nfa);
- }
- else if (*xt == colon_runtime ||
- *xt == debug_colon_runtime)
- {
- outs (": ");
- dot_name (nfa);
- cr_ ();
- decompile_rest ((Xt *) TO_BODY (xt), 1, 4);
- }
- else if (*xt == does_defined_runtime ||
- *xt == debug_does_defined_runtime)
- {
- outs ("DOES> ");
- decompile_rest (((Xt **) xt)[-1], 0, 4);
- }
- else
- {
- dot_name (nfa);
- outf ("is primitive ");
- }
- if (*nfa & IMMEDIATE)
- outs ("IMMEDIATE ");
- }
-
- /************************************************************************/
- /* debugger */
- /************************************************************************/
-
- char
- category (pCode p)
- {
- if (p == colon_runtime || p == debug_colon_runtime)
- return ':';
- if (p == create_runtime)
- return 'V';
- if (p == constant_runtime || p == two_constant_runtime)
- return 'C';
- if (p == sysvar_runtime)
- return 'v';
- if (p == sysconst_runtime)
- return 'c';
- if (p == vocabulary_runtime)
- return 'W';
- if (p == does_defined_runtime || p == debug_does_defined_runtime)
- return 'D';
- if (p == marker_runtime)
- return 'M';
- /* must be primitive */ return 'p';
- }
-
- static void
- prompt_col (void)
- {
- spaces (24 - OUT);
- }
-
- static void
- display (Xt *ip)
- {
- Decomp style;
- char buf[80];
- int indent = maxlevel * 2;
- int depth = sys.s0 - sp, i;
-
- prompt_col ();
- for (i = 0; i < depth; i++)
- {
- outf ("%10ld ", (long) sp[i]);
- if (OUT + 11 >= cols)
- break;
- }
- cr_ ();
- decompile_word (ip, buf, &style);
- outf ("%*s%c %s", indent, "", category (**ip), buf);
- }
-
- static void
- interaction (Xt *ip)
- {
- int c;
-
- for (;;)
- {
- display (ip);
-
- prompt_col ();
- outs ("> ");
- c = getekey ();
- backspace_ ();
- backspace_ ();
- if (isalpha (c))
- c = tolower (c);
-
- switch (c)
- {
- default:
- c_bell ();
- continue;
- case EKEY_kr:
- case 'd':
- case 'l':
- maxlevel++;
- return;
- case EKEY_kd:
- case '\r':
- case '\n':
- case 'k':
- case 'x':
- return;
- case EKEY_kl:
- case 's':
- case 'j':
- maxlevel--;
- return;
- case 'q':
- outf ("\nQuit!");
- debugging = 0;
- tHrow (THROW_QUIT);
- case ' ':
- switch (category (**ip))
- {
- default:
- decompile (to_name (*ip), *ip);
- break;
- case ':':
- cr_ ();
- decompile_rest ((Xt *) TO_BODY (*ip), 1, 4);
- break;
- case 'd':
- outs ("\nDOES>");
- decompile_rest ((Xt *) (*ip)[-1], 0, 4);
- break;
- }
- cr_ ();
- continue;
- case 'r':
- opcounter = 0;
- outf ("\nOperation counter reset\n");
- continue;
- case 'c':
- outf ("\n%ld Forth operations\n", opcounter);
- continue;
- case 'h':
- case '?':
- outf ("\nDown, 'x', 'k', CR\t" "execute word"
- "\nRight, 'd', 'l'\t\t" "single step word"
- "\nLeft, 's', 'j'\t\t" "finish word w/o single stepping"
- "\nSpace\t\t\t" "SEE word to be executed"
- "\n'C'\t\t\t" "display operation counter"
- "\n'R'\t\t\t" "reset operation counter"
- "\n'Q'\t\t\t" "QUIT"
- "\n'?', 'H'\t\t" "this message"
- "\n");
- continue;
- }
- }
- }
-
- static void
- adjust_level (Xt xt)
- {
- if (*xt == colon_runtime ||
- *xt == debug_colon_runtime ||
- *xt == does_defined_runtime ||
- *xt == debug_does_defined_runtime)
- level++;
- else if (*xt == semicolon_execution_ ||
- *xt == locals_exit_execution_)
- level--;
- }
-
- static void
- debug_execute (Xt xt)
- {
- adjust_level (xt);
- normal_execute (xt);
- }
-
- static void
- debug_on (void)
- {
- debugging = 1;
- opcounter = 0;
- execute = debug_execute;
- level = maxlevel = 0;
- outf ("\nSingle stepping, type 'h' or '?' for help\n");
- }
-
- void
- debug_off (void)
- {
- debugging = 0;
- execute = normal_execute;
- }
-
- static void /* modified inner interpreter for */
- single_step (void) /* single stepping */
- {
- while (level >= 0)
- {
- if (level <= maxlevel)
- {
- maxlevel = level;
- interaction (ip);
- }
- adjust_level (*ip);
- opcounter++;
- {
- #ifdef W
- Xt w = *ip++; /* ip is register but W isn't */
-
- (*w) ();
- #else
- W = *ip++; /* ip and W are same: register or not */
- (*W) ();
- #endif
- }
- }
- }
-
- void
- debug_colon_runtime (void)
- {
- colon_runtime ();
- if (!debugging)
- {
- debug_on ();
- single_step ();
- debug_off ();
- }
- }
-
- void
- debug_does_defined_runtime (void)
- {
- does_defined_runtime ();
- if (!debugging)
- {
- debug_on ();
- single_step ();
- debug_off ();
- }
- }
-
- Code (debug)
- {
- Xt xt;
-
- tick (&xt);
- if (*xt == debug_colon_runtime ||
- *xt == debug_does_defined_runtime)
- return;
- if (*xt == colon_runtime)
- *xt = debug_colon_runtime;
- else if (*xt == does_defined_runtime)
- *xt = debug_does_defined_runtime;
- else
- tHrow (THROW_ARG_TYPE);
- }
-
- Code (no_debug)
- {
- Xt xt;
-
- tick (&xt);
- if (*xt == debug_colon_runtime)
- *xt = colon_runtime;
- else if (*xt == debug_does_defined_runtime)
- *xt = does_defined_runtime;
- else
- tHrow (THROW_ARG_TYPE);
- }
-
- LISTWORDS (debug) =
- {
- CO ("DEBUG", debug),
- CO ("NO-DEBUG", no_debug)
- };
-
- COUNTWORDS (debug, "Debugger words");
-