#include "expr.h"
extern char *Salloc();
-extern t_lineno currline;
extern FILE *db_in;
int errorgiven;
[ ',' lin_num(&t2)
| { t2 = mknode(OP_INTEGER, t1->t_ival); }
]
+ | qualified_name(&t1)
] { *p = mknode(OP_LIST, t1, t2); }
;
AT
[ STRING { str = tok.str; }
':'
- | { if (! currfile) str = 0;
- else str = currfile->sy_idf->id_text;
+ | { if (! listfile) str = 0;
+ else str = listfile->sy_idf->id_text;
}
]
lin_num(&lin) { *p = mknode(OP_AT, lin->t_ival, str);
| /* type name */
{ s = NewSymbol(str, CurrentScope, TYPE, currnam); }
- 't' type_name(&(s->sy_type))
+ 't' type_name(&(s->sy_type), s)
{ if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; }
| /* tag name (only C?) */
tmp = s->sy_type;
} else s = NewSymbol(str, FileScope, VAR, currnam);
}
- 'G' type(&(s->sy_type), (int *) 0)
+ 'G' type(&(s->sy_type), (int *) 0, s)
{ if (tmp) s->sy_type = tmp; }
| /* static variable */
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
- 'S' type(&(s->sy_type), (int *) 0)
+ 'S' type(&(s->sy_type), (int *) 0, s)
| /* static variable, local scope */
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
- 'V' type(&(s->sy_type), (int *) 0)
+ 'V' type(&(s->sy_type), (int *) 0, s)
| /* register variable */
{ s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
- 'r' type(&(s->sy_type), (int *) 0)
+ 'r' type(&(s->sy_type), (int *) 0, s)
| /* value parameter */
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
- 'p' type(&(s->sy_type), (int *) 0)
+ 'p' type(&(s->sy_type), (int *) 0, s)
{ add_param_type('p', s); }
| /* value parameter but address passed */
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
- 'i' type(&(s->sy_type), (int *) 0)
+ 'i' type(&(s->sy_type), (int *) 0, s)
{ add_param_type('i', s); }
| /* variable parameter */
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
- 'v' type(&(s->sy_type), (int *) 0)
+ 'v' type(&(s->sy_type), (int *) 0, s)
{ add_param_type('v', s); }
| /* local variable */
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
- type_name(&(s->sy_type))
+ type_name(&(s->sy_type), s)
| /* function result in Pascal; ignore ??? */
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
- 'X' type_name(&(s->sy_type))
+ 'X' type_name(&(s->sy_type), s)
]
';'?
;
STRING /* has SINGLE quotes! */
;
-type_name(p_type *t;)
+type_name(p_type *t; p_symbol sy;)
{ int type_index[2]; p_type *p; }
:
type_index(type_index)
[
'='
- type(t, type_index)
+ type(t, type_index, sy)
{ p = tp_lookup(type_index);
if (*p && *p != incomplete_type) {
if (!((*p)->ty_flags & T_CROSS))
:
type_index(type_index)
'='
- type(&(t->sy_type), type_index)
+ type(&(t->sy_type), type_index, t)
{ p = tp_lookup(type_index);
if (*p && *p != incomplete_type) {
if (!((*p)->ty_flags & T_CROSS))
p->sy_type->ty_class = T_PROCEDURE;
p->sy_type->ty_size = pointer_size;
}
- type(&(p->sy_type->ty_retval), (int *) 0)
+ type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0)
{ if (CurrentScope != FileScope &&
saw_code) {
/* if saw_code is not set, it is a nested
CurrentScope->sc_proclevel = currnam->on_desc;
}
INTEGER ';'
- type(&(p->sy_type->ty_retval), (int *) 0)
+ type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0)
;
-type(p_type *ptp; int *type_index;)
+type(p_type *ptp; int *type_index; p_symbol sy;)
{ register p_type tp = 0;
p_type t1, t2;
long ic1, ic2;
* integer_const.
* Upperbound -1 means unsigned int or unsigned long.
*/
- 'r' type_name(&t1) ';'
+ 'r' type_name(&t1, (p_symbol) 0) ';'
[ 'A' integer_const(&ic1) { A_used = 1; }
| integer_const(&ic1)
]
/* array; first type is bound type, next type
* is element type
*/
- 'a' type(&t1, (int *) 0) ';' type(&t2, (int *) 0)
+ 'a' type(&t1, (int *) 0, (p_symbol) 0) ';' type(&t2, (int *) 0, (p_symbol) 0)
{ *ptp = array_type(t1, t2); }
|
/* structure type */
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
- structure_type(tp)
+ structure_type(tp, sy)
|
/* union type */
'u' { tp = new_type(); tp->ty_class = T_UNION; }
- structure_type(tp)
+ structure_type(tp, sy)
|
/* enumeration type */
'e' { tp = new_type(); tp->ty_class = T_ENUM; }
'*' { tp = new_type(); tp->ty_class =T_POINTER;
tp->ty_size = pointer_size;
}
- type(&(tp->ty_ptrto), (int *) 0)
+ type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0)
|
/* function type */
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
tp->ty_size = pointer_size;
}
- type(&(tp->ty_retval), (int *) 0)
+ type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
/*
[ %prefer
',' param_list(tp)
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
tp->ty_size = pointer_size;
}
- type(&(tp->ty_retval), (int *) 0)
+ type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
',' param_list(tp)
|
/* another procedure type */
* the second one represents the low bound
*/
'S' { tp = new_type(); tp->ty_class = T_SET; }
- type(&(tp->ty_setbase), (int *) 0) ';'
+ type(&(tp->ty_setbase), (int *) 0, (p_symbol) 0) ';'
[
integer_const(&(tp->ty_size)) ';'
integer_const(&(tp->ty_setlow)) ';'
|
/* file type of Pascal */
'L' { tp = new_type(); tp->ty_class = T_FILE; }
- type(&(tp->ty_fileof), (int *) 0)
+ type(&(tp->ty_fileof), (int *) 0, (p_symbol) 0)
|
- type_name(ptp)
+ type_name(ptp, (p_symbol) 0)
{ if (type_index &&
*ptp == incomplete_type &&
type_index[0] == last_index[0] &&
{ if (! *ptp) *ptp = tp; }
;
-structure_type(register p_type tp;)
+structure_type(register p_type tp; p_symbol sy;)
{ register struct fields *fldp;
- register p_symbol s;
+ char *str;
}
:
integer_const(&(tp->ty_size)) /* size in bytes */
- { open_scope((p_symbol) 0, 0); }
- [ { fldp = get_field_space(tp); }
- name(&(fldp->fld_name))
- { s = NewSymbol(fldp->fld_name, CurrentScope, FIELD, currnam);
- s->sy_field = fldp;
+ { open_scope(sy, 0);
+ if (sy) sy->sy_name.nm_scope = CurrentScope;
}
- type(&(fldp->fld_type), (int *) 0) ','
+ [
+ name(&str) { fldp = get_field_space(tp, str); }
+ type(&(fldp->fld_type), (int *) 0, (p_symbol) 0) ','
integer_const(&(fldp->fld_pos)) ',' /* offset in bits */
integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
]*
| 'v' { p->par_kind = 'v'; }
| 'i' { p->par_kind = 'i'; }
]
- type(&(p->par_type), (int *) 0) ';'
+ type(&(p->par_type), (int *) 0, (p_symbol) 0) ';'
{ t->ty_nbparams +=
param_size(p->par_type, p->par_kind);
p++;
}
static struct fields *
-get_field_space(tp)
+get_field_space(tp, s)
register p_type tp;
+ char *s;
{
+ register struct fields *p;
+ p_symbol sy;
+
if (! (tp->ty_nfields & 07)) {
tp->ty_fields = (struct fields *)
Realloc((char *) tp->ty_fields,
(tp->ty_nfields+8)*sizeof(struct fields));
}
- return &tp->ty_fields[tp->ty_nfields++];
+ p = &tp->ty_fields[tp->ty_nfields++];
+ p->fld_name = s;
+ sy = NewSymbol(s, CurrentScope, FIELD, currnam);
+ sy->sy_field = p;
+ return p;
}
static
saw_code = 0;
sym = add_file(n->on_mptr);
- if (! currfile) newfile(sym->sy_idf);
+ if (! listfile) newfile(sym->sy_idf);
open_scope(sym, 0);
sym->sy_file->f_scope = CurrentScope;
FileScope = CurrentScope;
--- /dev/null
+.\" $Header$
+.TH GRIND 1ACK
+.SH NAME
+grind \- source-level debugger for ACK
+.SH SYNOPSIS
+.B grind
+[
+.I <ACK object file>
+]
+[
+.I <object file>
+]
+.SH DESCRIPTION
+.B Grind
+is a utility for source-level debugging and execution of
+programs written in C or Modula-2 (Pascal will be added later).
+Its operation resembles the operation of
+.IR dbx ,
+a source-level debugger
+available on many Unix systems. However, some
+.B Grind
+commands are not available in
+.IR dbx ,
+and some more
+.I dbx
+commands are not available in
+.BR grind ,
+and some things are just plain different.
+.LP
+.I <object file>
+is an object file, produced by
+.IR ack (1ACK)
+with the
+.B \-g
+option to include a symbol table.
+.LP
+If no
+.I <object file>
+is specified, "a.out" is used.
+.LP
+For some machines, the debugger does not recognize the object file
+format. For these machines, the result of the
+.IR led (6ACK)
+program must be saved and offered to
+.BR grind .
+.SH USAGE
+Some
+.B grind
+commands take an expression argument.
+.SS Expressions
+.B Grind expressions
+are combinations of variables, constants, and operators.
+The syntax and the operators depend on the source language of the program
+being debugged. However, the type rules are probably less strict than the
+rules of this language. For instance, in Modula-2 one cannot combine
+values of type INTEGER with values of type REAL in an expression without
+using conversion routines. In
+.BR grind ,
+the conversions needed are performed automatically.
+Expressions cannot involve strings, structures, or
+arrays, although elements of structures or arrays may be used.
+.SS Operators
+.LP
+.B Grind
+supports operators for addition, subtraction, multiplication, division,
+remainder, bitwise or, bitwise xor, bitwise and, boolean or,
+boolean and, left-shift, right-shift, address-of, dereference, less than,
+less than or equal, equal, not equal, greater than, greater than or equal,
+selection.
+.LP
+The syntax and priority of these operators depends on the source language.
+Parentheses can be used for grouping.
+.SS "Scope Rules"
+.LP
+.B dbx
+uses the current file and function to resolve scope conflicts.
+Their values are updated as files and functions are entered and exited
+during execution.
+Names can also be qualified with procedure- or module names, as in
+\fImodule\fP`\fIproc\fP`\fIname\fP.
+.B Grind
+tries to be intelligent about names, so qualification is only needed when
+names are used for more than one object in a program and the current scope
+does not help.
+.SS "Positions"
+In general, there are two ways to specify a position; the first way is
+to specify filename and linenumber, in a so-called at-clause, like this:
+.RS
+\fBat\fP [ "\fIfilename\fP": ] \fIlinenumber\fP
+.RE
+The
+.I filename
+part is optional.
+The second way is to specify a function name, like this:
+.RS
+\fBin \fIfunction\fP
+.RE
+This indicates the first statement within the named function (except for
+the trace command discussed later).
+.SS "Commands"
+.TP
+.B \s+2^\s0C
+Interrupt. Stop the program being debugged and enter
+.BR grind .
+.TP
+\fBrun\fP [ \fIargs\fP ] [ < \fIinfile\fP ] [ > \fIoutfile\fP ]
+Start executing
+.I <object file>
+with command line arguments
+.IR args ,
+and possible redirection of standard input and/or standard output.
+.TP
+.B rerun
+Repeats the last
+.B run
+command.
+\fBcont\fP [ \fBat\fP \fIsourceline\fP ]
+Continue execution from where it stopped, or, if \fIsourceline\fP is
+given, at that source line.
+.TP
+\fBtrace\fP [ \fBon\fP \fIexpression\fP ] [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ]
+Display tracing information.
+If no argument is specified, each source line is displayed before
+execution.
+In addition, if an \fBon\fP-clause is given, the value of the expression
+is printed.
+If a position is given there are two possibilities: if the position is
+given as \fBin\fP \fIfunction\fP, then the tracing information is
+displayed only while executing the function or
+procedure
+.IR function .
+If the position is given as \fBat\fP \fIlinenumber\fP,
+then the tracing information is displayed only whenever the source line
+indicated is reached.
+If a condition is given, tracing information is only displayed when
+.I condition
+is true.
+.TP
+\fBstop\fP [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ]
+Stop execution when the
+.I position
+is reached, and then when
+.I condition
+becomes true.
+If no position is given, stop when
+.I condition
+becomes true.
+If no condition is given, stop when
+.I position
+is reached.
+Either a position or a condition (or both) must be given.
+.TP
+\fBwhen\fP [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ] { \fIcommand\fP [ ; \fIcommand ] ... }
+Execute the
+.B grind
+.IR command (s)
+when the
+.I position
+is reached, and then when
+.I condition
+becomes true.
+If no position is given, stop when
+.I condition
+becomes true.
+If no condition is given, stop when
+.I position
+is reached.
+Either a position or a condition (or both) must be given.
+.TP
+\fBprint\fP \fIexpression\fP [ ',' \fIexpression\fP ] ...
+Print the value of each expression.
+.TP
+\fBdisplay\fP \fIexpression\fP [ ',' \fIexpression\fP ] ...
+Print the value of each expression whenever the program stops.
+.TP
+.B dump
+Saves the data (global data + stack) of the program. These data can
+be restore with the
+.B restore
+command discussed later.
+.B Dump
+and
+.B restore
+combinations can be used as a poor man's implementation of an "undo"
+facility.
+.TP
+.B status
+Display active
+.BR trace ,
+.BR stop ,
+.BR when ,
+and
+.B display
+commands, and associated command numbers.
+Also display current
+.B dump
+records.
+.TP
+\fBdelete\fP \fIcommandnumber\fP
+Remove the command corresponding to \fIcommandnumber\fP
+(as displayed by
+.BR status ).
+.TP
+\fBrestore\fP \fIcommandnumber\fP
+Restore the data corresponding to the dump of \fIcommandnumber\fP
+(as displayed by
+.BR status ).
+This restores the values of all variables of the program to the values
+at the time the dump was made. The program counter is also restored.
+This effectively puts the program back into the state it was when the
+dump was made, except for file-handling: the state of the files that
+the program handles is not changed.
+Apart from this,
+.B restore
+even works when the program is finished.
+.TP
+\fBstep\fP [ \fIn\fP ]
+Execute the next
+.I n
+source lines.
+If omitted,
+.I n
+is taken to be 1.
+This command steps into functions.
+.TP
+\fBnext\fP [ \fIn\fP ]
+Execute the next
+.I n
+source lines.
+If omitted,
+.I n
+is taken to be 1.
+.B Next
+steps past function-calls.
+.TP
+\fBwhich\fP \fIname\fP
+Print the fully-qualified name of the given name.
+.TP
+\fBfind\fP \fIname\fP
+Print the fully qualified name of all symbols matching
+.IR name .
+.TP
+\fBset\fP \fIexpression\fP \fBto\fP \fIexpression\fP
+Assign the value of the second
+.I expression
+to the designator indicated by the first
+.IR expression .
+Needless to say, the first
+.I expression
+must indicate a designator (something that can be assigned to).
+If the types do not match,
+.B grind
+tries to apply conversions.
+.TP
+\fBwhere\fP [ \fIn\fP ]
+List all, or the top
+.IR n ,
+active functions on the stack.
+.TP
+\fBfile\fP [ \fIfilename\fP ]
+.br
+Print the name of the current source file, or
+change the current source file to
+.IR filename .
+.TP
+\fBlist\fP [ \fIstartline\fP [ , \fIendline\fP ] | \fIfunction\fP ]
+If no arguments are given, list the next ten lines from current source file,
+if a
+.I startline
+is given, list from
+.I startline
+through
+.IR endline ,
+or
+list from five lines above, to five lines below
+the first statement of
+.IR function .
+.TP
+.B quit
+Exit
+.BR grind .
+.SH ENVIRONMENT
+P.M.
+.SH SEE ALSO
+.BR ack (1ACK).
+.BR led (6ACK).
+.SH BUGS
+.LP
+.B Grind
+does not correctly handle bit-fields.
+.LP
+.B Grind
+does not understand WITH statements.
extern FILE *fopen();
extern FILE *db_out;
extern t_lineno currline;
-#define window_size 21
static int
mk_filnm(dir, file, newname)
return NULL;
}
+#define window_size 21
/* Print a window of window_size lines around line "line" of
file "file".
*/
for (n = l1; n <= l2; n++) {
register int c;
- fprintf(db_out, "%c%5d\t", n == currline ? '>' : ' ', n);
+ fprintf(db_out, "%c%5d\t", currfile && file == currfile->sy_file && n == currline ? '>' : ' ', n);
do {
c = getc(f);
if (c != EOF) putc(c, db_out);
#include "symbol.h"
#include "scope.h"
-static char *usage = "Usage: %s [-d] [<ack.out>] [<a.out>]";
+static char *usage = "Usage: %s [<ack.out>] [<a.out>]";
static char *progname;
char *AckObj;
char *AObj;
char *dirs[] = { "", 0 };
FILE *db_out;
FILE *db_in;
-t_lineno currline;
int debug;
extern struct tokenname tkidf[];
extern char *strindex();
#define MAXARG 128
extern char *strncpy();
+extern struct idf *str2idf();
+
extern char *AObj;
-extern t_lineno currline;
extern FILE *db_out;
extern int debug;
-extern struct idf *str2idf();
extern long pointer_size;
static int child_pid; /* process id of child */
static int to_child, from_child; /* file descriptors for communication */
static int child_status;
static int restoring;
+static int fild1[2], fild2[2]; /* pipe file descriptors */
int db_ss;
+t_lineno currline, listline;
static int catch_sigpipe();
static int stopped();
static int uputm(), ugetm();
-static int fild1[2], fild2[2]; /* pipe file descriptors */
int
init_run()
if (s) {
fprintf(db_out, "%s ", s);
pos = print_position((t_addr) a, 1);
- newfile(str2idf(pos->filename, 1));
- currline = pos->lineno;
fputs("\n", db_out);
- lines(currfile->sy_file, (int)currline, (int)currline);
+ list_position(pos);
}
return 1;
}
#include "tree.h"
#include "operator.h"
-p_symbol currfile;
+p_symbol currfile, listfile;
extern FILE *db_out;
case PROC:
case FUNCTION:
case MODULE:
+ case TYPE:
+ case VAR:
+ case REGVAR:
+ case LOCVAR:
+ case VARPAR:
return s->sy_name.nm_scope;
}
return 0;
switch(p->t_oper) {
case OP_NAME:
- sym = Lookfromscope(p->t_idf, FILELINK|FILESYM|PROC|FUNCTION|MODULE, sc->sc_static_encl);
+#define CLASS (FILELINK|FILESYM|PROC|FUNCTION|MODULE|TYPE|VAR|REGVAR|LOCVAR|VARPAR)
+ sym = Lookfromscope(p->t_idf, CLASS, sc->sc_static_encl);
if (sym) {
target_sc = def_scope(sym);
while (sc && sc != target_sc) {
case OP_SELECT:
arg = p->t_args[1];
- sym = Lookfromscope(arg->t_idf, FILELINK|FILESYM|PROC|FUNCTION|MODULE, sc->sc_static_encl);
+ sym = Lookfromscope(arg->t_idf, CLASS, sc->sc_static_encl);
if (sym) {
target_sc = def_scope(sym);
while (sc && sc != target_sc) {
do_find(p)
p_tree p;
{
- p_symbol sym = 0;
register p_symbol s;
p_tree arg;
arg = p->t_args[1];
assert(arg->t_oper == OP_NAME);
s = arg->t_idf->id_def;
- sym = 0;
while (s) {
if (consistent(p, s->sy_scope)) {
pr_sym(s);
extern p_symbol NewSymbol(), Lookup(), Lookfromscope(), add_file();
extern p_symbol identify();
-extern p_symbol currfile;
+extern p_symbol currfile, listfile;
#include "expr.h"
extern FILE *db_out;
-extern t_lineno currline;
+extern t_lineno currline, listline;
extern long pointer_size;
extern char *strrindex();
p_tree run_command;
+t_lineno list_line;
+
/*VARARGS1*/
p_tree
free_tree(p);
}
+static t_addr
+get_addr(p)
+ p_tree p;
+{
+ t_addr a = ILL_ADDR;
+ register p_symbol sym;
+
+ if (! p) return NO_ADDR;
+ if (p->t_address != 0) return p->t_address;
+ switch(p->t_oper) {
+ case OP_AT:
+ if (! p->t_filename &&
+ (! listfile || ! (p->t_filename = listfile->sy_idf->id_text))) {
+ error("no current file");
+ break;
+ }
+ a = get_addr_from_position(&(p->t_pos));
+ if (a == ILL_ADDR) {
+ error("could not determine address of \"%s\":%d",
+ p->t_filename, p->t_lino);
+ break;
+ }
+ p->t_address = a;
+ break;
+
+ case OP_IN:
+ a = get_addr(p->t_args[0]);
+ p->t_address = a;
+ break;
+
+ case OP_NAME:
+ case OP_SELECT:
+ sym = identify(p, FUNCTION|PROC|MODULE);
+ if (! sym) {
+ break;
+ }
+ if (! sym->sy_name.nm_scope || ! sym->sy_name.nm_scope->sc_bp_opp) {
+ error("could not determine address of \"%s\"", p->t_str);
+ break;
+ }
+ a = sym->sy_name.nm_scope->sc_bp_opp;
+ break;
+
+ default:
+ assert(0);
+ }
+ return a;
+}
+
print_node(p, top_level)
register p_tree p;
{
break;
case OP_WHERE:
fputs("where", db_out);
- if (p->t_ival != 0x7fffffff) fprintf(" %ld", p->t_ival);
+ if (p->t_ival != 0x7fffffff) fprintf(db_out, " %ld", p->t_ival);
break;
case OP_CONT:
fputs("cont", db_out);
do_list(p)
p_tree p;
{
- if (currfile) {
- lines(currfile->sy_file,
- p->t_args[0] ? (int) p->t_args[0]->t_ival : (int) currline-4,
- p->t_args[1] ? (int) p->t_args[1]->t_ival : (int) currline+5);
- currline = p->t_args[1] ? p->t_args[1]->t_ival + 1 : currline + 10;
+ int l1, l2;
+
+ if (! p->t_args[0]) {
+ l1 = listline;
+ l2 = listline + 9;
+ }
+ else {
+ if (p->t_args[0]->t_oper == OP_INTEGER) {
+ l1 = p->t_args[0]->t_ival;
+ assert(p->t_args[1] != 0);
+ l2 = p->t_args[1]->t_ival;
+ }
+ else {
+ t_addr a = get_addr(p->t_args[0]);
+ p_position pos;
+
+ if (a == ILL_ADDR) {
+ error("could not determine address");
+ return;
+ }
+ pos = get_position_from_addr(a);
+ newfile(str2idf(pos->filename, 1));
+ l1 = pos->lineno - 5;
+ if (l1 < 1) l1 = 1;
+ l2 = l1+9;
+ }
+ }
+ if (listfile) {
+ lines(listfile->sy_file, l1, l2);
+ listline = l2+1;
}
else fprintf(db_out, "no current file\n");
}
if (p->t_args[0]) {
newfile(p->t_args[0]->t_idf);
}
- else if (currfile) fprintf(db_out, "%s\n", currfile->sy_idf->id_text);
+ else if (listfile) fprintf(db_out, "%s\n", listfile->sy_idf->id_text);
else fprintf(db_out, "no current file\n");
}
{
register p_symbol sym = Lookup(id, PervasiveScope, FILESYM);
- if (currfile != sym) currline = 1;
- currfile = sym;
- if (! currfile) {
- currline = 1;
- currfile = add_file(id->id_text);
- currfile->sy_file->f_scope = FileScope;
+ if (listfile != sym) listline = 1;
+ listfile = sym;
+ if (! listfile) {
+ listline = 1;
+ listfile = add_file(id->id_text);
+ listfile->sy_file->f_scope = FileScope;
}
find_language(strrindex(id->id_text, '.'));
}
-static t_addr
-get_pos(p)
- p_tree p;
-{
- t_addr a = ILL_ADDR;
- register p_symbol sym;
-
- if (! p) return NO_ADDR;
- if (p->t_address != 0) return p->t_address;
- switch(p->t_oper) {
- case OP_AT:
- if (! p->t_filename &&
- (! currfile || ! (p->t_filename = currfile->sy_idf->id_text))) {
- error("no current file");
- break;
- }
- a = get_addr_from_position(&(p->t_pos));
- if (a == ILL_ADDR) {
- error("could not determine address of \"%s\":%d",
- p->t_filename, p->t_lino);
- break;
- }
- p->t_address = a;
- break;
-
- case OP_IN:
- a = get_pos(p->t_args[0]);
- p->t_address = a;
- break;
-
- case OP_NAME:
- case OP_SELECT:
- sym = identify(p, FUNCTION|PROC|MODULE);
- if (! sym) {
- break;
- }
- if (! sym->sy_name.nm_scope || ! sym->sy_name.nm_scope->sc_bp_opp) {
- error("could not determine address of \"%s\"", p->t_str);
- break;
- }
- a = sym->sy_name.nm_scope->sc_bp_opp;
- break;
-
- default:
- assert(0);
- }
- return a;
-}
-
do_stop(p)
p_tree p;
{
- t_addr a = get_pos(p->t_args[0]);
+ t_addr a = get_addr(p->t_args[0]);
if (a == ILL_ADDR) {
return;
p->t_address = NO_ADDR;
if (p->t_args[0]) {
- a = get_pos(p->t_args[0]);
+ a = get_addr(p->t_args[0]);
if (a == ILL_ADDR) return;
if (p->t_args[0]->t_oper == OP_AT) {
e = a;
if (p) switch(p->t_oper) {
case OP_WHEN:
case OP_STOP: {
- t_addr a = get_pos(p->t_args[0]);
+ t_addr a = get_addr(p->t_args[0]);
if (a != ILL_ADDR && a != NO_ADDR) {
set_or_clear_breakpoint(a, CLRBP);
break;
}
case OP_TRACE: {
- t_addr a = get_pos(p->t_args[0]);
+ t_addr a = get_addr(p->t_args[0]);
if (a != ILL_ADDR && a != NO_ADDR) {
t_addr e;
break;
}
}
- {
- p_position pos = get_position_from_addr(a);
-
- newfile(str2idf(pos->filename, 1));
- currline = pos->lineno;
- lines(currfile->sy_file, (int)currline, (int)currline);
- if (p->t_args[2]) do_print(p->t_args[2]);
- }
+ list_position(get_position_from_addr(a));
+ if (p->t_args[2]) do_print(p->t_args[2]);
break;
default:
assert(0);
}
}
+
+list_position(pos)
+ p_position pos;
+{
+ newfile(str2idf(pos->filename, 1));
+ currfile = listfile;
+ currline = pos->lineno;
+ listline = currline-5;
+ lines(currfile->sy_file, (int)currline, (int)currline);
+}