BSD 4_4 release
[unix-history] / usr / src / old / dbx / eval.c
index 80a2e76..8f6dfad 100644 (file)
@@ -1,6 +1,39 @@
-/* Copyright (c) 1982 Regents of the University of California */
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 
-static char sccsid[] = "@(#)eval.c 1.5 %G%";
+#ifndef lint
+static char sccsid[] = "@(#)eval.c     5.7 (Berkeley) 6/1/90";
+#endif /* not lint */
 
 /*
  * Tree evaluation.
 
 /*
  * Tree evaluation.
@@ -9,6 +42,7 @@ static char sccsid[] = "@(#)eval.c 1.5 %G%";
 #include "defs.h"
 #include "tree.h"
 #include "operators.h"
 #include "defs.h"
 #include "tree.h"
 #include "operators.h"
+#include "debug.h"
 #include "eval.h"
 #include "events.h"
 #include "symbols.h"
 #include "eval.h"
 #include "events.h"
 #include "symbols.h"
@@ -17,6 +51,7 @@ static char sccsid[] = "@(#)eval.c 1.5 %G%";
 #include "object.h"
 #include "mappings.h"
 #include "process.h"
 #include "object.h"
 #include "mappings.h"
 #include "process.h"
+#include "runtime.h"
 #include "machine.h"
 #include <signal.h>
 
 #include "machine.h"
 #include <signal.h>
 
@@ -24,7 +59,7 @@ static char sccsid[] = "@(#)eval.c 1.5 %G%";
 
 #include "machine.h"
 
 
 #include "machine.h"
 
-#define STACKSIZE 2000
+#define STACKSIZE 20000
 
 typedef Char Stack;
 
 
 typedef Char Stack;
 
@@ -36,6 +71,11 @@ typedef Char Stack;
     (*((type *) (sp -= sizeof(type)))) \
 )
 
     (*((type *) (sp -= sizeof(type)))) \
 )
 
+#define popn(n, dest) { \
+    sp -= n; \
+    bcopy(sp, dest, n); \
+}
+
 #define alignstack() { \
     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
 }
 #define alignstack() { \
     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
 }
@@ -44,6 +84,7 @@ typedef Char Stack;
 
 public Stack stack[STACKSIZE];
 public Stack *sp = &stack[0];
 
 public Stack stack[STACKSIZE];
 public Stack *sp = &stack[0];
+public Boolean useInstLoc = false;
 
 #define chksp() \
 { \
 
 #define chksp() \
 { \
@@ -55,7 +96,11 @@ public Stack *sp = &stack[0];
 #define poparg(n, r, fr) { \
     eval(p->value.arg[n]); \
     if (isreal(p->op)) { \
 #define poparg(n, r, fr) { \
     eval(p->value.arg[n]); \
     if (isreal(p->op)) { \
-       fr = pop(double); \
+       if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
+           fr = pop(float); \
+       } else { \
+           fr = pop(double); \
+       } \
     } else if (isint(p->op)) { \
        r = popsmall(p->value.arg[n]->nodetype); \
     } \
     } else if (isint(p->op)) { \
        r = popsmall(p->value.arg[n]->nodetype); \
     } \
@@ -63,6 +108,25 @@ public Stack *sp = &stack[0];
 
 #define Boolrep char   /* underlying representation type for booleans */
 
 
 #define Boolrep char   /* underlying representation type for booleans */
 
+/*
+ * Command-level evaluation.
+ */
+
+public Node topnode;
+
+public topeval (p)
+Node p;
+{
+    if (traceeval) {
+       fprintf(stderr, "topeval(");
+       prtree(stderr, p);
+       fprintf(stderr, ")\n");
+       fflush(stderr);
+    }
+    topnode = p;
+    eval(p);
+}
+
 /*
  * Evaluate a parse tree leaving the value on the top of the stack.
  */
 /*
  * Evaluate a parse tree leaving the value on the top of the stack.
  */
@@ -75,12 +139,16 @@ register Node p;
     Address addr;
     long i, n;
     int len;
     Address addr;
     long i, n;
     int len;
-    Symbol s, f;
+    Symbol s;
     Node n1, n2;
     Node n1, n2;
-    Boolean b;
+    boolean b;
     File file;
     File file;
+    String str;
 
     checkref(p);
 
     checkref(p);
+    if (traceeval) {
+       fprintf(stderr, "begin eval %s\n", opname(p->op));
+    }
     switch (degree(p->op)) {
        case BINARY:
            poparg(1, r1, fr1);
     switch (degree(p->op)) {
        case BINARY:
            poparg(1, r1, fr1);
@@ -99,21 +167,26 @@ register Node p;
            s = p->value.sym;
            if (s == retaddrsym) {
                push(long, return_addr());
            s = p->value.sym;
            if (s == retaddrsym) {
                push(long, return_addr());
-           } else {
-               if (isvariable(s)) {
-                   if (s != program and not isactive(container(s))) {
-                       error("\"%s\" is not active", symname(s));
-                   }
-                   push(long, address(s, nil));
-               } else if (isblock(s)) {
-                   push(Symbol, s);
+           } else if (isvariable(s)) {
+               if (s != program and not isactive(container(s))) {
+                   error("\"%s\" is not active", symname(s));
+               }
+               if (isvarparam(s) and not isopenarray(s)) {
+                   rpush(address(s, nil), sizeof(Address));
                } else {
                } else {
-                   error("can't evaluate a %s", classname(s));
+                   push(Address, address(s, nil));
                }
                }
+           } else if (isblock(s)) {
+               push(Symbol, s);
+           } else if (isconst(s)) {
+               eval(constval(s));
+           } else {
+               error("can't evaluate a %s", classname(s));
            }
            break;
 
        case O_LCON:
            }
            break;
 
        case O_LCON:
+       case O_CCON:
            r0 = p->value.lcon;
            pushsmall(p->nodetype, r0);
            break;
            r0 = p->value.lcon;
            pushsmall(p->nodetype, r0);
            break;
@@ -129,15 +202,19 @@ register Node p;
            break;
 
        case O_INDEX:
            break;
 
        case O_INDEX:
-           n = pop(long);
-           i = evalindex(p->value.arg[0]->nodetype,
-               popsmall(p->value.arg[1]->nodetype));
-           push(long, n + i*size(p->nodetype));
+           s = p->value.arg[0]->nodetype;
+           p->value.arg[0]->nodetype = t_addr;
+           eval(p->value.arg[0]);
+           p->value.arg[0]->nodetype = s;
+           n = pop(Address);
+           eval(p->value.arg[1]);
+           evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
            break;
 
        case O_DOT:
            s = p->value.arg[1]->value.sym;
            break;
 
        case O_DOT:
            s = p->value.arg[1]->value.sym;
-           n = lval(p->value.arg[0]);
+           eval(p->value.arg[0]);
+           n = pop(long);
            push(long, n + (s->symvalue.field.offset div 8));
            break;
 
            push(long, n + (s->symvalue.field.offset div 8));
            break;
 
@@ -152,25 +229,19 @@ register Node p;
            if (addr == 0) {
                error("reference through nil pointer");
            }
            if (addr == 0) {
                error("reference through nil pointer");
            }
-           if (p->op == O_INDIR) {
-               len = sizeof(long);
-           } else {
-               len = size(p->nodetype);
-           }
+           len = size(p->nodetype);
            rpush(addr, len);
            break;
 
            rpush(addr, len);
            break;
 
-       /*
-        * Effectively, we want to pop n bytes off for the evaluated subtree
-        * and push len bytes on for the new type of the same tree.
-        */
        case O_TYPERENAME:
        case O_TYPERENAME:
-           n = size(p->value.arg[0]->nodetype);
-           len = size(p->nodetype);
-           sp = sp - n + len;
+           loophole(size(p->value.arg[0]->nodetype), size(p->nodetype));
            break;
 
        case O_COMMA:
            break;
 
        case O_COMMA:
+           eval(p->value.arg[0]);
+           if (p->value.arg[1] != nil) {
+               eval(p->value.arg[1]);
+           }
            break;
 
        case O_ITOF:
            break;
 
        case O_ITOF:
@@ -297,51 +368,16 @@ register Node p;
            break;
 
        case O_CONT:
            break;
 
        case O_CONT:
-           cont();
+           cont(p->value.lcon);
            printnews();
            break;
 
        case O_LIST:
            printnews();
            break;
 
        case O_LIST:
-           if (p->value.arg[0]->op == O_SYM) {
-               f = p->value.arg[0]->value.sym;
-               addr = firstline(f);
-               if (addr == NOADDR) {
-                   error("no source lines for \"%s\"", symname(f));
-               }
-               setsource(srcfilename(addr));
-               r0 = srcline(addr) - 5;
-               r1 = r0 + 10;
-               if (r0 < 1) {
-                   r0 = 1;
-               }
-           } else {
-               eval(p->value.arg[0]);
-               r0 = pop(long);
-               eval(p->value.arg[1]);
-               r1 = pop(long);
-           }
-           printlines((Lineno) r0, (Lineno) r1);
+           list(p);
            break;
 
        case O_FUNC:
            break;
 
        case O_FUNC:
-           if (p->value.arg[0] == nil) {
-               printname(stdout, curfunc);
-               putchar('\n');
-           } else {
-               curfunc = p->value.arg[0]->value.sym;
-               if (isblock(curfunc) and not ismodule(curfunc)) {
-                   error("%s is not a procedure or function",
-                       symname(curfunc));
-               }
-               addr = codeloc(curfunc);
-               if (addr != NOADDR) {
-                   setsource(srcfilename(addr));
-                   cursrcline = srcline(addr) - 5;
-                   if (cursrcline < 1) {
-                       cursrcline = 1;
-                   }
-               }
-           }
+           func(p->value.arg[0]);
            break;
 
        case O_EXAMINE:
            break;
 
        case O_EXAMINE:
@@ -397,6 +433,7 @@ register Node p;
                stepc();
            }
            inst_tracing = b;
                stepc();
            }
            inst_tracing = b;
+           useInstLoc = (Boolean) (not p->value.step.source);
            printnews();
            break;
 
            printnews();
            break;
 
@@ -413,40 +450,92 @@ register Node p;
            break;
 
        case O_WHEREIS:
            break;
 
        case O_WHEREIS:
-           printwhereis(stdout, p->value.arg[0]->value.sym);
+           if (p->value.arg[0]->op == O_SYM) {
+               printwhereis(stdout, p->value.arg[0]->value.sym);
+           } else {
+               printwhereis(stdout, p->value.arg[0]->nodetype);
+           }
            break;
 
        case O_WHICH:
            break;
 
        case O_WHICH:
-           printwhich(stdout, p->value.arg[0]->value.sym);
+           if (p->value.arg[0]->op == O_SYM) {
+               printwhich(stdout, p->value.arg[0]->value.sym);
+           } else {
+               printwhich(stdout, p->value.arg[0]->nodetype);
+           }
            putchar('\n');
            break;
 
        case O_ALIAS:
            n1 = p->value.arg[0];
            n2 = p->value.arg[1];
            putchar('\n');
            break;
 
        case O_ALIAS:
            n1 = p->value.arg[0];
            n2 = p->value.arg[1];
-           if (n1 == nil) {
-               print_alias(nil);
-           } else if (n2 == nil) {
-               print_alias(n1->value.name);
+           if (n2 == nil) {
+               if (n1 == nil) {
+                   alias(nil, nil, nil);
+               } else {
+                   alias(n1->value.name, nil, nil);
+               }
+           } else if (n2->op == O_NAME) {
+               str = ident(n2->value.name);
+               alias(n1->value.name, nil, strdup(str));
            } else {
            } else {
-               enter_alias(n1->value.name, n2->value.name);
+               if (n1->op == O_COMMA) {
+                   alias(
+                       n1->value.arg[0]->value.name,
+                       (List) n1->value.arg[1],
+                       n2->value.scon
+                   );
+               } else {
+                   alias(n1->value.name, nil, n2->value.scon);
+               }
            }
            break;
 
            }
            break;
 
+       case O_UNALIAS:
+           unalias(p->value.arg[0]->value.name);
+           break;
+
+       case O_CALLPROC:
+           callproc(p, false);
+           break;
+
        case O_CALL:
        case O_CALL:
-           callproc(p->value.arg[0], p->value.arg[1]);
+           callproc(p, true);
            break;
 
        case O_CATCH:
            break;
 
        case O_CATCH:
-           psigtrace(process, p->value.lcon, true);
+           if (p->value.lcon == 0) {
+               printsigscaught(process);
+           } else {
+               psigtrace(process, p->value.lcon, true);
+           }
            break;
 
        case O_EDIT:
            edit(p->value.scon);
            break;
 
            break;
 
        case O_EDIT:
            edit(p->value.scon);
            break;
 
+        case O_DEBUG:
+            debug(p);
+           break;
+
+       case O_DOWN:
+           checkref(p->value.arg[0]);
+           assert(p->value.arg[0]->op == O_LCON);
+           down(p->value.arg[0]->value.lcon);
+           break;
+
        case O_DUMP:
        case O_DUMP:
-           dump();
+           if (p->value.arg[0] == nil) {
+               dumpall();
+           } else {
+               s = p->value.arg[0]->value.sym;
+               if (s == curfunc) {
+                   dump(nil);
+               } else {
+                   dump(s);
+               }
+           }
            break;
 
        case O_GRIPE:
            break;
 
        case O_GRIPE:
@@ -458,13 +547,34 @@ register Node p;
            break;
 
        case O_IGNORE:
            break;
 
        case O_IGNORE:
-           psigtrace(process, p->value.lcon, false);
+           if (p->value.lcon == 0) {
+               printsigsignored(process);
+           } else {
+               psigtrace(process, p->value.lcon, false);
+           }
+           break;
+
+       case O_RETURN:
+           if (p->value.arg[0] == nil) {
+               rtnfunc(nil);
+           } else {
+               assert(p->value.arg[0]->op == O_SYM);
+               rtnfunc(p->value.arg[0]->value.sym);
+           }
            break;
 
        case O_RUN:
            run();
            break;
 
            break;
 
        case O_RUN:
            run();
            break;
 
+       case O_SET:
+           set(p->value.arg[0], p->value.arg[1]);
+           break;
+
+       case O_SEARCH:
+           search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
+           break;
+
        case O_SOURCE:
            setinput(p->value.scon);
            break;
        case O_SOURCE:
            setinput(p->value.scon);
            break;
@@ -476,17 +586,21 @@ register Node p;
        case O_TRACE:
        case O_TRACEI:
            trace(p);
        case O_TRACE:
        case O_TRACEI:
            trace(p);
-           if (isstdin()) {
-               status();
-           }
            break;
 
        case O_STOP:
        case O_STOPI:
            stop(p);
            break;
 
        case O_STOP:
        case O_STOPI:
            stop(p);
-           if (isstdin()) {
-               status();
-           }
+           break;
+
+       case O_UNSET:
+           undefvar(p->value.arg[0]->value.name);
+           break;
+
+       case O_UP:
+           checkref(p->value.arg[0]);
+           assert(p->value.arg[0]->op == O_LCON);
+           up(p->value.arg[0]->value.lcon);
            break;
 
        case O_ADDEVENT:
            break;
 
        case O_ADDEVENT:
@@ -494,7 +608,19 @@ register Node p;
            break;
 
        case O_DELETE:
            break;
 
        case O_DELETE:
-           delevent((unsigned int) p->value.lcon);
+           n1 = p->value.arg[0];
+           while (n1->op == O_COMMA) {
+               n2 = n1->value.arg[0];
+               assert(n2->op == O_LCON);
+               if (not delevent((unsigned int) n2->value.lcon)) {
+                   error("unknown event %ld", n2->value.lcon);
+               }
+               n1 = n1->value.arg[1];
+           }
+           assert(n1->op == O_LCON);
+           if (not delevent((unsigned int) n1->value.lcon)) {
+               error("unknown event %ld", n1->value.lcon);
+           }
            break;
 
        case O_ENDX:
            break;
 
        case O_ENDX:
@@ -534,8 +660,10 @@ register Node p;
                    printf("tracei: ");
                    printinst(pc, pc);
                } else {
                    printf("tracei: ");
                    printinst(pc, pc);
                } else {
-                   printf("trace:  ");
-                   printlines(curline, curline);
+                   if (canReadSource()) {
+                       printf("trace:  ");
+                       printlines(curline, curline);
+                   }
                }
            } else {
                printsrcpos();
                }
            } else {
                printsrcpos();
@@ -572,6 +700,9 @@ register Node p;
        default:
            panic("eval: bad op %d", p->op);
     }
        default:
            panic("eval: bad op %d", p->op);
     }
+    if (traceeval) { 
+       fprintf(stderr, "end eval %s\n", opname(p->op));
+    }
 }
 
 /*
 }
 
 /*
@@ -653,23 +784,26 @@ long v;
 public long popsmall(t)
 Symbol t;
 {
 public long popsmall(t)
 Symbol t;
 {
+    register integer n;
     long r;
 
     long r;
 
-    switch (size(t)) {
-       case sizeof(char):
+    n = size(t);
+    if (n == sizeof(char)) {
+       if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
+           r = (long) pop(unsigned char);
+       } else {
            r = (long) pop(char);
            r = (long) pop(char);
-           break;
-
-       case sizeof(short):
+       }
+    } else if (n == sizeof(short)) {
+       if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
+           r = (long) pop(unsigned short);
+       } else {
            r = (long) pop(short);
            r = (long) pop(short);
-           break;
-
-       case sizeof(long):
-           r = pop(long);
-           break;
-
-       default:
-           panic("popsmall: size is %d", size(t));
+       }
+    } else if (n == sizeof(long)) {
+       r = pop(long);
+    } else {
+       error("[internal error: size %d in popsmall]", n);
     }
     return r;
 }
     }
     return r;
 }
@@ -681,13 +815,15 @@ Symbol t;
 public Boolean cond(p)
 Node p;
 {
 public Boolean cond(p)
 Node p;
 {
-    register Boolean b;
+    Boolean b;
+    int i;
 
     if (p == nil) {
        b = true;
     } else {
        eval(p);
 
     if (p == nil) {
        b = true;
     } else {
        eval(p);
-       b = pop(Boolean);
+       i = pop(Boolrep);
+       b = (Boolean) i;
     }
     return b;
 }
     }
     return b;
 }
@@ -766,6 +902,9 @@ Node cond;
     }
     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
     action->value.trace.event = addevent(event, buildcmdlist(action));
     }
     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
     action->value.trace.event = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(action->value.trace.event);
+    }
 }
 
 /*
 }
 
 /*
@@ -779,9 +918,10 @@ Node cond;
 {
     Node event, wh;
     Command action;
 {
     Node event, wh;
     Command action;
+    Event e;
 
     if (exp->op == O_LCON) {
 
     if (exp->op == O_LCON) {
-       wh = build(O_QLINE, build(O_SCON, cursource), exp);
+       wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
     } else {
        wh = exp;
     }
     } else {
        wh = exp;
     }
@@ -794,7 +934,10 @@ Node cond;
     if (cond) {
        action = build(O_IF, cond, buildcmdlist(action));
     }
     if (cond) {
        action = build(O_IF, cond, buildcmdlist(action));
     }
-    addevent(event, buildcmdlist(action));
+    e = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(e);
+    }
 }
 
 /*
 }
 
 /*
@@ -809,6 +952,7 @@ Node cond;
 {
     Node event;
     Command action;
 {
     Node event;
     Command action;
+    Event e;
 
     if (op == O_TRACEI) {
        event = build(O_EQ, build(O_SYM, pcsym), place);
 
     if (op == O_TRACEI) {
        event = build(O_EQ, build(O_SYM, pcsym), place);
@@ -819,7 +963,10 @@ Node cond;
     if (cond != nil) {
        action = build(O_IF, cond, buildcmdlist(action));
     }
     if (cond != nil) {
        action = build(O_IF, cond, buildcmdlist(action));
     }
-    addevent(event, buildcmdlist(action));
+    e = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(e);
+    }
 }
 
 /*
 }
 
 /*
@@ -849,6 +996,7 @@ Node cond;
     Node event;
     Command action;
     Cmdlist actionlist;
     Node event;
     Command action;
     Cmdlist actionlist;
+    Event e;
 
     action = build(O_PRINTCALL, p);
     actionlist = list_alloc();
 
     action = build(O_PRINTCALL, p);
     actionlist = list_alloc();
@@ -860,7 +1008,10 @@ Node cond;
        actionlist = buildcmdlist(build(O_IF, cond, actionlist));
     }
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
        actionlist = buildcmdlist(build(O_IF, cond, actionlist));
     }
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
-    addevent(event, actionlist);
+    e = addevent(event, actionlist);
+    if (isstdin()) {
+       printevent(e);
+    }
 }
 
 /*
 }
 
 /*
@@ -877,6 +1028,9 @@ Node cond;
     Node event;
     Command action;
 
     Node event;
     Command action;
 
+    if (size(exp->nodetype) > MAXTRSIZE) {
+       error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
+    }
     p = (place == nil) ? tcontainer(exp) : place->value.sym;
     if (p == nil) {
        p = program;
     p = (place == nil) ? tcontainer(exp) : place->value.sym;
     if (p == nil) {
        p = program;
@@ -888,6 +1042,9 @@ Node cond;
     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
     action->value.trace.event = addevent(event, buildcmdlist(action));
     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
     action->value.trace.event = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(action->value.trace.event);
+    }
 }
 
 /*
 }
 
 /*
@@ -897,43 +1054,63 @@ Node cond;
 public stop(p)
 Node p;
 {
 public stop(p)
 Node p;
 {
-    Node exp, place, cond;
+    Node exp, place, cond, t;
     Symbol s;
     Command action;
     Symbol s;
     Command action;
+    Event e;
 
     exp = p->value.arg[0];
     place = p->value.arg[1];
     cond = p->value.arg[2];
     if (exp != nil) {
        stopvar(p->op, exp, place, cond);
 
     exp = p->value.arg[0];
     place = p->value.arg[1];
     cond = p->value.arg[2];
     if (exp != nil) {
        stopvar(p->op, exp, place, cond);
-    } else if (cond != nil) {
-       s = (place == nil) ? program : place->value.sym;
-       action = build(O_IF, cond, buildcmdlist(build(O_STOPX)));
-       action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action));
-       cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
-       action->value.trace.event = addevent(cond, buildcmdlist(action));
-    } else if (place->op == O_SYM) {
-       s = place->value.sym;
-       cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
-       addevent(cond, buildcmdlist(build(O_STOPX)));
     } else {
     } else {
-       stopinst(p->op, place, cond);
+       action = build(O_STOPX);
+       if (cond != nil) {
+           action = build(O_IF, cond, buildcmdlist(action));
+       }
+       if (place == nil or place->op == O_SYM) {
+           if (place == nil) {
+               s = program;
+           } else {
+               s = place->value.sym;
+           }
+           t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
+           if (cond != nil) {
+               action = build(O_TRACEON, (p->op == O_STOPI),
+                   buildcmdlist(action));
+               e = addevent(t, buildcmdlist(action));
+               action->value.trace.event = e;
+           } else {
+               e = addevent(t, buildcmdlist(action));
+           }
+           if (isstdin()) {
+               printevent(e);
+           }
+       } else {
+           stopinst(p->op, place, cond, action);
+       }
     }
 }
 
     }
 }
 
-private stopinst(op, place, cond)
+private stopinst(op, place, cond, action)
 Operator op;
 Node place;
 Node cond;
 Operator op;
 Node place;
 Node cond;
+Command action;
 {
     Node event;
 {
     Node event;
+    Event e;
 
     if (op == O_STOP) {
        event = build(O_EQ, build(O_SYM, linesym), place);
     } else {
        event = build(O_EQ, build(O_SYM, pcsym), place);
     }
 
     if (op == O_STOP) {
        event = build(O_EQ, build(O_SYM, linesym), place);
     } else {
        event = build(O_EQ, build(O_SYM, pcsym), place);
     }
-    addevent(event, buildcmdlist(build(O_STOPX)));
+    e = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(e);
+    }
 }
 
 /*
 }
 
 /*
@@ -951,14 +1128,31 @@ Node cond;
     Node event;
     Command action;
 
     Node event;
     Command action;
 
-    p = (place == nil) ? tcontainer(exp) : place->value.sym;
-    if (p == nil) {
-       p = program;
+    if (size(exp->nodetype) > MAXTRSIZE) {
+       error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
+    }
+    if (place == nil) {
+       if (exp->op == O_LCON) {
+           p = program;
+       } else {
+           p = tcontainer(exp);
+           if (p == nil) {
+               p = program;
+           }
+       }
+    } else {
+       p = place->value.sym;
+    }
+    action = build(O_STOPIFCHANGED, exp);
+    if (cond != nil) {
+       action = build(O_IF, cond, buildcmdlist(action));
     }
     }
-    action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp)));
     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
     action->value.trace.event = addevent(event, buildcmdlist(action));
     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
     action->value.trace.event = addevent(event, buildcmdlist(action));
+    if (isstdin()) {
+       printevent(action->value.trace.event);
+    }
 }
 
 /*
 }
 
 /*
@@ -970,102 +1164,166 @@ Node var;
 Node exp;
 {
     Address addr;
 Node exp;
 {
     Address addr;
-    int varsize;
+    integer varsize, expsize;
     char cvalue;
     short svalue;
     long lvalue;
     char cvalue;
     short svalue;
     long lvalue;
+    float fvalue;
 
 
-    if (not compatible(var->nodetype, exp->nodetype)) {
-       error("incompatible types");
+    if (var->op == O_SYM and regnum(var->value.sym) != -1) {
+       eval(exp);
+       setreg(regnum(var->value.sym), pop(Address));
+    } else {
+       addr = lval(var);
+       varsize = size(var->nodetype);
+       expsize = size(exp->nodetype);
+       eval(exp);
+       if (varsize == sizeof(float) and expsize == sizeof(double)) {
+           fvalue = (float) pop(double);
+           dwrite(&fvalue, addr, sizeof(fvalue));
+       } else {
+           if (varsize < sizeof(long)) {
+               lvalue = 0;
+               popn(expsize, &lvalue);
+               if (varsize == sizeof(char)) {
+                   cvalue = lvalue;
+                   dwrite(&cvalue, addr, sizeof(cvalue));
+               } else if (varsize == sizeof(short)) {
+                   svalue = lvalue;
+                   dwrite(&svalue, addr, sizeof(svalue));
+               } else {
+                   error("[internal error: bad size %d in assign]", varsize);
+               }
+           } else {
+               if (expsize <= varsize) {
+                   sp -= expsize;
+                   dwrite(sp, addr, expsize);
+               } else {
+                   sp -= expsize;
+                   dwrite(sp, addr, varsize);
+               }
+           }
+       }
     }
     }
-    addr = lval(var);
-    eval(exp);
-    varsize = size(var->nodetype);
-    if (varsize < sizeof(long)) {
-       lvalue = pop(long);
-       switch (varsize) {
-           case sizeof(char):
-               cvalue = lvalue;
-               dwrite(&cvalue, addr, varsize);
-               break;
-
-           case sizeof(short):
-               svalue = lvalue;
-               dwrite(&svalue, addr, varsize);
-               break;
-
-           default:
-               panic("bad size %d", varsize);
+}
+
+/*
+ * Set a debugger variable.
+ */
+
+private set (var, exp)
+Node var, exp;
+{
+    Symbol t;
+
+    if (var == nil) {
+       defvar(nil, nil);
+    } else if (exp == nil) {
+       defvar(var->value.name, nil);
+    } else if (var->value.name == identname("$frame", true)) {
+       t = exp->nodetype;
+       if (not compatible(t, t_int) and not compatible(t, t_addr)) {
+           error("$frame must be an address");
        }
        }
+       eval(exp);
+       getnewregs(pop(Address));
     } else {
     } else {
-       sp -= varsize;
-       dwrite(sp, addr, varsize);
+       defvar(var->value.name, unrval(exp));
     }
 }
 
     }
 }
 
-#define DEF_EDITOR  "vi"
-
 /*
 /*
- * Invoke an editor on the given file.  Which editor to use might change
- * installation to installation.  For now, we use "vi".  In any event,
- * the environment variable "EDITOR" overrides any default.
+ * Execute a list command.
  */
 
  */
 
-public edit(filename)
-String filename;
+private list (p)
+Node p;
 {
 {
-    extern String getenv();
-    String ed, src;
-    File f;
-    Symbol s;
+    Symbol f;
     Address addr;
     Address addr;
-    char buff[10];
+    Lineno line, l1, l2;
 
 
-    ed = getenv("EDITOR");
-    if (ed == nil) {
-       ed = DEF_EDITOR;
+    if (p->value.arg[0]->op == O_SYM) {
+       f = p->value.arg[0]->value.sym;
+       addr = firstline(f);
+       if (addr == NOADDR) {
+           error("no source lines for \"%s\"", symname(f));
+       }
+       setsource(srcfilename(addr));
+       line = srcline(addr);
+       getsrcwindow(line, &l1, &l2);
+    } else {
+       eval(p->value.arg[0]);
+       l1 = (Lineno) (pop(long));
+       eval(p->value.arg[1]);
+       l2 = (Lineno) (pop(long));
     }
     }
-    if (filename == nil) {
-       call(ed, stdin, stdout, cursource, nil);
+    printlines(l1, l2);
+}
+
+/*
+ * Execute a func command.
+ */
+
+private func (p)
+Node p;
+{
+    Symbol s, f;
+    Address addr;
+
+    if (p == nil) {
+       printname(stdout, curfunc);
+       putchar('\n');
     } else {
     } else {
-       f = fopen(filename, "r");
-       if (f == nil) {
-           s = which(identname(filename, true));
-           if (not isblock(s)) {
-               error("can't read \"%s\"", filename);
-           }
-           addr = firstline(s);
-           if (addr == NOADDR) {
-               error("no source for \"%s\"", filename);
-           }
-           src = srcfilename(addr);
-           sprintf(buff, "+%d", srcline(addr));
-           call(ed, stdin, stdout, buff, src, nil);
+       s = p->value.sym;
+       if (isroutine(s)) {
+           setcurfunc(s);
        } else {
        } else {
-           fclose(f);
-           call(ed, stdin, stdout, filename, nil);
+           find(f, s->name) where isroutine(f) endfind(f);
+           if (f == nil) {
+               error("%s is not a procedure or function", symname(s));
+           }
+           setcurfunc(f);
+       }
+       addr = codeloc(curfunc);
+       if (addr != NOADDR) {
+           setsource(srcfilename(addr));
+           cursrcline = srcline(addr);
        }
     }
 }
 
 /*
        }
     }
 }
 
 /*
- * Send some nasty mail to the current support person.
+ * Send a message to the current support person.
  */
 
 public gripe()
 {
     typedef Operation();
     Operation *old;
  */
 
 public gripe()
 {
     typedef Operation();
     Operation *old;
-
-    char *maintainer = "linton@ucbarpa";
-
-    puts("Type control-D to end your message.  Be sure to include");
-    puts("your name and the name of the file you are debugging.");
-    putchar('\n');
-    old = signal(SIGINT, SIG_DFL);
-    call("Mail", stdin, stdout, maintainer, nil);
-    signal(SIGINT, old);
-    puts("Thank you.");
+    int pid, status;
+    extern int versionNumber;
+    char subject[100];
+
+#   ifdef MAINTAINER
+       puts("Type control-D to end your message.  Be sure to include");
+       puts("your name and the name of the file you are debugging.");
+       putchar('\n');
+       old = signal(SIGINT, SIG_DFL);
+       sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
+       pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
+       signal(SIGINT, SIG_IGN);
+       pwait(pid, &status);
+       signal(SIGINT, old);
+       if (status == 0) {
+           puts("Thank you.");
+       } else {
+           puts("\nMail not sent.");
+       }
+#   else
+       puts("Sorry, no dbx maintainer available to gripe to.");
+       puts("Try contacting your system manager.");
+#   endif
 }
 
 /*
 }
 
 /*
@@ -1075,6 +1333,10 @@ public gripe()
 public help()
 {
     puts("run                    - begin execution of the program");
 public help()
 {
     puts("run                    - begin execution of the program");
+    puts("print <exp>            - print the value of the expression");
+    puts("where                  - print currently active procedures");
+    puts("stop at <line>         - suspend execution at the line");
+    puts("stop in <proc>         - suspend execution when <proc> is called");
     puts("cont                   - continue execution");
     puts("step                   - single step one line");
     puts("next                   - step to next line (skip over calls)");
     puts("cont                   - continue execution");
     puts("step                   - single step one line");
     puts("next                   - step to next line (skip over calls)");
@@ -1082,16 +1344,11 @@ public help()
     puts("trace <proc>           - trace calls to the procedure");
     puts("trace <var>            - trace changes to the variable");
     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
     puts("trace <proc>           - trace calls to the procedure");
     puts("trace <var>            - trace changes to the variable");
     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
-    puts("stop at <line>         - suspend execution at the line");
-    puts("stop in <proc>         - suspend execution when <proc> is called");
     puts("status                 - print trace/stop's in effect");
     puts("delete <number>        - remove trace or stop of given number");
     puts("status                 - print trace/stop's in effect");
     puts("delete <number>        - remove trace or stop of given number");
-    puts("call <proc>            - call the procedure");
-    puts("where                  - print currently active procedures");
-    puts("print <exp>            - print the value of the expression");
+    puts("call <proc>            - call a procedure in program");
     puts("whatis <name>          - print the declaration of the name");
     puts("list <line>, <line>    - list source lines");
     puts("whatis <name>          - print the declaration of the name");
     puts("list <line>, <line>    - list source lines");
-    puts("edit <proc>            - edit file containing <proc>");
     puts("gripe                  - send mail to the person in charge of dbx");
     puts("quit                   - exit dbx");
 }
     puts("gripe                  - send mail to the person in charge of dbx");
     puts("quit                   - exit dbx");
 }