Initial version
authorceriel <none@none>
Fri, 31 Aug 1990 18:22:53 +0000 (18:22 +0000)
committerceriel <none@none>
Fri, 31 Aug 1990 18:22:53 +0000 (18:22 +0000)
53 files changed:
util/grind/Amakefile [new file with mode: 0644]
util/grind/LLgen.amk [new file with mode: 0644]
util/grind/PROBLEMS [new file with mode: 0644]
util/grind/READ_ME [new file with mode: 0644]
util/grind/ack-defs.amk [new file with mode: 0644]
util/grind/avl.cc [new file with mode: 0644]
util/grind/avl.h [new file with mode: 0644]
util/grind/cc_hh_tools.amk [new file with mode: 0644]
util/grind/char.ct [new file with mode: 0644]
util/grind/char_tools.amk [new file with mode: 0644]
util/grind/class.h [new file with mode: 0644]
util/grind/commands.g [new file with mode: 0644]
util/grind/dbx_string.g [new file with mode: 0644]
util/grind/dbxread.c [new file with mode: 0644]
util/grind/dump.c [new file with mode: 0644]
util/grind/expr.c [new file with mode: 0644]
util/grind/file.hh [new file with mode: 0644]
util/grind/idf.c [new file with mode: 0644]
util/grind/idf.h [new file with mode: 0644]
util/grind/itemlist.cc [new file with mode: 0644]
util/grind/langdep.cc [new file with mode: 0644]
util/grind/langdep.h [new file with mode: 0644]
util/grind/list.c [new file with mode: 0644]
util/grind/main.c [new file with mode: 0644]
util/grind/make.allocd [new file with mode: 0755]
util/grind/make.next [new file with mode: 0755]
util/grind/make.ops [new file with mode: 0755]
util/grind/make.tokcase [new file with mode: 0755]
util/grind/make.tokfile [new file with mode: 0755]
util/grind/message.h [new file with mode: 0644]
util/grind/modula-2.c [new file with mode: 0644]
util/grind/op_tools.amk [new file with mode: 0644]
util/grind/operator.h [new file with mode: 0644]
util/grind/operators.ot [new file with mode: 0644]
util/grind/position.c [new file with mode: 0644]
util/grind/position.h [new file with mode: 0644]
util/grind/print.c [new file with mode: 0644]
util/grind/rd.c [new file with mode: 0644]
util/grind/rd.h [new file with mode: 0644]
util/grind/run.c [new file with mode: 0644]
util/grind/scope.cc [new file with mode: 0644]
util/grind/scope.h [new file with mode: 0644]
util/grind/sizes.h [new file with mode: 0644]
util/grind/symbol.c [new file with mode: 0644]
util/grind/symbol.hh [new file with mode: 0644]
util/grind/tok_tools.amk [new file with mode: 0644]
util/grind/tokenname.c [new file with mode: 0644]
util/grind/tokenname.h [new file with mode: 0644]
util/grind/tree.c [new file with mode: 0644]
util/grind/tree.hh [new file with mode: 0644]
util/grind/type.c [new file with mode: 0644]
util/grind/type.hh [new file with mode: 0644]
util/grind/value.c [new file with mode: 0644]

diff --git a/util/grind/Amakefile b/util/grind/Amakefile
new file mode 100644 (file)
index 0000000..d88c245
--- /dev/null
@@ -0,0 +1,141 @@
+AMAKELIB = { . , /usr/local/lib/amake } ;
+
+%include ack-defs.amk ;
+%include common.amk ;
+%include cc_hh_tools.amk ;
+%include tok_tools.amk ;
+%include op_tools.amk ;
+%include char_tools.amk ;
+%include LLgen.amk ;
+%include cc-c.amk ;
+%include loader.amk ;
+%include lint.amk ;
+
+%default grind ;
+
+TOKENNAMES = tokenname.c [
+       gen_tokens,
+       cc-dest = symbol2str.c,
+       LL-dest = tokenfile.g
+];
+
+DBS_LLTARGETS = {
+       dbx_string.c[type=C-src],
+       DBSpars.c[type=C-src],
+       DBSpars.h[type=C-incl]
+} ;
+
+DBS_LLSRC = {
+       dbx_string.g
+} ;
+
+CMD_LLTARGETS = {
+       tokenfile.c[type=C-src],
+       commands.c[type=C-src],
+       Lpars.c[type=C-src],
+       Lpars.h[type=C-incl]
+} ;
+
+CMD_LLSRC = {
+       tokenname.c,
+       commands.g
+} ;
+
+GENNEXTSRC = {
+       file.h[type=C-incl],
+       next.c[type=C-src]
+} ;
+
+CSRC = {
+       dbxread.c,
+       main.c,
+       list.c,
+       tree.c,
+       expr.c,
+       position.c,
+       idf.c,
+       run.c,
+       dump.c,
+       symbol.c,
+       print.c,
+       value.c,
+       type.c,
+       rd.c,
+       modula-2.c
+} ;
+
+HSRC = {
+       tokenname.h,
+       operator.h,
+       class.h,
+       position.h,
+       idf.h,
+       message.h,
+       avl.h,
+       scope.h,
+       langdep.h,
+       sizes.h,
+       rd.h
+} ;
+
+HHSRC = {
+       file.hh,
+       type.hh,
+       symbol.hh,
+       tree.hh,
+       avl.cc,
+       scope.cc,
+       itemlist.cc,
+       langdep.cc
+} ;
+
+LIBRARIES = {
+       $EMHOME/modules/lib/libassert.a,
+       $EMHOME/modules/lib/liballoc.a,
+       $EMHOME/modules/lib/malloc.o,
+       $EMHOME/modules/lib/libstring.a,
+       $EMHOME/modules/lib/libobject.a,
+       $EMHOME/modules/lib/libsystem.a
+} ;
+
+DBFLAGS = { -g, -DDEBUG } ;
+PROFFLAGS = { } ;
+
+LDFLAGS = {
+       -Bstatic,
+       $PROFFLAGS,
+       $DBFLAGS
+} ;
+
+INCLUDES = {
+       -I$EMHOME/modules/h,
+       -I$EMHOME/modules/pkg,
+       -I$EMHOME/h
+} ;
+
+CFLAGS = {
+       $INCLUDES,
+       $PROFFLAGS,
+       $DBFLAGS
+} ;
+
+LINTFLAGS = {
+       $INCLUDES
+} ;
+
+%cluster {
+       %targets $DBS_LLTARGETS ;
+       %sources $DBS_LLSRC ;
+       %use LLgen(prefix => DBS) ;
+} ;
+
+%cluster {
+       %targets lint.out[type = lint-output];
+       %sources $CMD_LLSRC + $CSRC + $DBS_LLTARGETS + $HHSRC + char.ct + operators.ot ;
+       %use lint(realdest => lint.out) ;
+} ;
+
+%cluster {
+       %targets grind[type = program];
+       %sources $CMD_LLSRC + $CSRC + $DBS_LLTARGETS + $HHSRC + char.ct + operators.ot ;
+} ;
diff --git a/util/grind/LLgen.amk b/util/grind/LLgen.amk
new file mode 100644 (file)
index 0000000..768791b
--- /dev/null
@@ -0,0 +1,40 @@
+# LLgen:       LL(1) parser generator
+# variables:   LLGEN, LLFLAGS
+
+# tool definition for the new version of LLgen that allows for more than
+# one parser in one program. Unfortunately, for historical reasons there
+# is no proper default prefix for LLgen-generated files (LL.output versus
+# Lpars.[ch]). If LLgen would generate LLpars.[ch] instead of Lpars.[ch],
+# we could have a default value for prefix of 'LL', which would make
+# things a bit more simple.
+
+%instance deftypesuffix(LLgen-src, '%.g') ;
+
+%include ack-defs.amk;
+
+%if (%not defined(LLGEN), {
+    LLGEN = $EMHOME/bin/LLgen;
+});
+
+%if (%not defined(LLFLAGS), {
+    LLFLAGS = {};
+});
+
+%tool LLgen (
+    verbose: %boolean                    => %false;
+    flags:   %string %list               => $LLFLAGS;
+    prefix:  %string                     => '';
+    src:     %in %list  [type = LLgen-src];
+    parser:  %out %list [type = C-src]
+       => match($src) + if($prefix == '', Lpars.c, $prefix'pars.c');
+    tokens:  %out      [type = C-incl, compare]
+       => if($prefix == '', Lpars.h, $prefix'pars.h');
+    diagn:   %out      [type = text]
+       => if($prefix == '', LL.output, $prefix.output) %conform $verbose;
+    cmd:     %in      [type = command]    => $LLGEN;
+)
+{
+    exec($cmd, args => if($verbose, {'-vvv'}, {}) + $flags + $src);
+    echo({'LLgen ', $src, ' done'});
+};
+
diff --git a/util/grind/PROBLEMS b/util/grind/PROBLEMS
new file mode 100644 (file)
index 0000000..65e9242
--- /dev/null
@@ -0,0 +1,6 @@
+- front-end cannot generate DBX symbol table information for bit-fields,
+  because it does not know about byte-order.
+- single stepping on a line by line basis is difficult if you use breakpoints.
+  The problem is where to set the next breakpoint. One solution is to use
+  single-stepping until we are at a different line, but this is probably
+  extremely slow. Another solution is to adapt edb's method.
diff --git a/util/grind/READ_ME b/util/grind/READ_ME
new file mode 100644 (file)
index 0000000..7db04f5
--- /dev/null
@@ -0,0 +1,3 @@
+This is GRIND (GRind Is Not Dbx). This program is still being developed,
+so behaviour may change without notice.
+
diff --git a/util/grind/ack-defs.amk b/util/grind/ack-defs.amk
new file mode 100644 (file)
index 0000000..0357a29
--- /dev/null
@@ -0,0 +1,5 @@
+# definition of EMHOME
+
+%if (%not defined(EMHOME), {
+    EMHOME = /usr/proj/em/Work;
+});
diff --git a/util/grind/avl.cc b/util/grind/avl.cc
new file mode 100644 (file)
index 0000000..a97d587
--- /dev/null
@@ -0,0 +1,245 @@
+/* $Header$ */
+
+#include <alloc.h>
+
+/* Implementation of AVL-trees: trees in which the difference in depth
+   of the left branch and the right branch is at most one.
+   The difference in depth is indicated by a "balance" flag in each node:
+   this flag has one of three values:
+   .   indicating that the left branch has the same depth as the right branch,
+   +   indicating that the right branch is deeper,
+   -   indicating that the left branch is deeper.
+   So, a node has the following structure:
+*/
+
+struct avl_node {
+  struct avl_node
+               *left,
+               *right;         /* the left and right branches */
+  char         *info;          /* pointer to information in this node */
+  char         balance;        /* balance information described above */
+};
+
+/* create definitions for new_avl_node() and free_avl_node() */
+/* STATICALLOCDEF "avl_node" 10 */
+
+/* There is also a tree header, which contains the root of the tree and
+   the address of a user-supplied comparison routine:
+*/
+
+struct avl_tree {
+  struct avl_node
+               *root;          /* root of the avl tree */
+  int          (*cmp)();       /* address of comparison routine */
+};
+/* create definitions for new_avl_tree() and free_avl_tree() */
+/* STATICALLOCDEF "avl_tree" 2 */
+
+/* The next routine adds a node to an avl tree. It returns 1 if the
+   tree got deeper.
+*/
+static int
+balance_add(ppsc, n, cmp)
+  struct avl_node **ppsc;      /* address of root */
+  register char *n;            /* user-supplied information */
+  int (*cmp)();                        /* user-supplied comparison routine */
+{
+  register struct avl_node *psc = *ppsc, *qsc, *ssc;
+
+  if (! psc) {
+       *ppsc = new_avl_node();
+       (*ppsc)->balance = '.';
+       (*ppsc)->info = n;
+       return 1;
+  }
+  if ((*cmp)(n, psc->info) < 0) {
+       if (balance_add(&(psc->left), n, cmp)) {
+               /* left hand side got deeper */
+               if (psc->balance == '+') {
+                       /* but the right hand side was deeper */
+                       psc->balance = '.';
+                       return 0;
+               }
+               if (psc->balance == '.') {
+                       /* but the right hand side was as deep */
+                       psc->balance = '-';
+                       return 1;
+               }
+               /* left hand side already was one deeper; re-organize */
+               qsc = psc->left;
+               if (qsc->balance == '-') {
+                       /* if left-hand side of left node was deeper,
+                          this node becomes the new root
+                       */
+                       psc->balance = '.';
+                       qsc->balance = '.';
+                       psc->left = qsc->right;
+                       qsc->right = psc;
+                       *ppsc = qsc;
+                       return 0;
+               }
+               /* else the right node of the left node becomes the new root */
+               ssc = qsc->right;
+               psc->left = ssc->right;
+               qsc->right = ssc->left;
+               ssc->left = qsc;
+               ssc->right = psc;
+               *ppsc = ssc;
+               if (ssc->balance == '.') {
+                       psc->balance = '.';
+                       qsc->balance = '.';
+                       return 0;
+               }
+               if (ssc->balance == '-') {
+                       psc->balance = '+';
+                       qsc->balance = '.';
+                       ssc->balance = '.';
+                       return 0;
+               }
+               psc->balance = '.';
+               qsc->balance = '-';
+       }
+       return 0;
+  }
+  if (balance_add(&(psc->right), n, cmp)) {
+       /* right hand side got deeper */
+       if (psc->balance == '-') {
+               /* but the left hand side was deeper */
+               psc->balance = '.';
+               return 0;
+       }
+       if (psc->balance == '.') {
+               /* but the left hand side as deep */
+               psc->balance = '+';
+               return 1;
+       }
+       /* right hand side already was one deeper; re-organize */
+       qsc = psc->right;
+       if (qsc->balance == '+') {
+               /* if right-hand side of left node was deeper,
+                  this node becomes the new root
+               */
+               psc->balance = '.';
+               qsc->balance = '.';
+               psc->right = qsc->left;
+               qsc->left = psc;
+               *ppsc = qsc;
+               return 0;
+       }
+       /* else the left node of the right node becomes the new root */
+       ssc = qsc->left;
+       psc->right = ssc->left;
+       qsc->left = ssc->right;
+       ssc->right = qsc;
+       ssc->left = psc;
+       *ppsc = ssc;
+       if (ssc->balance == '.') {
+               psc->balance = '.';
+               qsc->balance = '.';
+               return 0;
+       }
+       if (ssc->balance == '+') {
+               psc->balance = '-';
+               qsc->balance = '.';
+               ssc->balance = '.';
+               return 0;
+       }
+       psc->balance = '.';
+       qsc->balance = '+';
+  }
+  return 0;
+}
+
+/* extern struct avl_tree *create_avl_tree(int (*cmp)());
+   Returns a fresh avl_tree structure.
+*/
+struct avl_tree *
+create_avl_tree(cmp)
+  int  (*cmp)();               /* comparison routine */
+{
+  register struct avl_tree *p = new_avl_tree();
+
+  p->cmp = cmp;
+  return p;
+}
+
+/* extern add_to_avl_tree(struct avl_tree *tree, char *n);
+   Adds the information indicated by 'n' to the avl_tree indicated by 'tree'
+*/
+add_to_avl_tree(tree, n)
+  struct avl_tree      *tree;  /* tree to be added to */
+  char                 *n;     /* information */
+{
+  balance_add(&(tree->root), n, tree->cmp);
+}
+
+/* extern char *find_ngt(struct avl_tree *tree, char *n);
+   Returns the information in the largest node that still compares <= to 'n',
+   or 0 if not present.
+*/
+char *
+find_ngt(tree, n)
+  struct avl_tree      *tree;  /* tree to be searched in */
+  char                 *n;     /* information to be compared with */
+{
+  register struct avl_node *nd = tree->root, *lastnd = 0;
+
+  for (;;) {
+       while (nd && (*tree->cmp)(nd->info, n) > 0) {
+               nd = nd->left;
+       }
+       while (nd && (*tree->cmp)(nd->info, n) <= 0) {
+               lastnd = nd;
+               nd = nd->right;
+       }
+       if (! nd) break;
+  }
+  return lastnd ? lastnd->info : (char *) 0;
+}
+
+/* extern char *find_nlt(struct avl_tree *tree, char *n);
+   Returns the information in the largest node that still compares >= to 'n',
+   or 0 if not present.
+*/
+char *
+find_nlt(tree, n)
+  struct avl_tree      *tree;  /* tree to be searched in */
+  char                 *n;     /* information to be compared with */
+{
+  register struct avl_node *nd = tree->root, *lastnd = 0;
+
+  for (;;) {
+       while (nd && (*tree->cmp)(nd->info, n) < 0) {
+               nd = nd->right;
+       }
+       while (nd && (*tree->cmp)(nd->info, n) >= 0) {
+               lastnd = nd;
+               nd = nd->left;
+       }
+       if (! nd) break;
+  }
+  return lastnd ? lastnd->info : (char *) 0;
+}
+
+/* extern char *find_eq(struct avl_tree *tree, char *n);
+   Returns the information in the node that compares equal to 'n',
+   or 0 if not present.
+*/
+char *
+find_eq(tree, n)
+  struct avl_tree      *tree;  /* tree to be searched in */
+  char                 *n;     /* information to be compared with */
+{
+  register struct avl_node *nd = tree->root;
+
+  for (;;) {
+       while (nd && (*tree->cmp)(nd->info, n) < 0) {
+               nd = nd->right;
+       }
+       while (nd && (*tree->cmp)(nd->info, n) > 0) {
+               nd = nd->left;
+       }
+       if (! nd) break;
+  }
+  return nd ? nd->info : (char *) 0;
+}
diff --git a/util/grind/avl.h b/util/grind/avl.h
new file mode 100644 (file)
index 0000000..7cbc802
--- /dev/null
@@ -0,0 +1,43 @@
+/* $Header$ */
+
+/* AVL-trees: trees in which the difference in depth
+   of the left branch and the right branch is at most one.
+   Information in the nodes is represented by a pointer, which is to
+   be supplied by the user. The user is also expected to supply a
+   comparison routine for each AVL tree. This routine is offered two
+   parameters, both pointers, and is expected to return:
+   a negative number   if the comparison result is <
+   0                   if the comparison result is =
+   a positive number   if the comparison result is >
+*/
+
+typedef struct avl_tree        *AVL_tree;
+
+/* extern AVL_tree create_avl_tree(int (*cmp)());
+   Returns a fresh avl_tree structure. 'cmp' will be used as comparison
+   routine for this tree.
+*/
+extern AVL_tree create_avl_tree();
+
+/* extern add_to_avl_tree(AVL_tree tree, char *n);
+   Adds the information indicated by 'n' to the avl_tree indicated by 'tree'.
+*/
+extern add_to_avl_tree();
+
+/* extern char *find_ngt(AVL_tree tree, char *n);
+   Returns the information in the largest node that still compares <= to 'n',
+   or 0 if not present.
+*/
+extern char *find_ngt();
+
+/* extern char *find_nlt(AVL_tree tree, char *n);
+   Returns the information in the largest node that still compares >= to 'n',
+   or 0 if not present.
+*/
+extern char *find_nlt();
+
+/* extern char *find_eq(AVL_tree tree, char *n);
+   Returns the information in the node that compares equal to 'n',
+   or 0 if not present.
+*/
+extern char *find_eq();
diff --git a/util/grind/cc_hh_tools.amk b/util/grind/cc_hh_tools.amk
new file mode 100644 (file)
index 0000000..e03ee52
--- /dev/null
@@ -0,0 +1,43 @@
+%instance deftypesuffix(hh-src, '%.hh') ;
+%instance deftypesuffix(cc-src, '%.cc') ;
+
+ALLOCD = make.allocd;
+NEXT = make.next;
+
+%tool allochd (
+    hhsrc:     %in [type = hh-src, persistent];
+    hsrc:      %out [type = C-incl]    => match($hhsrc);
+    prog:      %in [type = command]    => $ALLOCD;
+)
+{
+    exec($prog, stdin => $hhsrc, stdout => $hsrc);
+    echo({$hsrc ,'created'});
+};
+
+
+%tool alloccd (
+    ccsrc:     %in [type = cc-src, persistent];
+    csrc:      %out [type = C-src]     => match($ccsrc);
+    prog:      %in [type = command]    => $ALLOCD;
+)
+{
+    exec($prog, stdin => $ccsrc, stdout => $csrc);
+    echo({$csrc ,'created'});
+};
+
+
+# Possibly there's only one type of { cc-src, hh-src } available,
+# so introduce a new attribute.
+
+%derive f[cc-or-hh-src] %when get($f, type) == cc-src
+                       %or   get($f, type) == hh-src;
+
+%tool mknext (
+    cchhsrc:   %in %list [cc-or-hh-src];
+    next:      %out [type = C-src]     => next.c;
+    prog:      %in [type = command]    => $NEXT;
+)
+{
+    exec($prog, args => $cchhsrc, stdout => $next);
+    echo({$next ,'created'});
+};
diff --git a/util/grind/char.ct b/util/grind/char.ct
new file mode 100644 (file)
index 0000000..21a4fba
--- /dev/null
@@ -0,0 +1,71 @@
+% character tables for debugger
+% $Header$
+%S257
+%F     %s,
+%
+%      CHARACTER CLASSES
+%
+%iSTGARB
+STSKIP: \t\013\014\015
+STNL:;\012
+STIDF:a-zA-Z_$
+STSTR:"'
+STDOT:.
+STNUM:0-9
+STSIMP:,<>{}:`
+%T#include "class.h"
+%Tchar tkclass[] = {
+%p
+%T};
+%
+%      INIDF
+%
+%S129
+%C
+1:a-zA-Z0-9_$
+%Tchar inidf[] = {
+%F     %s,
+%p
+%T};
+%
+%      INEXT
+%
+%S129
+%C
+1:-#+{}~`@%^=|\\;:?/,a-zA-Z0-9_$.
+%Tchar inext[] = {
+%F     %s,
+%p
+%T};
+%
+%      ISDIG
+%
+%C
+1:0-9
+%Tchar isdig[] = {
+%p
+%T};
+%
+%      ISHEX
+%
+%C
+1:A-F0-9
+%Tchar ishex[] = {
+%p
+%T};
+%
+%      ISOCT
+%
+%C
+1:0-7
+%Tchar isoct[] = {
+%p
+%T};
+%
+%      ISTOKEN
+%
+%C
+1:-abcefiprstuvxAEFGLMPQSTVX,;:+=()*
+%T char istoken[] = {
+%p
+%T};
diff --git a/util/grind/char_tools.amk b/util/grind/char_tools.amk
new file mode 100644 (file)
index 0000000..9126a01
--- /dev/null
@@ -0,0 +1,24 @@
+# tabgen: tool definition for character table generator
+# variables:   TABGEN, CHTAB
+
+%include ack-defs.amk;
+
+%if (%not defined(TABGEN), {
+    TABGEN = $EMHOME/bin/tabgen;
+});
+
+%if (%not defined(CHTAB), {
+    CHTAB = chtab.c;
+});
+
+%instance deftypesuffix(char_tab, '%.ct');
+
+%tool gen_tab (
+    chtab:     %in [type = char_tab];
+    cfile:     %out [type = C-src]     => $CHTAB;
+    mktab:     %in [type = command]    => $TABGEN;
+)
+{
+    exec($mktab, args => '-f' $chtab, stdout => $cfile);
+    echo({$cfile, 'created'});
+};
diff --git a/util/grind/class.h b/util/grind/class.h
new file mode 100644 (file)
index 0000000..06f407a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ * Author: Ceriel J.H. Jacobs
+ */
+
+/* U S E   O F   C H A R A C T E R   C L A S S E S */
+
+/* $Header$ */
+
+/*     As a starter, chars are divided into classes, according to which
+       token they can be the start of.
+       At present such a class number is supposed to fit in 4 bits.
+*/
+
+#define        class(ch)       (tkclass[ch])
+
+/*     Being the start of a token is, fortunately, a mutual exclusive
+       property, so, as there are less than 16 classes they can be
+       packed in 4 bits.
+*/
+
+#define        STSKIP  0       /* spaces and so on: skipped characters         */
+#define        STNL    1       /* newline character(s): update linenumber etc. */
+#define        STGARB  2       /* garbage ascii character: not allowed         */
+#define        STDOT   3       /* '.' can start a number, or be a separate token */
+#define        STCOMP  4       /* this one can start a compound token          */
+#define        STIDF   5       /* being the initial character of an identifier */
+#define        STCHAR  6       /* the starter of a character constant          */
+#define        STSTR   7       /* the starter of a string                      */
+#define        STNUM   8       /* the starter of a numeric constant            */
+#define        STEOI   9       /* End-Of-Information mark                      */
+#define STSIMP  10      /* this character can occur as token            */
+
+/*     But occurring inside a token is not, so we need 1 bit for each
+       class.  This is implemented as a collection of tables to speed up
+       the decision whether a character has a special meaning.
+*/
+#define        in_idf(ch)      ((unsigned)ch < 0177 && inidf[ch])
+#define        in_ext(ch)      ((unsigned)ch < 0177 && inext[ch])
+#define        is_oct(ch)      ((unsigned)ch < 0177 && isoct[ch])
+#define        is_dig(ch)      ((unsigned)ch < 0177 && isdig[ch])
+#define        is_hex(ch)      ((unsigned)ch < 0177 && ishex[ch])
+#define        is_token(ch)    ((unsigned)ch < 0177 && istoken[ch])
+
+extern char tkclass[];
+extern char inidf[], isoct[], isdig[], ishex[], inext[], istoken[];
diff --git a/util/grind/commands.g b/util/grind/commands.g
new file mode 100644 (file)
index 0000000..aa86944
--- /dev/null
@@ -0,0 +1,590 @@
+/* $Header$ */
+
+/* Command grammar */
+{
+#include       <stdio.h>
+#include       <alloc.h>
+#include       <setjmp.h>
+#include       <signal.h>
+
+#include       "ops.h"
+#include       "class.h"
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+#include       "symbol.h"
+#include       "tree.h"
+
+extern char    *Salloc();
+extern t_lineno        currline;
+extern FILE    *db_in;
+
+int            errorgiven;
+int            extended_charset = 0;
+jmp_buf                jmpbuf;
+
+static int     init_del();
+static int     skip_to_eol();
+
+static struct token {
+  int  tokno;
+  long ival;
+  char *str;
+  double fval;
+  struct idf *idf;
+} tok, aside;
+
+#define TOK    tok.tokno
+#define ASIDE  aside.tokno
+}
+%start Commands, commands;
+
+%lexical LLlex;
+
+commands
+  { p_tree com, lastcom = 0;
+  }
+:
+                       { if (! setjmp(jmpbuf)) {
+                               init_del();
+                         }
+                         else {
+                               skip_to_eol();
+                               goto prmpt;
+                         }
+                       }
+  [ %persistent command_line(&com)
+                       { if (com) {
+                               if (errorgiven) {
+                                       freenode(com);
+                                       com = 0;
+                               }
+                               if (lastcom && !in_status(lastcom) &&
+                                   lastcom != run_command) {
+                                       freenode(lastcom);
+                                       lastcom = 0;
+                               }
+
+                               if (com) {
+                                       if (repeatable(com)) {
+                                               lastcom = com;
+                                       }
+                                       eval(com);
+                                       if (! repeatable(com) &&
+                                           ! in_status(com) &&
+                                           com != run_command) {
+                                               freenode(com);
+                                       }
+                               }
+                         } else if (lastcom && ! errorgiven) eval(lastcom);
+                       }
+    [  '\n'            { prmpt: prompt(); }
+    |  ';'
+    ]                  { errorgiven = 0; }
+  ]*
+                       { signal_child(SIGKILL); }
+;
+
+command_line(p_tree *p;)
+:
+  list_command(p)
+| file_command(p)
+| run_command(p)
+| stop_command(p)
+| when_command(p)
+| continue_command(p)
+| step_command(p)
+| next_command(p)
+| regs_command(p)
+| WHERE                        { *p = mknode(OP_WHERE); }
+| STATUS               { *p = mknode(OP_STATUS); }
+| DUMP                 { *p = mknode(OP_DUMP); }
+| RESTORE INTEGER      { *p = mknode(OP_RESTORE, tok.ival); }
+| delete_command(p)
+| print_command(p)
+| trace_command(p)
+|                      { *p = 0; }
+;
+
+list_command(p_tree *p;)
+  { p_tree t1 = 0, t2 = 0; }
+:
+  LIST
+  [
+  | lin_num(&t1)
+    [ ',' lin_num(&t2)
+    |                  { t2 = mknode(OP_INTEGER, t1->t_ival); }
+    ]
+  ]                    { *p = mknode(OP_LIST, t1, t2); }
+;
+
+file_command(p_tree *p;)
+:
+  XFILE                        { extended_charset = 1; }
+  [                    { *p = 0; }
+  | name(p)            { (*p)->t_idf = str2idf((*p)->t_str, 0); }
+  ]                    { *p = mknode(OP_FILE, *p);
+                         extended_charset = 0;
+                       }
+;
+
+run_command(p_tree *p;)
+:
+  RUN                  { extended_charset = 1; *p = 0; }
+  args(p)              { *p = mknode(OP_RUN, *p);
+                         extended_charset = 0;
+                         freenode(run_command);
+                         run_command = *p;
+                       }
+| RERUN                        { if (! run_command) {
+                               error("no run command given yet");
+                         }
+                         else *p = run_command;
+                       }
+;
+
+stop_command(p_tree *p;)
+  { p_tree whr = 0, cond = 0; }
+:
+  STOP
+  where(&whr)?
+  condition(&cond)?    { if (! whr && ! cond) {
+                               error("no position or condition");
+                               *p = 0;
+                         }
+                         else *p = mknode(OP_STOP, whr, cond);
+                       }
+;
+
+trace_command(p_tree *p;)
+  { p_tree whr = 0, cond = 0, exp = 0; }
+:
+  TRACE
+  [ ON expression(&exp) ]?
+  where(&whr)?
+  condition(&cond)?    { *p = mknode(OP_TRACE, whr, cond, exp); }
+;
+
+continue_command(p_tree *p;)
+  { long l; p_tree pos = 0; }
+:
+  CONT
+  [ INTEGER            { l = tok.ival; }
+  |                    { l = 1; }
+  ]
+  position(&pos)?
+                       { *p = mknode(OP_CONT, mknode(OP_INTEGER, l), pos); }
+;
+
+when_command(p_tree *p;)
+  { p_tree     whr = 0, cond = 0; }
+:
+  WHEN
+  where(&whr)?
+  condition(&cond)?
+  '{' 
+  command_line(p)
+  [ ';'                        { *p = mknode(OP_LINK, *p, (p_tree) 0);
+                         p = &((*p)->t_args[1]);
+                       }
+    command_line(p)
+  ]*
+  '}'
+                       { if (! whr && ! cond) {
+                               error("no position or condition");
+                               freenode(*p);
+                               *p = 0;
+                         }
+                         else *p = mknode(OP_WHEN, whr, cond, *p);
+                       }
+;
+
+step_command(p_tree *p;)
+  { long       l; }
+:
+  STEP
+  [ INTEGER            { l = tok.ival; }
+  |                    { l = 1; }
+  ]                    { *p = mknode(OP_STEP, l); }
+;
+
+next_command(p_tree *p;)
+  { long       l; }
+:
+  NEXT
+  [ INTEGER            { l = tok.ival; }
+  |                    { l = 1; }
+  ]                    { *p = mknode(OP_NEXT, l); }
+;
+
+regs_command(p_tree *p;)
+  { long       l; }
+:
+  REGS
+  [ INTEGER            { l = tok.ival; }
+  |                    { l = 0; }
+  ]                    { *p = mknode(OP_REGS, l); }
+;
+
+delete_command(p_tree *p;)
+:
+  DELETE
+  INTEGER              { *p = mknode(OP_DELETE, tok.ival); }
+;
+
+print_command(p_tree *p;)
+:
+  PRINT expression(p)  { *p = mknode(OP_PRINT, *p); 
+                         p = &((*p)->t_args[0]);
+                       }
+  [ ','                        { *p = mknode(OP_LINK, *p, (p_tree) 0);
+                         p = &((*p)->t_args[1]);
+                       }
+    expression(p)
+  ]*
+;
+
+condition(p_tree *p;)
+:
+  IF expression(p)
+;
+
+where(p_tree *p;)
+:
+  IN qualified_name(p) { *p = mknode(OP_IN, *p); }
+|
+  position(p)
+;
+
+expression(p_tree *p;)
+:
+       qualified_name(p)
+;
+
+position(p_tree *p;)
+  { p_tree lin;
+    char *str;
+  }
+:
+  AT
+  [ STRING             { str = tok.str; }
+    ':'
+  |                    { if (! currfile) str = 0;
+                         else str = currfile->sy_idf->id_text;
+                       }
+  ]
+  lin_num(&lin)                { *p = mknode(OP_AT, lin->t_ival, str);
+                         freenode(lin);
+                       }
+;
+
+args(p_tree *p;)
+  { int first_time = 1; }
+:
+  [                    { if (! first_time) {
+                               *p = mknode(OP_LINK, *p, (p_tree) 0);
+                               p = &((*p)->t_args[1]);
+                         }
+                         first_time = 0;
+                       }
+       arg(p)
+  ]*
+;
+
+arg(p_tree *p;)
+:
+  name(p)
+|
+  '>' name(p)          { (*p)->t_oper = OP_OUTPUT; }
+|
+  '<' name(p)          { (*p)->t_oper = OP_INPUT; }
+;
+
+lin_num(p_tree *p;)
+:
+  INTEGER              { *p = mknode(OP_INTEGER, tok.ival); }
+;
+
+qualified_name(p_tree *p;)
+:
+  name(p)
+  [    '`'             { *p = mknode(OP_SELECT, *p, (p_tree) 0); }
+       name(&((*p)->t_args[1]))
+  ]*
+;
+
+name(p_tree *p;)
+:
+  [ XFILE
+  | LIST
+  | RUN
+  | RERUN
+  | STOP
+  | WHEN
+  | AT
+  | IN
+  | IF
+  | NAME
+  | CONT
+  | STEP
+  | NEXT
+  | REGS
+  | WHERE
+  | STATUS
+  | PRINT
+  | DELETE
+  | DUMP
+  | RESTORE
+  | TRACE
+  | ON
+  ]                    { *p = mknode(OP_NAME, tok.idf, tok.str); }
+;
+
+{
+int
+LLlex()
+{
+  register int c;
+
+  if (ASIDE) {
+       tok = aside;
+       ASIDE = 0;
+       return TOK;
+  }
+  do {
+       c = getc(db_in);
+  } while (c != EOF && class(c) == STSKIP);
+  if (c == EOF) return c;
+  switch(class(c)) {
+  case STSTR:
+       TOK = get_string(c);
+       break;
+  case STIDF:
+       TOK = get_name(c);
+       break;
+  case STDOT:
+       c = getc(db_in);
+       if (c == EOF || class(c) != STNUM) {
+               ungetc(c,db_in);
+               TOK = '.';
+               break;
+       }
+       /* Fall through */
+  case STNUM:
+       TOK = get_number(c);
+       break;
+  case STNL:
+  case STSIMP:
+       TOK = c;
+       break;
+  default:
+       error("illegal character '\\0%o'", c);
+       return LLlex();
+  }
+  return TOK;
+}
+
+int
+get_name(c)
+  register int c;
+{
+  char buf[512+1];
+  register char        *p = &buf[0];
+  register struct idf *id;
+
+  do {
+       if (p - buf < 512) *p++ = c;
+       c = getc(db_in);
+  } while ((extended_charset && in_ext(c)) || in_idf(c));
+  ungetc(c, db_in);
+  *p = 0;
+  if (extended_charset) {
+       tok.idf = 0;
+       tok.str = Salloc(buf, (unsigned) (p - buf));
+       return NAME;
+  }
+  id = str2idf(buf, 1);
+  tok.idf = id;
+  tok.str = id->id_text;
+  return id->id_reserved ? id->id_reserved : NAME;
+}
+
+static int
+quoted(ch)
+  int  ch;
+{
+  /*   quoted() replaces an escaped character sequence by the
+       character meant.
+  */
+  /* first char after backslash already in ch */
+  if (!is_oct(ch)) {           /* a quoted char */
+       switch (ch) {
+       case 'n':
+               ch = '\n';
+               break;
+       case 't':
+               ch = '\t';
+               break;
+       case 'b':
+               ch = '\b';
+               break;
+       case 'r':
+               ch = '\r';
+               break;
+       case 'f':
+               ch = '\f';
+               break;
+       }
+  }
+  else {                               /* a quoted octal */
+       register int oct = 0, cnt = 0;
+
+       do {
+               oct = oct*8 + (ch-'0');
+               ch = getc(db_in);
+       } while (is_oct(ch) && ++cnt < 3);
+       ungetc(ch, db_in);
+       ch = oct;
+  }
+  return ch&0377;
+
+}
+
+int get_string(c)
+  int  c;
+{
+  register int ch;
+  char buf[512];
+  register int len = 0;
+
+  while (ch = getc(db_in), ch != c) {
+       if (ch == '\n') {
+               error("newline in string");
+               break;
+       }
+       if (ch == '\\') {
+               ch = getc(db_in);
+               ch = quoted(ch);
+       }
+       buf[len++] = ch;
+  }
+  buf[len++] = 0;
+  tok.str = Salloc(buf, (unsigned) len);
+  return STRING;
+}
+
+static int
+val_in_base(c, base)
+  register int c;
+{
+  return is_dig(c) 
+       ? c - '0'
+       : base != 16
+         ? -1
+         : is_hex(c)
+           ? (c - 'a' + 10) & 017
+           : -1;
+}
+
+int
+get_number(c)
+  register int c;
+{
+  char buf[512+1];
+  register int base = 10;
+  register char *p = &buf[0];
+  register long val = 0;
+  register int val_c;
+
+  if (c == '0') {
+       /* check if next char is an 'x' or an 'X' */
+       c = getc(db_in);
+       if (c == 'x' || c == 'X') {
+               base = 16;
+               c = getc(db_in);
+       }
+       else    base = 8;
+  }
+  while (val_c = val_in_base(c, base), val_c >= 0) {
+       val = val * base + val_c;
+       if (p - buf < 512) *p++ = c;
+       c = getc(db_in);
+  }
+  if (base == 16 || !((c == '.' || c == 'e' || c == 'E'))) {
+       ungetc(c, db_in);
+       tok.ival = val;
+       return INTEGER;
+  }
+  if (c == '.') {
+       if (p - buf < 512) *p++ = c;
+       c = getc(db_in);
+  }
+  while (is_dig(c)) {
+       if (p - buf < 512) *p++ = c;
+       c = getc(db_in);
+  }
+  if (c == 'e' || c == 'E') {
+       if (p - buf < 512) *p++ = c;
+       c = getc(db_in);
+       if (c == '+' || c == '-') {
+               if (p - buf < 512) *p++ = c;
+               c = getc(db_in);
+       }
+       if (! is_dig(c)) {
+               error("malformed floating constant");
+       }
+       while (is_dig(c)) {
+               if (p - buf < 512) *p++ = c;
+               c = getc(db_in);
+       }
+  }
+  ungetc(c, db_in);
+  *p++ = 0;
+  if (p == &buf[512+1]) {
+       error("floating point constant too long");
+  }
+  return REAL;
+}
+
+extern char * symbol2str();
+
+LLmessage(t)
+{
+  if (t > 0) {
+       if (! errorgiven) {
+               error("%s missing before %s", symbol2str(t), symbol2str(TOK));
+       }
+       aside = tok;
+  }
+  else if (t == 0) {
+       if (! errorgiven) {
+               error("%s unexpected", symbol2str(TOK));
+       }
+  }
+  else if (! errorgiven) {
+       error("EOF expected");
+  }
+  errorgiven = 1;
+}
+
+static int
+catch_del()
+{
+  signal(SIGINT, catch_del);
+  signal_child(SIGEMT);
+  longjmp(jmpbuf, 1);
+}
+
+static int
+init_del()
+{
+  signal(SIGINT, catch_del);
+}
+
+static int
+skip_to_eol()
+{
+  while (TOK != '\n' && TOK > 0) LLlex();
+  wait_for_child("interrupted");
+}
+}
diff --git a/util/grind/dbx_string.g b/util/grind/dbx_string.g
new file mode 100644 (file)
index 0000000..012b800
--- /dev/null
@@ -0,0 +1,679 @@
+/* $Header$
+   Grammar of a string of a debugger symbol table entry.
+*/
+
+{
+#include       <out.h>
+#include       <alloc.h>
+
+#include       "type.h"
+#include       "symbol.h"
+#include       "scope.h"
+#include       "class.h"
+#include       "idf.h"
+
+extern char    *strindex();
+extern long    str2long();
+extern double  atof();
+extern int     saw_code;
+extern long    pointer_size;
+
+static char    *DbxPtr;                /* current pointer in DBX string */
+static int     AllowName;              /* set if NAME legal at this point */
+static long    ival;
+static double  fval;
+static char    *strval;
+static int     last_index[2];
+static struct outname  *currnam;
+
+static struct literal *get_literal_space();
+static struct fields *get_field_space();
+static end_field();
+static char *string_val();
+}
+
+%start DbxParser, debugger_string;
+
+%prefix DBS;
+
+%lexical DBSlex;
+
+%onerror DBSonerror;
+
+%token INTEGER, REAL, STRING, NAME;
+
+debugger_string
+  { register p_symbol s;
+    char *str;
+    p_type tmp = 0;
+  }
+:
+  name(&str)
+  [ /* constant name */
+                       { s = NewSymbol(str, CurrentScope, CONST, currnam); }
+       'c' const_name(s)
+
+  | /* type name */
+                       { s = NewSymbol(str, CurrentScope, TYPE, currnam); }
+       't' type_name(&(s->sy_type))
+
+  | /* tag name (only C?) */
+                       { s = NewSymbol(str, CurrentScope, TAG, currnam); }
+       'T' tag_name(s)
+
+  | /* end scope */
+       'E' INTEGER
+                       { close_scope(); }
+
+  | /* module begin */
+                       { s = NewSymbol(str, CurrentScope, MODULE, currnam); }
+       'M' INTEGER
+                       { open_scope(s, 1);
+                         s->sy_name.nm_scope = CurrentScope;
+                         CurrentScope->sc_start = currnam->on_valu;
+                         CurrentScope->sc_proclevel = currnam->on_desc;
+                         add_scope_addr(CurrentScope);
+                       }
+
+  | /* external procedure */
+                       { s = NewSymbol(str, PervasiveScope, PROC, currnam); }
+       'P' routine(s)
+
+  | /* private procedure */
+                       { s = NewSymbol(str, CurrentScope, PROC, currnam); }
+       'Q' routine(s)
+
+  | /* external function */
+                       { s = NewSymbol(str, PervasiveScope, FUNCTION, currnam); }
+       'F' function(s)
+
+  | /* private function */
+                       { s = NewSymbol(str, CurrentScope, FUNCTION, currnam); }
+       'f' function(s)
+
+  | /* global variable, external */
+                               /* maybe we already know it; but we need
+                                  the type information anyway for other
+                                  types.
+                               */
+                       { s = Lookup(findidf(str), PervasiveScope, VAR);
+                         if (s) {
+                               tmp = s->sy_type;
+                         } else s = NewSymbol(str, PervasiveScope, VAR, currnam);
+                       }
+       'G' type(&(s->sy_type), (int *) 0)
+                       { if (tmp) s->sy_type = tmp; } 
+
+  | /* static variable */
+                       { s = NewSymbol(str, CurrentScope, VAR, currnam); }
+       'S' type(&(s->sy_type), (int *) 0)
+
+  | /* static variable, local scope */
+                       { s = NewSymbol(str, CurrentScope, VAR, currnam); }
+       'V' type(&(s->sy_type), (int *) 0)
+
+  | /* register variable */
+                       { s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
+       'r' type(&(s->sy_type), (int *) 0)
+
+  | /* value parameter */
+                       { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
+       'p' type(&(s->sy_type), (int *) 0)
+                       { add_param_type('p', s); }
+
+  | /* value parameter but address passed */
+                       { s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
+       'i' type(&(s->sy_type), (int *) 0)
+                       { add_param_type('i', s); }
+
+  | /* variable parameter */
+                       { s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
+       'v' type(&(s->sy_type), (int *) 0)
+                       { add_param_type('v', s); }
+
+  | /* local variable */
+                       { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
+       type_name(&(s->sy_type))
+
+  | /* function result in Pascal; ignore ??? */
+                       { s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
+       'X' type_name(&(s->sy_type))
+  ]
+  ';'?
+;
+
+name(char **s;)
+:
+  /* anything up to a ':' */
+  NAME { *s = strval; }
+;
+
+const_name(p_symbol cst;)
+  { int type_index[2];
+    long iconst;
+    register char *p;
+  }
+:
+  '='
+  [
+       'b' integer_const(&(cst->sy_const.co_ival))     /* boolean */
+  |
+       'c' integer_const(&(cst->sy_const.co_ival))     /* character */
+                               { cst->sy_type = char_type; }
+  |
+       'i' integer_const(&(cst->sy_const.co_ival))     /* integer */
+                               { cst->sy_type = long_type; }
+  |
+       'r' real_const(&(cst->sy_const.co_rval))        /* real */
+                               { cst->sy_type = double_type; }
+  |
+       's' string_const                                /* string */
+                               { cst->sy_const.co_sval = string_val(strval);
+                                 cst->sy_type = string_type;
+                               }
+  |
+       'e' type_index(type_index) ',' integer_const(&(cst->sy_const.co_ival))
+                               /* enumeration constant;
+                                * enumeration type, value
+                                */
+                               { cst->sy_type = *tp_lookup(type_index); }
+                               
+  |
+       'S' type_index(type_index)
+                               { cst->sy_type = *tp_lookup(type_index);
+                                 cst->sy_const.co_setval = p =
+                                   Malloc((unsigned) cst->sy_type->ty_size);
+                               }
+       [ ',' integer_const(&iconst)
+                               { *p++ = iconst; }
+       ]+
+                               /* set constant:
+                                *  settype, values of the bytes
+                                *  in the set.
+                                */
+  ]
+;
+
+integer_const(long *iconst;)
+  { int sign = 0; }
+:
+  [ '+' | '-' { sign = 1; } ]?
+  INTEGER                      { *iconst = sign ? -ival : ival; }
+;
+
+real_const(double *f;)
+  { int sign = 0; }
+:
+  [ '+' | '-' { sign = 1; } ]?
+  REAL                         { *f = sign ? fval : -fval; }
+;
+
+string_const
+:
+  STRING                       /* has SINGLE quotes! */
+;
+
+type_name(p_type *t;)
+  { int type_index[2]; p_type *p; }
+:
+  type_index(type_index)
+  [
+       '='                     
+       type(t, type_index)
+                               { p = tp_lookup(type_index);
+                                 if (*p && *p != incomplete_type) {
+                                       if (!((*p)->ty_flags & T_CROSS))
+                                               error("Redefining (%d,%d) %d",
+                                                 type_index[0],
+                                                 type_index[1],
+                                                 (*p)->ty_class);
+                                       if (*t && *p != *t) free_type(*p);
+                                 }
+                                 if (*t) *p = *t; 
+                               }
+  |
+                               { p = tp_lookup(type_index); }
+  ]
+                               { if (*p == 0) *p = incomplete_type;
+                                 *t = *p;
+                               }
+;
+
+type_index(int *type_index;)
+:
+[
+  INTEGER                      { type_index[0] = 0; type_index[1] = ival; }
+|
+  '(' INTEGER                  { type_index[0] = ival; }
+  ',' INTEGER                  { type_index[1] = ival; }
+  ')'
+]
+                               { last_index[0] = type_index[0];
+                                 last_index[1] = type_index[1];
+                               }
+;
+
+tag_name(p_symbol t;)
+  { int type_index[2]; p_type *p; }
+:
+  type_index(type_index)
+  '='                          
+  type(&(t->sy_type), type_index)
+                               { p = tp_lookup(type_index);
+                                 if (*p && *p != incomplete_type) {
+                                       if (!((*p)->ty_flags & T_CROSS))
+                                               error("Redefining (%d,%d) %d",
+                                                 type_index[0],
+                                                 type_index[1],
+                                                 (*p)->ty_class);
+                                       if (t->sy_type && *p != t->sy_type) {
+                                               free_type(*p);
+                                       }
+                                 }
+                                 if (t->sy_type) *p = t->sy_type; 
+                                 if (*p == 0) *p = incomplete_type;
+                               }
+;
+
+function(p_symbol p;)
+:
+                       { p->sy_type = new_type();
+                         p->sy_type->ty_class = T_PROCEDURE;
+                         p->sy_type->ty_size = pointer_size;
+                       }
+  type(&(p->sy_type->ty_retval), (int *) 0) 
+                       { if (CurrentScope != FileScope &&
+                             saw_code) {
+                               /* if saw_code is not set, it is a nested
+                                  procedure
+                               */
+                               close_scope();
+                         }
+                         saw_code = 0;
+                         open_scope(p, 1);
+                         p->sy_name.nm_scope = CurrentScope;
+                         CurrentScope->sc_start = currnam->on_valu;
+                         add_scope_addr(CurrentScope);
+                         CurrentScope->sc_proclevel = currnam->on_desc;
+                       }
+;
+
+routine(p_symbol p;)
+:
+                       { p->sy_type = new_type();
+                         p->sy_type->ty_class = T_PROCEDURE;
+                         p->sy_type->ty_size = pointer_size;
+                         if (CurrentScope != FileScope &&
+                             saw_code) {
+                               /* if saw_code is not set, it is a nested
+                                  procedure
+                               */
+                               close_scope();
+                         }
+                         saw_code = 0;
+                         open_scope(p, 1);
+                         p->sy_name.nm_scope = CurrentScope;
+                         CurrentScope->sc_start = currnam->on_valu;
+                         add_scope_addr(CurrentScope);
+                         CurrentScope->sc_proclevel = currnam->on_desc;
+                       }
+  INTEGER ';'
+  type(&(p->sy_type->ty_retval), (int *) 0) 
+;
+
+type(p_type *ptp; int *type_index;)
+  { register p_type tp = 0;
+    p_type t1, t2;
+    long ic1, ic2;
+    int A_used = 0;
+  }
+:                      { *ptp = 0; }
+  [
+       /* type cross reference */
+       /* these are used in C for references to a struct, union or
+        * enum that has not been declared (yet)
+        */
+       'x'             { tp = new_type(); tp->ty_flags = T_CROSS; }
+       [ 's'   /* struct */
+                       { tp->ty_class = T_STRUCT; }
+       | 'u'   /* union */
+                       { tp->ty_class = T_UNION; }
+       | 'e'   /* enum */
+                       { tp->ty_class = T_ENUM; }
+       ]
+                       { AllowName = 1; }
+       name(&(tp->ty_tag))
+  |
+       /* subrange */
+       /* the integer_const's represent the lower and the upper bound.
+        * A subrange type defined as subrange of itself is an integer type.
+        * If the second integer_const == 0, but the first is not, we
+        * have a floating point type with size equal to the first
+        * integer_const.
+        * Upperbound -1 means unsigned int or unsigned long.
+        */
+       'r' type_name(&t1) ';'
+       [ 'A' integer_const(&ic1)       { A_used = 1; }
+       | integer_const(&ic1)
+       ]
+       ';'
+       [ 'A' integer_const(&ic2)       { A_used |= 2; }
+       | integer_const(&ic2)
+       ]
+                       { *ptp = subrange_type(A_used,
+                                              last_index,
+                                              ic1,
+                                              ic2,
+                                              type_index);
+                       }
+  |
+       /* array; first type is bound type, next type
+        * is element type
+        */
+       'a' type(&t1, (int *) 0) ';' type(&t2, (int *) 0)
+                       { *ptp = array_type(t1, t2); }
+  |
+       /* structure type */
+       's'             { tp = new_type(); tp->ty_class = T_STRUCT; }
+       structure_type(tp)
+  |
+       /* union type */
+       'u'             { tp = new_type(); tp->ty_class = T_UNION; }
+       structure_type(tp)
+  |
+       /* enumeration type */
+       'e'             { tp = new_type(); tp->ty_class = T_ENUM; }
+       enum_type(tp)
+  |
+       /* pointer type */
+       '*'             { tp = new_type(); tp->ty_class =T_POINTER;
+                         tp->ty_size = pointer_size;
+                       }
+       type(&(tp->ty_ptrto), (int *) 0)
+  |
+       /* function type */
+       'f'             { tp = new_type(); tp->ty_class = T_PROCEDURE;
+                         tp->ty_size = pointer_size;
+                       }
+       type(&(tp->ty_retval), (int *) 0) 
+/*
+       [ %prefer
+               ',' param_list(tp)
+       |
+       ]
+*/
+  |
+       /* procedure type */
+       'Q'             { tp = new_type(); tp->ty_class = T_PROCEDURE;
+                         tp->ty_size = pointer_size;
+                       }
+       type(&(tp->ty_retval), (int *) 0) 
+       ',' param_list(tp)
+  |
+       /* another procedure type */
+       'p'             { tp = new_type(); tp->ty_class = T_PROCEDURE;
+                         tp->ty_size = pointer_size;
+                         tp->ty_retval = void_type;
+                       }
+       param_list(tp)
+  |
+       /* set type */
+       /* the first integer_const represents the size in bytes,
+        * the second one represents the low bound
+        */
+       'S'             { tp = new_type(); tp->ty_class = T_SET; }
+       type(&(tp->ty_setbase), (int *) 0) ';'
+       [
+               integer_const(&(tp->ty_size)) ';'
+               integer_const(&(tp->ty_setlow)) ';'
+       |
+                       { set_bounds(tp); }
+       ]
+  |
+       /* file type of Pascal */
+       'L'             { tp = new_type(); tp->ty_class = T_FILE; }
+       type(&(tp->ty_fileof), (int *) 0)
+  |
+       type_name(ptp)
+                       { if (type_index &&
+                             *ptp == incomplete_type &&
+                             type_index[0] == last_index[0] &&
+                             type_index[1] == last_index[1]) {
+                               *ptp = void_type;
+                         }
+                       }
+  ]
+                       { if (! *ptp) *ptp = tp; }
+;
+
+structure_type(register p_type tp;)
+  { register struct fields *fldp; }
+:
+  integer_const(&(tp->ty_size))                /* size in bytes */
+  [                    { fldp = get_field_space(tp); }
+       name(&(fldp->fld_name))
+       type(&(fldp->fld_type), (int *) 0) ','
+       integer_const(&(fldp->fld_pos)) ','     /* offset in bits */
+       integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
+  ]*
+  ';'                  { end_field(tp); }
+;
+
+enum_type(register p_type tp;)
+  { register struct literal *litp;
+    long maxval = 0;
+  }
+:
+  [                    { litp = get_literal_space(tp);
+                       }
+       name(&(litp->lit_name))
+       integer_const(&(litp->lit_val)) ',' 
+                       { if (maxval < litp->lit_val) maxval = litp->lit_val;
+                         AllowName = 1;
+                       }
+  ]*
+  ';'                  { end_literal(tp, maxval); }
+;
+
+param_list(p_type t;)
+  { register struct param *p;
+    long iconst;
+  }
+:
+  integer_const(&iconst) ';'   /* number of parameters */
+                       { t->ty_nparams = iconst;
+                         t->ty_params = p = (struct param *)
+                           Malloc((unsigned)(t->ty_nparams * sizeof(struct param)));
+                       }
+  [
+       [       'p'     { p->par_kind = 'p'; }
+       |       'v'     { p->par_kind = 'v'; }
+       |       'i'     { p->par_kind = 'i'; }
+       ]
+       type(&(p->par_type), (int *) 0) ';'
+                       { t->ty_nbparams += 
+                               param_size(p->par_type, p->par_kind);
+                         p++;
+                       }
+  ]*
+;
+
+{
+static char *dbx_string;
+static char *DbxOldPtr;
+
+struct outname *
+DbxString(n)
+  struct outname       *n;
+{
+  currnam = n;
+  DbxPtr = n->on_mptr;
+  dbx_string = DbxPtr;
+  AllowName = 1;
+  DbxParser();
+  return currnam;
+}
+
+/*ARGSUSED*/
+DBSmessage(n)
+{
+  fatal("error in Dbx string \"%s\", DbxPtr = \"%s\", DbxOldPtr = \"%s\"",
+       dbx_string,
+       DbxPtr,
+       DbxOldPtr);
+
+}
+
+DBSonerror(tk, p)
+  int  *p;
+{
+  DbxPtr = DbxOldPtr;
+/* ???  if (DBSsymb < 0) {
+       while (*p && *p != ';') p++;
+       if (*p) DbxPtr = ";";
+       return;
+  }
+*/
+  if (! tk) {
+       while (*p && *p != NAME) p++;
+       if (*p) {
+               AllowName = 1;
+       }
+  }
+  else if (tk == NAME) AllowName = 1;
+}
+
+DBSlex()
+{
+  register char *cp = DbxPtr;
+  int allow_name = AllowName;
+  register int c;
+
+  AllowName = 0;
+  DbxOldPtr = cp;
+  c = *cp;
+  if (c == '\\' && *(cp+1) == '\0') {
+       currnam++;
+       cp = currnam->on_mptr;
+       DbxOldPtr = cp;
+       c = *cp;
+  }
+  if (! c) {
+       DbxPtr = cp;
+       return -1;
+  }
+  if ((! allow_name && is_token(c)) || c == ';') {
+       DbxPtr = cp+1;
+       return c;
+  }
+  if (is_dig(c)) {
+       int retval = INTEGER;
+
+       while (++cp, is_dig(*cp)) /* nothing */;
+       c = *cp;
+       if (c == '.') {
+               retval = REAL;
+               while (++cp, is_dig(*cp)) /* nothing */;
+               c = *cp;
+       }
+       if (c == 'e' || c == 'E') {
+               char *oldcp = cp;
+
+               cp++;
+               c = *cp;
+               if (c == '-' || c == '+') {
+                       cp++;
+                       c = *cp;
+               }
+               if (is_dig(c)) {
+                       retval = REAL;
+                       while (++cp, is_dig(*cp)) /* nothing */;
+               }
+               else cp = oldcp;
+       }
+       c = *cp;
+       *cp = 0;
+       if (retval == INTEGER) {
+               ival = str2long(DbxOldPtr, 10);
+       }
+       else {
+               fval = atof(DbxOldPtr);
+       }
+       *cp = c;
+       DbxPtr = cp;
+       return retval;
+  }
+  if (c == '\'') {
+       cp++;
+       strval = cp;
+       while ((c = *cp) && c != '\'') {
+               if (c == '\\') cp++;    /* backslash escapes next character */
+               if (!(c =  *cp)) break; /* but not a null byte */
+               cp++;
+       }
+       if (! c) DBSmessage(0); /* no return */
+       *cp = 0;
+       DbxPtr = cp + 1;
+       return STRING;
+  }
+  strval = cp;
+  while ((c = *cp) && c != ':' && c != ',') cp++;
+  DbxPtr = *cp ? cp+1 : cp;
+  *cp = 0;
+  return NAME;
+}
+
+static struct fields *
+get_field_space(tp)
+  register p_type tp;
+{
+  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++];
+}
+
+static
+end_field(tp)
+  register p_type tp;
+{
+  tp->ty_fields = (struct fields *)
+       Realloc((char *) tp->ty_fields,
+               tp->ty_nfields * sizeof(struct fields));
+}
+
+static struct literal *
+get_literal_space(tp)
+  register p_type tp;
+{
+  if (! (tp->ty_nenums & 07)) {
+       tp->ty_literals = (struct literal *)
+               Realloc((char *) tp->ty_literals,
+                       (tp->ty_nenums+8)*sizeof(struct literal));
+  }
+  return &tp->ty_literals[tp->ty_nenums++];
+}
+
+static char *
+string_val(s)
+  char *s;
+{
+  register char *ns = s, *os = s;
+  register unsigned int i = 1;
+
+  for (;;) {
+       if (!*os) break;
+       i++;
+       if (*os == '\\') {
+               os++;
+               *ns++ = *os++;
+       }
+       else *ns++ = *os++;
+  }
+  *ns = '\0';
+  return Salloc(s, i);
+}
+
+}
diff --git a/util/grind/dbxread.c b/util/grind/dbxread.c
new file mode 100644 (file)
index 0000000..62ef146
--- /dev/null
@@ -0,0 +1,194 @@
+/* $Header$
+   Read the symbol table from an ACK a.out format file.
+*/
+
+#include <stb.h>
+#include <alloc.h>
+#include <assert.h>
+
+#include "position.h"
+#include "file.h"
+#include "symbol.h"
+#include "idf.h"
+#include "scope.h"
+#include "rd.h"
+
+extern char            *Malloc();
+extern char            *strindex();
+extern struct outname  *DbxString();
+
+int                    saw_code = 0;
+
+static char            *AckStrings;    /* ACK a.out string table */
+static struct outname  *AckNames;      /* ACK a.out symbol table entries */
+static unsigned int    NAckNames;      /* Number of ACK symbol table entries */
+static struct outname  *EndAckNames;   /* &AckNames[NAckNames] */
+
+/* Read the symbol table from file 'f', which is supposed to be an
+   ACK a.out format file. Offer DBX strings to the DBX string parser.
+*/
+int
+DbxRead(f)
+  char *f;
+{
+  struct outhead h;
+  register struct outname *n;
+  register struct outname *line_file = 0;
+  long OffsetStrings;
+  int had_lbrac = 0;
+
+  /* Open file, read header, and check magic word */
+  if (! rd_open(f)) {
+       fatal("%s: not an ACK object file", f);
+  }
+  rd_ohead(&h);
+  if (BADMAGIC(h) && h.oh_magic != O_CONVERTED) {
+       fatal("%s: not an ACK object file", f);
+  }
+
+  /* Allocate space for name table and read it */
+  AckNames = (struct outname *) 
+               Malloc((unsigned)(sizeof(struct outname) * h.oh_nname));
+  AckStrings = Malloc((unsigned) h.oh_nchar);
+  rd_name(AckNames, h.oh_nname);
+  rd_string(AckStrings, h.oh_nchar);
+
+  /* Adjust file offsets in name table to point at strings */
+  OffsetStrings = OFF_CHAR(h);
+  NAckNames = h.oh_nname;
+  EndAckNames = &AckNames[h.oh_nname];
+  for (n = EndAckNames; --n >= AckNames;) {
+       if (n->on_foff) {
+               if ((unsigned)(n->on_foff - OffsetStrings) >= h.oh_nchar) {
+                       fatal("%s: error in object file", f);
+               }
+               n->on_mptr = AckStrings + (n->on_foff - OffsetStrings);
+       }
+       else    n->on_mptr = 0;
+  }
+
+  /* Offer strings to the DBX string parser if they contain a ':'.
+     Also offer filename-line number information to add_position_addr().
+     Here, the order may be important.
+  */
+  for (n = &AckNames[0]; n < EndAckNames; n++) {
+       int tp = n->on_type >> 8;
+       register p_symbol sym;
+
+       if (tp & (S_STB >> 8)) {
+               switch(tp) {
+#ifdef N_BINCL
+               case N_BINCL:
+                       n->on_valu = (long) line_file;
+                       line_file = n;
+                       break;
+               case N_EINCL:
+                       if (line_file) {
+                               line_file = (struct outname *) line_file->on_valu;
+                       }
+                       break;
+#endif
+               case N_SO:
+                       if (n->on_mptr[strlen(n->on_mptr)-1] == '/') {
+                               /* another N_SO follows ... */
+                               break;
+                       }
+                       while (CurrentScope != PervasiveScope) {
+                               close_scope();
+                       }
+                       saw_code = 0;
+                       sym = add_file(n->on_mptr);
+
+                       if (! currfile) newfile(sym->sy_idf);
+                       open_scope(sym, 0);
+                       sym->sy_file->f_scope = CurrentScope;
+                       FileScope = CurrentScope;
+                       clean_tp_tab();
+                       /* fall through */
+               case N_SOL:
+                       if (! line_file) line_file = n;
+                       else line_file->on_mptr = n->on_mptr;
+                       break;
+               case N_MAIN:
+                       newfile(FileScope->sc_definedby->sy_idf);
+                       break;
+               case N_SLINE:
+                       assert(line_file);
+                       if (! saw_code && !CurrentScope->sc_bp_opp) {
+                           CurrentScope->sc_bp_opp = n->on_valu;
+                           if (! CurrentScope->sc_start) {
+                               CurrentScope->sc_start = n->on_valu;
+                               if (CurrentScope->sc_has_activation_record) {
+                                       add_scope_addr(CurrentScope);
+                               }
+                           }
+                       }
+                       saw_code = 1;
+                       add_position_addr(line_file->on_mptr, n);
+                       break;
+               case N_LBRAC:   /* block, desc = nesting level */
+                       if (had_lbrac) {
+                               open_scope((p_symbol) 0, 0);
+                               saw_code = 0;
+                       }
+                       else {
+                               register p_scope sc = 
+                                       get_scope_from_addr(n->on_valu);
+
+                               if (!sc || sc->sc_bp_opp) {
+                                       had_lbrac = 1;
+                               }
+                               else CurrentScope = sc;
+                       }
+                       break;
+#ifdef N_SCOPE
+               case N_SCOPE:
+                       if (n->on_mptr && strindex(n->on_mptr, ':')) {
+                               n = DbxString(n);
+                       }
+                       break;
+#endif
+               case N_RBRAC:   /* end block, desc = nesting level */
+                       had_lbrac = 0;
+                       if (CurrentScope != FileScope) close_scope();
+                       saw_code = 0;
+                       break;
+               case N_FUN:     /* function, value = address */
+               case N_GSYM:    /* global variable */
+               case N_STSYM:   /* data, static, value = address */
+               case N_LCSYM:   /* bss, static, value = address */
+               case N_RSYM:    /* register var, value = reg number */
+               case N_SSYM:    /* struct/union el, value = offset */
+               case N_PSYM:    /* parameter, value = offset from AP */
+               case N_LSYM:    /* local sym, value = offset from FP */
+                       if (had_lbrac) {
+                               open_scope((p_symbol) 0, 0);
+                               saw_code = 0;
+                               had_lbrac = 0;
+                       }
+                       if (n->on_mptr && strindex(n->on_mptr, ':')) {
+                               n = DbxString(n);
+                       }
+                       break;
+               default:
+/*
+                       if (n->on_mptr && (n->on_type&S_TYP) >= S_MIN) {
+                               struct idf *id = str2idf(n->on_mptr, 0);
+
+                               sym = new_symbol();
+                               sym->sy_next = id->id_def;
+                               id->id_def = sym;
+                               sym->sy_class = SYMENTRY;
+                               sym->sy_onam = *n;
+                               sym->sy_idf = id;
+                       }
+*/
+                       break;
+               }
+       }
+  }
+  close_scope();
+  add_position_addr((char *) 0, (struct outname *) 0);
+  rd_close();
+  return (h.oh_magic == O_CONVERTED);
+}
diff --git a/util/grind/dump.c b/util/grind/dump.c
new file mode 100644 (file)
index 0000000..2a44bec
--- /dev/null
@@ -0,0 +1,65 @@
+/* $Header$ */
+
+#include <assert.h>
+#include <alloc.h>
+
+#include "operator.h"
+#include "position.h"
+#include "tree.h"
+#include "message.h"
+
+extern long    pointer_size;
+extern p_tree  get_from_item_list();
+
+struct dump {
+  char *globals, *stack;
+  struct message_hdr mglobal, mstack;
+};
+
+/* dumping and restoring of child process.
+*/
+do_dump(p)
+  p_tree       p;
+{
+  struct dump *d = (struct dump *) Malloc(sizeof(struct dump));
+
+  if (! get_dump(&d->mglobal, &d->globals, &d->mstack, &d->stack)) {
+       error("no debuggee");
+       free((char *) d);
+       return;
+  }
+  p->t_args[0] = (struct tree *) d;
+  p->t_address = (t_addr) BUFTOA(d->mglobal.m_buf+PC_OFF*pointer_size);
+  add_to_item_list(p);
+}
+
+/* dumping and restoring of child process.
+*/
+do_restore(p)
+  p_tree       p;
+{
+  struct dump *d;
+  
+  p = get_from_item_list((int) p->t_ival);
+  if (!p || p->t_oper != OP_DUMP) {
+       error("no such dump");
+       return;
+  }
+
+  d = (struct dump *) p->t_args[0];
+
+  if (! put_dump(&d->mglobal, d->globals, &d->mstack, d->stack)) {
+       error("no debuggee");
+  }
+  do_items();
+}
+
+free_dump(p)
+  p_tree       p;
+{
+  struct dump *d = (struct dump *) p->t_args[0];
+
+  free(d->globals);
+  free(d->stack);
+  free((char *) d);
+}
diff --git a/util/grind/expr.c b/util/grind/expr.c
new file mode 100644 (file)
index 0000000..0ddbdc7
--- /dev/null
@@ -0,0 +1,13 @@
+/* $Header$ */
+
+#include "position.h"
+#include "operator.h"
+#include "tree.h"
+
+int
+eval_cond(p)
+  p_tree       p;
+{
+  /* to be written !!! */
+  return 1;
+}
diff --git a/util/grind/file.hh b/util/grind/file.hh
new file mode 100644 (file)
index 0000000..5823b08
--- /dev/null
@@ -0,0 +1,38 @@
+/* $Header$ */
+
+/* Structure for information about files. This information consists of three
+   parts:
+   - file name and directory
+   - mapping of line numbers to offsets in file
+   - mapping of object adresses to lines in file and vice versa
+*/
+
+#define LOGHSIZ                6               /* make sure HSIZ is a power of 2 */
+#define HSIZ           (1 << LOGHSIZ)
+#define        HASH(line)      ((line) & (HSIZ-1))
+
+typedef struct file {
+       struct symbol   *f_sym;
+       char            *f_fullname;    /* name including directory */
+       struct scope    *f_scope;       /* reference to scope of this file */
+       t_lineno        f_nlines;       /* number of lines in file */
+       union {
+         long          *ff_linepos;    /* positions of lines in file */
+         struct file   *ff_next;       /* only for BINCL, EINCL */
+       } f_x;
+#define f_linepos      f_x.ff_linepos
+#define f_next         f_x.ff_next
+       struct outname  *f_start;
+       struct outname  *f_end;
+       struct outname  *f_line_addr[HSIZ];
+                                       /* hash table, mapping line numbers to
+                                          outname structures. Collisions are
+                                          resolved by chaining:
+                                       */
+#define next_outname(n)                ((struct outname *) ((n)->on_mptr))
+#define setnext_outname(n,m)   ((n)->on_mptr = (char *) (m))
+
+       struct file     *f_nextmap;     /* next file in mapping */
+} t_file, *p_file;
+
+/* ALLOCDEF "file" 10 */
diff --git a/util/grind/idf.c b/util/grind/idf.c
new file mode 100644 (file)
index 0000000..304de3b
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ * Author: Ceriel J.H. Jacobs
+ */
+
+/* I N S T A N T I A T I O N   O F   I D F   P A C K A G E */
+
+/* $Header$ */
+
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+#include       <idf_pkg.body>
diff --git a/util/grind/idf.h b/util/grind/idf.h
new file mode 100644 (file)
index 0000000..71eff3a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ * Author: Ceriel J.H. Jacobs
+ */
+
+/* U S E R   D E C L A R E D   P A R T   O F   I D F */
+
+/* $Header$ */
+
+struct id_u {
+       int id_res;
+       struct symbol *id_df;
+};
+
+#define IDF_TYPE       struct id_u
+#define id_reserved    id_user.id_res
+#define id_def         id_user.id_df
+
+#include       <idf_pkg.spec>
diff --git a/util/grind/itemlist.cc b/util/grind/itemlist.cc
new file mode 100644 (file)
index 0000000..81e54cf
--- /dev/null
@@ -0,0 +1,163 @@
+/* $Header$ */
+
+#include <alloc.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "position.h"
+#include "tree.h"
+#include "operator.h"
+
+extern FILE    *db_out;
+extern int     db_ss;
+
+typedef struct item {
+  struct item          *i_next;
+  struct tree          *i_node;
+} t_item, *p_item;
+
+/* STATICALLOCDEF "item" 10 */
+
+struct itemlist {
+  p_item       il_first, il_last;
+  int          il_count;
+};
+
+static struct itemlist item_list;
+
+int
+in_item_list(p)
+  p_tree       p;
+{
+  register p_item i = item_list.il_first;
+
+  while (i) {
+       if (i->i_node == p) return 1;
+       i = i->i_next;
+  }
+  return 0;
+}
+
+int
+item_addr_actions(a)
+  t_addr       a;
+{
+  /* Perform actions associated with position 'a', and return 1 if we must stop
+     there, and 0 if not.
+  */
+  register p_item i = item_list.il_first;
+  int stopping = 0;
+
+  while (i) {
+       register p_tree p = i->i_node;
+
+       if (p->t_address == a || p->t_address == NO_ADDR) {
+               switch(p->t_oper) {
+               case OP_TRACE:
+               case OP_WHEN:
+                       if (! p->t_args[1] ||
+                           eval_cond(p->t_args[1])) {
+                               perform(p, a);
+                       }
+                       break;
+               case OP_STOP:
+                       if (! p->t_args[1] ||
+                           eval_cond(p->t_args[1])) stopping = 1;
+                       break;
+               case OP_DUMP:
+                       break;
+               default:
+                       assert(0);
+               }
+       }
+       i = i->i_next;
+  }
+  return stopping;
+}
+
+add_to_item_list(p)
+  p_tree       p;
+{
+  p_item i;
+  
+  if (in_item_list(p)) return 1;
+
+  i = new_item();
+  i->i_node = p;
+  if (p->t_address == NO_ADDR &&
+      (p->t_oper != OP_TRACE || ! p->t_args[0])) db_ss++;
+  if (item_list.il_first == 0) {
+       item_list.il_first = i;
+  }
+  else {
+       item_list.il_last->i_next = i;
+  }
+  p->t_itemno = ++item_list.il_count;
+  item_list.il_last = i;
+  pr_item(p);
+  return 1;
+}
+
+p_tree
+remove_from_item_list(n)
+  int  n;
+{
+  register p_item i = item_list.il_first, prev = 0;
+  p_tree       p = 0;
+
+  while (i) {
+       if (i->i_node->t_itemno == n) break;
+       prev = i;
+       i = i->i_next;
+  }
+  if (i) {
+       if (prev) {
+               prev->i_next = i->i_next;
+       }
+       else item_list.il_first = i->i_next;
+       if (i == item_list.il_last) item_list.il_last = prev;
+       p = i->i_node;
+       if (p->t_address == NO_ADDR &&
+           (p->t_oper != OP_TRACE || ! p->t_args[0])) db_ss--;
+       free_item(i);
+  }
+  return p;
+}
+
+p_tree
+get_from_item_list(n)
+  int  n;
+{
+  register p_item i = item_list.il_first;
+
+  while (i) {
+       if (i->i_node->t_itemno == n) return i->i_node;
+       i = i->i_next;
+  }
+  return 0;
+}
+
+print_items()
+{
+  register p_item i = item_list.il_first;
+
+  for (; i; i = i->i_next) {
+       pr_item(i->i_node);
+  }
+}
+
+pr_item(p)
+  p_tree       p;
+{
+  fprintf(db_out, "(%d)\t", p->t_itemno);
+  print_node(p, 1);
+}
+
+do_items()
+{
+  register p_item i = item_list.il_first;
+
+  for (; i; i = i->i_next) {
+       if (i->i_node->t_oper != OP_DUMP) eval(i->i_node);
+  }
+}
diff --git a/util/grind/langdep.cc b/util/grind/langdep.cc
new file mode 100644 (file)
index 0000000..930de6a
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Header$ */
+
+#include "langdep.h"
+
+struct langlist {
+  struct langlist      *l_next;
+  struct langdep       *l_lang;
+  char                 *l_suff;
+};
+
+/* STATICALLOCDEF "langlist" 5 */
+
+static struct langlist *list;
+
+struct langdep *currlang;
+
+static int
+add_language(suff, lang)
+  char *suff;
+  struct langdep *lang;
+{
+  struct langlist *p = new_langlist();
+
+  p->l_next = list;
+  p->l_suff = suff;
+  p->l_lang = lang;
+  list = p;
+}
+
+int
+init_languages()
+{
+  add_language(".mod", m2_dep);
+}
+
+int
+find_language(suff)
+  char *suff;
+{
+  register struct langlist *p = list;
+
+  while (p) {
+       currlang = p->l_lang;
+       if (! strcmp(p->l_suff, suff)) break;
+       p = p->l_next;
+  }
+}
diff --git a/util/grind/langdep.h b/util/grind/langdep.h
new file mode 100644 (file)
index 0000000..4fe6eb0
--- /dev/null
@@ -0,0 +1,32 @@
+/* $Header$ */
+
+/* language-dependent routines and formats, together in one structure: */
+
+struct langdep {
+  /* formats (for fprintf): */
+  char *decint_fmt;            /* decimal ints (format for long) */
+  char *octint_fmt;            /* octal ints (format for long) */
+  char *hexint_fmt;            /* hexadecimal ints (format for long) */
+  char *uns_fmt;               /* unsigneds (format for long) */
+  char *addr_fmt;              /* address (format for long) */
+  char *real_fmt;              /* real (format for double) */
+  char *char_fmt;              /* character (format for int) */
+
+  /* display openers and closers: */
+  char *open_array_display;
+  char *close_array_display;
+  char *open_struct_display;
+  char *close_struct_display;
+  char *open_set_display;
+  char *close_set_display;
+
+  /* language dependant routines: */
+  int  (*printstring)();
+  long (*arrayelsize)();
+};
+
+extern struct langdep  *m2_dep, *currlang;
+
+extern int find_language();
+
+extern int init_languages();
diff --git a/util/grind/list.c b/util/grind/list.c
new file mode 100644 (file)
index 0000000..ee59684
--- /dev/null
@@ -0,0 +1,146 @@
+/* $Header$ */
+
+#include <stdio.h>
+#include <alloc.h>
+
+#include "position.h"
+#include "idf.h"
+#include "file.h"
+#include "symbol.h"
+
+static line_positions();
+extern char    *dirs[];
+extern FILE    *fopen();
+extern FILE    *db_out;
+#define        window_size     21
+
+static int
+mk_filnm(dir, file, newname)
+  char *dir;
+  char *file;
+  char **newname;
+{
+  register char        *dst = Malloc((unsigned) (strlen(dir) + strlen(file) + 2));
+
+  *newname = dst;
+  if (*dir) {
+       while (*dst++ = *dir++) /* nothing */;
+       *(dst - 1) = '/';
+  }
+  while (*dst++ = *file++) /* nothing */;
+}
+
+static FILE *
+open_file(fn, mode, ffn)
+  char *fn;
+  char *mode;
+  char **ffn;
+{
+  FILE *f;
+  char **p;
+
+  if (fn[0] == '/') {
+       *ffn = fn;
+       return fopen(fn, mode);
+  }
+  p = dirs;
+  while (*p) { 
+       mk_filnm(*p++, fn, ffn);
+       if ((f = fopen(*ffn, mode)) != NULL) {
+               return f;
+       }
+       free(*ffn);
+  }
+  return NULL;
+}
+
+/*     Print a window of window_size lines around line "line" of
+       file "file".
+*/
+window(file, line)
+  p_file       file;
+  int          line;
+{
+  lines(file,
+       line + ((window_size >> 1) - window_size), line + (window_size >> 1));
+}
+
+lines(file, l1, l2)
+  register p_file file;
+  int          l1, l2;
+{
+  static p_file last_file;
+  static FILE *last_f;
+  register FILE        *f;
+  register int n;
+
+  if (last_file != file) {
+       if (last_f) fclose(last_f);
+       last_f = 0;
+       if (!(f = open_file(file->f_sym->sy_idf->id_text, 
+                           "r",
+                           &file->f_fullname))) {
+               error("could not open %s", file->f_sym->sy_idf->id_text);
+               return;
+       }
+       printf("filedesc = %d\n", fileno(f));
+       last_file = file;
+       last_f = f;
+       if (! file->f_linepos) {
+               line_positions(file, f);
+       }
+  }
+  else f = last_f;
+
+  if (l1 < 1) l1 = 1;
+  if (l2 > file->f_nlines) l2 = file->f_nlines;
+  if (l1 > l2) {
+       error("%s has only %d lines", file->f_sym->sy_idf->id_text, file->f_nlines);
+       return;
+  }
+
+  fseek(f, *(file->f_linepos+(l1-1)), 0);
+  for (n = l1; n <= l2; n++) {
+       register int    c;
+
+       fprintf(db_out, "%6d  ", n);
+       do {
+               c = getc(f);
+               if (c != EOF) putc(c, db_out);
+       } while (c != '\n' && c != EOF);
+       if (c == EOF) break;
+  }
+  clearerr(f);
+}
+
+static
+line_positions(file, f)
+  p_file       file;
+  register FILE        *f;
+{
+  int          nl;
+  unsigned int n_alloc = 256;
+  register long        cnt = 0;
+  register int c;
+
+  file->f_linepos = (long *) Malloc(n_alloc * sizeof(long));
+  file->f_linepos[0] = 0;
+  nl = 1;
+  while ((c = getc(f)) != EOF) {
+       cnt++;
+       if (c == '\n') {
+               if (nl == n_alloc) {
+                       n_alloc <<= 1;
+                       file->f_linepos =
+                               (long *) Realloc((char *)(file->f_linepos),
+                                                n_alloc * sizeof(long));
+               }
+               file->f_linepos[nl++] = cnt;
+       }
+  }
+  if (cnt == file->f_linepos[nl-1]) nl--;
+  file->f_linepos = (long *) Realloc((char *)(file->f_linepos),
+                                       (unsigned)nl * sizeof(long));
+  file->f_nlines = nl;
+  clearerr(f);
+}
diff --git a/util/grind/main.c b/util/grind/main.c
new file mode 100644 (file)
index 0000000..6ac468f
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdio.h>
+#include <varargs.h>
+
+#include "tokenname.h"
+#include "position.h"
+#include "file.h"
+#include "symbol.h"
+#include "scope.h"
+
+static char    *usage = "Usage: %s [-d] [<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();
+
+main(argc, argv)
+  char *argv[];
+{
+  char *p;
+
+  db_out = stdout;
+  db_in = stdin;
+  progname = argv[0];
+  while (p = strindex(progname, '/')) {
+       progname = p + 1;
+  }
+  if (argv[1][0] == '-') {
+       switch(argv[1][1]) {
+       case 'd':
+               debug++;
+               break;
+       default:
+               fatal(usage, progname);
+       }
+       argv++;
+       argc--;
+  }
+  if (argc > 3) {
+       fatal(usage, progname);
+  }
+  AckObj = argv[1] ? argv[1] : "a.out";
+  if (argc == 3) AObj = argv[2];
+  init_idf();
+  init_types();
+  init_scope();
+  init_languages();
+  if (DbxRead(AckObj) && AObj == 0) AObj = AckObj;
+  else if (AObj == 0) AObj = "a.out";
+  reserve(tkidf);
+  if (currfile) CurrentScope = currfile->sy_file->f_scope;
+  if (! init_run()) {
+       fatal("something wrong with file descriptors");
+  }
+  prompt();
+  Commands();
+  fputc( '\n', db_out);
+  exit(0);
+}
+
+prompt()
+{
+  if (isatty(fileno(db_in))) {
+       fprintf(db_out, "%s -> ", progname);
+       fflush(db_out);
+  }
+}
+
+/*VARARGS1*/
+fatal(va_alist)
+  va_dcl
+{
+  va_list ap;
+  char *fmt;
+
+  va_start(ap);
+  {
+       fmt = va_arg(ap, char *);
+       fprintf(stderr, "%s: ", progname);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+  }
+  va_end(ap);
+  abort();
+  exit(1);
+}
+
+extern int errorgiven;
+
+/*VARARGS1*/
+error(va_alist)
+  va_dcl
+{
+  va_list ap;
+  char *fmt;
+
+  va_start(ap);
+  {
+       fmt = va_arg(ap, char *);
+       fprintf(stderr, "%s: ", progname);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+  }
+  va_end(ap);
+  errorgiven = 1;
+}
+
+rd_fatal()
+{
+  fatal("read error in %s", AckObj);
+}
+
+No_Mem()
+{
+  fatal("out of memory");
+}
diff --git a/util/grind/make.allocd b/util/grind/make.allocd
new file mode 100755 (executable)
index 0000000..c4dd3e1
--- /dev/null
@@ -0,0 +1,26 @@
+sed -e '
+s:^.*[         ]ALLOCDEF[      ].*"\(.*\)"[    ]*\([0-9][0-9]*\).*$:\
+/* allocation definitions of struct \1 */\
+extern char *st_alloc();\
+extern struct \1 *h_\1;\
+#ifdef DEBUG\
+extern int cnt_\1;\
+extern char *std_alloc();\
+#define        new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
+#else\
+#define        new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
+#endif\
+#define        free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
+:' -e '
+s:^.*[         ]STATICALLOCDEF[        ].*"\(.*\)"[    ]*\([0-9][0-9]*\).*$:\
+/* allocation definitions of struct \1 */\
+extern char *st_alloc();\
+struct \1 *h_\1;\
+#ifdef DEBUG\
+int cnt_\1;\
+#define        new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
+#else\
+#define        new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
+#endif\
+#define        free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
+:'
diff --git a/util/grind/make.next b/util/grind/make.next
new file mode 100755 (executable)
index 0000000..812adf6
--- /dev/null
@@ -0,0 +1,6 @@
+sed -n '
+s:^.*[         ]ALLOCDEF[      ].*"\(.*\)".*$:struct \1 *h_\1 = 0;\
+#ifdef DEBUG\
+int cnt_\1 = 0;\
+#endif:p
+' $*
diff --git a/util/grind/make.ops b/util/grind/make.ops
new file mode 100755 (executable)
index 0000000..35235db
--- /dev/null
@@ -0,0 +1,18 @@
+awk '
+BEGIN  { n = 0 }
+       { print "#define " $1 " " n; n++
+         if ($3 !~ /0/) print "extern int " $3 "();" ;
+       }
+' < $1 > ops.h
+
+cat > ops.c <<'EOF'
+#include "operator.h"
+#include "ops.h"
+
+t_operator operators[] = {
+EOF
+awk '  { print "{ " $2 ", " $3 "}, /* " $1 " */" }' < $1 >> ops.c
+cat >> ops.c <<'EOF'
+{ 0, 0 }
+};
+EOF
diff --git a/util/grind/make.tokcase b/util/grind/make.tokcase
new file mode 100755 (executable)
index 0000000..8a551b8
--- /dev/null
@@ -0,0 +1,36 @@
+cat <<'--EOT--'
+/* Generated by make.tokcase */
+/* $Header$ */
+#include "Lpars.h"
+
+char *
+symbol2str(tok)
+       int tok;
+{
+#define SIZBUF 8
+       /* allow for a few invocations in f.i. an argument list */
+       static char buf[SIZBUF] = { '\'', 0, '\'', 0, '\'', 0, '\'', 0};
+       static int index = 1;
+
+       switch (tok) {
+--EOT--
+
+sed '
+/{[A-Z]/!d
+s/.*{\(.*\),.*\(".*"\).*$/     case \1 :\
+               return \2;/
+'
+
+cat <<'--EOT--'
+       default:
+               if (tok <= 0) return "end of file";
+               if (tok == '\n') return "<newline>";
+               if (tok < 040 || tok >= 0177) {
+                       return "bad token";
+               }
+               index = (index+4) & (SIZBUF-1);
+               buf[index] = tok;
+               return &buf[index-1];
+       }
+}
+--EOT--
diff --git a/util/grind/make.tokfile b/util/grind/make.tokfile
new file mode 100755 (executable)
index 0000000..494b7e3
--- /dev/null
@@ -0,0 +1,6 @@
+sed '
+/{[A-Z]/!d
+s/.*{//
+s/,.*//
+s/.*/%token    &;/
+'
diff --git a/util/grind/message.h b/util/grind/message.h
new file mode 100644 (file)
index 0000000..1a090ba
--- /dev/null
@@ -0,0 +1,59 @@
+/* $Header$ */
+
+#define BUFLEN 24      /* size of buffer in message header */
+
+struct message_hdr {
+  int  m_type;
+/* Possible values of m_type: */
+#define DB_RUN 020000  /* set for commands that cause child to run */
+#define        SETBP    0      /* set breakpoint at address in m_size */
+#define        CLRBP    1      /* clear breakpoint at address in m_size */
+#define        SETSS    (2|DB_RUN)     /* set single stepping, # of steps in m_size */
+#define SETSSF  (3|DB_RUN)     /* set single stepping, counting calls as one step */
+#define        GETEMREGS 4     /* get EM registers, m_size contains level */
+#define        GETBYTES 5      /* get data; m_size contains size, m_buf contains address */
+#define GETSTR  6      /* get string; m_buf contains address */
+#define SETBYTES 7     /* set data; m_buf contains address, m_size contains size */
+#define CALL    8      /* call function; 
+                          m_size contains size of parameter buffer,
+                          m_buf contains address + size of function result
+                       */
+#define CONT    (9|DB_RUN)     /* continue */
+#define        SETEMREGS 10    /* set EM registers, m_size contains level
+                          Actually, only the program counter is set.
+                       */
+#define DB_SS  040000  /* debugger wants single stepping (to be orred with
+                          SETSS(F) or CONT
+                       */
+#define CLRSS  12      /* clear single stepping */
+#define DUMP   13      /* dump command */
+#define DGLOB  14      /* data area */
+#define DSTACK 15      /* stack area */
+#define SETTRACE 16    /* start tracing; range in m_mes */
+#define CLRTRACE 17    /* end tracing */
+
+#define        OK      50      /* answer of child to most messages */
+#define FAIL   51      /* answer of child when something goes wrong */
+#define DATA   52      /* answer of child when data requested */
+#define END_SS 53      /* when stopped because of user single stepping */
+  long m_size;         /* size */
+  char m_buf[BUFLEN];  /* some of the data required included in message */
+};
+
+#define        LB_OFF  0
+#define AB_OFF 1
+#define PC_OFF 2
+#define HP_OFF 3
+#define SP_OFF 4
+
+#define IN_FD  3
+#define OUT_FD 6
+
+#define BUFTOL(c)      (*((long *) (c)))
+#define LTOBUF(c,l)    (*((long *) (c)) = (l))
+#define BUFTOA(c)      (*((char **) (c)))
+#define ATOBUF(c,p)    (*((char **) (c)) = (p))
+#define BUFTOS(c)      (*((short *) (c)))
+#define BUFTOI(c)      (*((int *) (c)))
+#define BUFTOF(c)      (*((float *) (c)))
+#define BUFTOD(c)      (*((double *) (c)))
diff --git a/util/grind/modula-2.c b/util/grind/modula-2.c
new file mode 100644 (file)
index 0000000..10a351a
--- /dev/null
@@ -0,0 +1,61 @@
+/* $Header$ */
+
+/* Language dependant support; this one is for Modula-2 */
+
+#include <stdio.h>
+
+#include "langdep.h"
+
+extern FILE *db_out;
+
+static int
+       print_string();
+
+static long
+       array_elsize();
+
+static struct langdep m2 = {
+       "%ld",
+       "%loB",
+       "%lXH",
+       "%lu",
+       "%lXH",
+       "%g",
+       "%oC",
+
+       "[",
+       "]",
+       "(",
+       ")",
+       "{",
+       "}",
+
+       print_string,
+       array_elsize
+};
+
+struct langdep *m2_dep = &m2;
+
+static int
+print_string(s)
+  char *s;
+{
+  register char        *str = s;
+  int delim = '\'';
+
+  while (*str) {
+       if (*str++ == '\'') delim = '"';
+  }
+  fprintf(db_out, "%c%s%c", delim, s, delim);
+}
+
+extern long    int_size;
+
+static long
+array_elsize(size)
+  long size;
+{
+  if (! (int_size % size)) return size;
+  if (! (size % int_size)) return size;
+  return ((size + int_size - 1) / int_size) * int_size;
+}
diff --git a/util/grind/op_tools.amk b/util/grind/op_tools.amk
new file mode 100644 (file)
index 0000000..fd5b047
--- /dev/null
@@ -0,0 +1,14 @@
+MAKE_OPS = make.ops;
+
+%instance deftypesuffix(op_tab, '%.ot');
+
+%tool gen_ops (
+    ops:       %in  [type = op_tab];
+    cfile:     %out [type = C-src]     => ops.c;
+    hfile:     %out [type = C-incl]    => ops.h;
+    mkops:     %in  [type = command]   => $MAKE_OPS;
+)
+{
+    exec($mkops, args => $ops);
+    echo({$cfile, 'and', $hfile, 'created'});
+};
diff --git a/util/grind/operator.h b/util/grind/operator.h
new file mode 100644 (file)
index 0000000..0435ada
--- /dev/null
@@ -0,0 +1,12 @@
+/* $Header$ */
+
+#include "ops.h"
+
+typedef struct operator {
+       int     op_nargs;
+       int     (*op_fun)();
+} t_operator, *p_operator;
+
+extern t_operator operators[];
+
+#define nargs(n)       (operators[(n)].op_nargs)
diff --git a/util/grind/operators.ot b/util/grind/operators.ot
new file mode 100644 (file)
index 0000000..01f2d49
--- /dev/null
@@ -0,0 +1,24 @@
+OP_LIST                2       do_list
+OP_FILE                1       do_file
+OP_LINK                2       0
+OP_RUN         1       start_child
+OP_INPUT       1       0
+OP_OUTPUT      1       0
+OP_INTEGER     0       0
+OP_NAME                0       0
+OP_AT          0       0
+OP_IN          1       0
+OP_STOP                2       do_stop
+OP_WHEN                3       do_stop
+OP_CONT                2       do_continue
+OP_STEP                0       do_step
+OP_NEXT                0       do_next
+OP_REGS                0       do_regs
+OP_WHERE       0       do_where
+OP_STATUS      0       do_status
+OP_DELETE      0       do_delete
+OP_SELECT      2       0
+OP_PRINT       1       do_print
+OP_DUMP                0       do_dump
+OP_RESTORE     0       do_restore
+OP_TRACE       3       do_trace
diff --git a/util/grind/position.c b/util/grind/position.c
new file mode 100644 (file)
index 0000000..c22725a
--- /dev/null
@@ -0,0 +1,196 @@
+/* $Header$ */
+
+#include       <stdio.h>
+#include       <assert.h>
+#include       <alloc.h>
+#include       <out.h>
+#include       <stb.h>
+
+#include       "position.h"
+#include       "scope.h"
+#include       "file.h"
+#include       "idf.h"
+#include       "symbol.h"
+
+extern FILE    *db_out;
+
+static p_file  mapping;
+static int     nfiles = 0;
+
+/* static p_file get_map_from_addr(t_addr t);
+   Returns the file entry that contains the code at the address 't',
+   or 0 if there is no information available, or 't' represents an address
+   below the start address of the first file.
+*/
+static p_file
+get_map_from_addr(t)
+  t_addr t;
+{
+  register p_file p = mapping, oldp = 0;
+
+  /* linear search is probably acceptable here */
+  while (p && p->f_start->on_valu <= t) {
+       oldp = p;
+       p = p->f_nextmap;
+  }
+  return oldp ? oldp : p->f_start->on_valu <= t ? p : 0;
+}
+
+/* extern char *get_filename_from_addr(t_addr t);
+   Returns the source filename that contains the code at the address 't',
+   or 0 if there is no information available, or 't' represents an address
+   below the start address of the first file.
+*/
+char *
+get_filename_from_addr(t)
+  t_addr t;
+{
+  register p_file map = get_map_from_addr(t);
+
+  if (! map) return 0;
+  return map->f_sym->sy_idf->id_text;
+}
+
+/* extern t_lineno get_lineno_from_addr(t_addr t);
+   Returns the source line number of the line that contains the code at address
+   't'.  0 is returned if no source line number could be found.
+*/
+t_lineno
+get_lineno_from_addr(t)
+  t_addr t;
+{
+  p_position p;
+
+  p = get_position_from_addr(t);
+  return p == 0 ? 0 : p->lineno;
+}
+
+/* extern p_position get_position_from_addr(t_addr t);
+   Returns a pointer to a structure containing the source position of the code
+   at address 't'.  0 is returned if no source position could be found.
+*/
+p_position
+get_position_from_addr(t)
+  t_addr t;
+{
+  register p_file map = get_map_from_addr(t);
+  static t_position retval;
+  register int i,j,m;
+
+  if (! map) return 0;
+  i = 0;
+  j = map->f_end - map->f_start;
+  do {
+       m = ((i + j) >> 1) + ((i + j) & 1);
+       while ((map->f_start[m].on_type >> 8) != N_SLINE) m++;
+       assert(m <= j);
+       if (map->f_start[m].on_valu > t) {
+               j = m - 1;
+               while (j > i && (map->f_start[j].on_type >> 8) != N_SLINE) j--;
+       }
+       else    i = m;
+  } while (i < j);
+  retval.filename = map->f_sym->sy_idf->id_text;
+  retval.lineno = map->f_start[j].on_desc;
+  return &retval;
+}
+
+/* extern t_addr get_addr_from_position(p_position p);
+   Returns the address of the code at position 'p', or ILL_ADDR if it could
+   not be found. If there is no symbolic information for the filename in
+   position 'p', an error message will be given.
+*/
+t_addr
+get_addr_from_position(p)
+  p_position p;
+{
+  register p_symbol sym = Lookup(findidf(p->filename), PervasiveScope, FILESYM);
+
+  if (sym) {
+       register unsigned int i;
+       register p_file map = sym->sy_file;
+
+       for (i = p->lineno; i > 0; i--) {
+               register struct outname *n = map->f_line_addr[HASH(i)];
+
+               while (n) {
+                       if (n->on_desc == i) return (t_addr) n->on_valu;
+                       n = next_outname(n);
+               }
+       }
+       return ILL_ADDR;
+  }
+  error("no symbolic information for file %s", p->filename);
+  return ILL_ADDR;
+}
+
+/* extern add_position_addr(char *filename, struct outname *n);
+   Adds the ('filename','lineno'),'t' pair to the mapping information.
+*/
+add_position_addr(filename, n)
+  char *filename;
+  register struct outname *n;
+{
+  static char *lastfile = 0;
+  static p_file lastmap = 0;
+  register p_file map = lastmap;
+
+  if (filename != lastfile) {  /* new file ... */
+       register p_symbol sym;
+
+       nfiles++;
+       lastfile = filename;
+       if (! filename) {       /* last call */
+               return;
+       }
+       sym = Lookup(findidf(filename), PervasiveScope, FILESYM);
+       if (sym) map = sym->sy_file; 
+       else {
+               sym = add_file(filename);
+               map = sym->sy_file;
+               map->f_scope = FileScope;
+       }
+       if (! mapping) mapping = map;
+       else lastmap->f_nextmap = map;
+       lastmap = map;
+       map->f_start = n;
+  }
+  else map = lastmap;
+  map->f_end = n;
+  setnext_outname(n, map->f_line_addr[HASH(n->on_desc)]);
+  map->f_line_addr[HASH(n->on_desc)] = n;
+}
+
+/* extern struct scope  *get_scope_from_position(p_position p);
+   Returns the scope of the code at position 'p', or 0 if it could not be found.
+*/
+struct scope *
+get_scope_from_position(p)
+  p_position p;
+{
+  t_addr a = get_addr_from_position(p);
+
+  if (a != ILL_ADDR) {
+       return get_scope_from_addr(a);
+  }
+  return 0;
+}
+
+/* extern p_position print_position(t_addr a, int print_function);
+   Prints position 'a' and returns it. If 'print_function' is set,
+   an attempt is made to print the function name as well.
+*/
+p_position
+print_position(a, print_function)
+  t_addr       a;
+  int          print_function;
+{
+  register p_scope     sc = base_scope(get_scope_from_addr(a));
+  register p_position  pos = get_position_from_addr(a);
+
+  if (sc && print_function) {
+       fprintf(db_out, "in %s ", sc->sc_definedby->sy_idf->id_text);
+  }
+  if (pos) fprintf(db_out, "at \"%s\":%u", pos->filename, pos->lineno);
+  return pos;
+}
diff --git a/util/grind/position.h b/util/grind/position.h
new file mode 100644 (file)
index 0000000..be5b036
--- /dev/null
@@ -0,0 +1,57 @@
+/* $Header$ */
+
+/* maps from address to filename-lineno pair and reverse,
+   maps from filename-lineno pair or address to scope.
+*/
+
+typedef unsigned int   t_lineno;
+typedef long           t_addr;
+#define ILL_ADDR       ((t_addr) -1)
+#define NO_ADDR                ((t_addr) -3)
+
+typedef struct pos {
+  t_lineno     lineno;
+  char         *filename;
+} t_position, *p_position;
+
+/* extern char *get_filename_from_addr(t_addr t);
+   Returns the source filename that contains the code at the address 't',
+   or 0 if there is no information available, or 't' represents an address
+   below the start address of the first file.
+*/
+extern char            *get_filename_from_addr();
+
+/* extern t_lineno     get_lineno_from_addr(t_addr t);
+   Returns the source line number of the line that contains the code at address
+   't'.  0 is returned if no source line number could be found.
+*/
+extern t_lineno                get_lineno_from_addr();
+
+/* extern p_position   get_position_from_addr(t_addr t);
+   Returns a pointer to a structure containing the source position of the code
+   at address 't'.  0 is returned if no source position could be found.
+*/
+extern p_position      get_position_from_addr();
+
+/* extern t_addr       get_addr_from_position(p_position p);
+   Returns the address of the code at position 'p', or ILL_ADDR if it could
+   not be found. If there is no symbolic information for the filename in
+   position 'p', an error message will be given.
+*/
+extern t_addr          get_addr_from_position();
+
+/* extern      add_position_addr(char *filename, struct outname *n);
+   Adds the ('filename','n'->on_desc),'n'->on_valu pair to the mapping information.
+*/
+extern                         add_position_addr();
+
+/* extern struct scope *get_scope_from_position(p_position p);
+   Returns the scope of the code at position 'p', or 0 if it could not be found.
+*/
+extern struct scope    *get_scope_from_position();
+
+/* extern p_position print_position(t_addr a, int print_function);
+   Prints position 'a' and returns it. If 'print_function' is set,
+   an attempt is made to print the function name as well.
+*/
+extern p_position      print_position();
diff --git a/util/grind/print.c b/util/grind/print.c
new file mode 100644 (file)
index 0000000..bab80bb
--- /dev/null
@@ -0,0 +1,322 @@
+/* $Header$ */
+
+#include <alloc.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "type.h"
+#include "message.h"
+#include "langdep.h"
+#include "scope.h"
+#include "symbol.h"
+#include "position.h"
+#include "idf.h"
+
+extern FILE *db_out;
+extern long float_size, pointer_size, int_size;
+
+static
+print_literal(tp, v)
+  p_type       tp;
+  int          v;
+{
+  register struct literal *lit = tp->ty_literals;
+  register int i;
+
+  for (i = tp->ty_nenums; i; i--, lit++) {
+       if (lit->lit_val == v) {
+               fprintf(db_out, lit->lit_name);
+               break;
+       }
+  }
+  if (! i) {
+       fprintf(db_out, "unknown enumeration value %d", v);
+  }
+}
+
+static
+print_unsigned(tp, v)
+  p_type       tp;
+  long         v;
+{
+  if (tp == uchar_type) {
+       fprintf(db_out, currlang->char_fmt, (int) v);
+  }
+  else fprintf(db_out, currlang->uns_fmt, v);
+}
+
+static
+print_integer(tp, v)
+  p_type       tp;
+  long         v;
+{
+  if (tp == char_type) {
+       fprintf(db_out, currlang->char_fmt, (int) v);
+  }
+  else fprintf(db_out, currlang->decint_fmt, v);
+}
+
+print_params(tp, AB, static_link)
+  p_type       tp;
+  t_addr       AB;
+{
+  char *param_bytes;
+  register char *p;
+  register int i;
+  register struct param *par;
+  long size;
+
+  if (! tp) return;
+  assert(tp->ty_class == T_PROCEDURE);
+
+  if ((i = tp->ty_nparams) == 0) return;
+
+  /* get parameter bytes */
+  par = tp->ty_params;
+  size = tp->ty_nbparams;
+  if (static_link) size += pointer_size;
+  param_bytes = p = Malloc((unsigned)size);
+  if (static_link) p += pointer_size;
+  if (! get_bytes(size, AB, param_bytes)) {
+       error("no debuggee");
+       free(param_bytes);
+       return;
+  }
+
+  while (i--) {
+       if (par->par_kind == 'v' || par->par_kind == 'i') {
+               /* call by reference parameter, or
+                  call by value parameter, but address is passed;
+                  try and get value.
+               */
+               char    *q;
+
+               if ((size = par->par_type->ty_size) == 0) {
+                       size = compute_size(par->par_type, param_bytes);
+               }
+               q = Malloc((unsigned) size);
+               if (! get_bytes(size, (t_addr) BUFTOA(p), q)) {
+                       fprintf(db_out, currlang->addr_fmt, BUFTOA(p));
+               }
+               else {
+                       print_val(par->par_type, q, 1, 0, param_bytes);
+               }
+               free(q);
+       }
+       else print_val(par->par_type, p, 1, 0, param_bytes);
+       if (i) fputs(", ", db_out);
+       p += param_size(par->par_type, par->par_kind);
+       par++;
+  }
+  free(param_bytes);
+}
+
+print_val(tp, addr, compressed, indent, AB)
+  p_type       tp;             /* type of value to be printed */
+  char         *addr;          /* address to get value from */
+  int          compressed;     /* for parameter lists */
+  int          indent;         /* indentation */
+  char         *AB;            /* argument base for dynamic subranges */
+{
+  long sz;
+  register int i;
+  long elsize;
+
+  if (indent == 0) indent = 4;
+  switch(tp->ty_class) {
+  case T_SUBRANGE:
+       print_val(tp->ty_base, addr, compressed, indent, AB);
+       break;
+  case T_ARRAY:
+       if (tp->ty_elements == char_type ||
+           tp->ty_elements == uchar_type) {
+               print_val(string_type, addr, compressed, indent, AB);
+               break;
+       }
+       if ((sz = tp->ty_size) == 0) sz = compute_size(tp, AB);
+       if (compressed) {
+               fprintf(db_out, currlang->open_array_display);
+       }
+       else {
+               fprintf(db_out, "\n%*c%s%*c",
+                       indent,
+                       ' ',
+                       currlang->open_array_display,
+                       4-strlen(currlang->open_array_display), ' ');
+       }
+       indent += 4;
+       elsize = (*currlang->arrayelsize)(tp->ty_elements->ty_size);
+       for (i = sz/elsize; i; i--) {
+               print_val(tp->ty_elements, addr, compressed, indent, AB);
+               addr += elsize;
+               if (compressed && i > 1) {
+                       fprintf(db_out, ", ...");
+                       break;
+               } 
+               if (i > 1) {
+                       fputc(',', db_out);
+               }
+               fprintf(db_out, "\n%*c", i > 1 ? indent : indent - 4, ' ');
+       }
+       fprintf(db_out, currlang->close_array_display);
+       indent -= 4;
+       break;
+  case T_STRUCT: {
+       register struct fields *fld = tp->ty_fields;
+
+       if (compressed) {
+               fprintf(db_out, currlang->open_struct_display);
+       }
+       else {
+               fprintf(db_out, "\n%*c%s%*c",
+                       indent,
+                       ' ',
+                       currlang->open_struct_display,
+                       4-strlen(currlang->open_struct_display), ' ');
+       }
+       indent += 4;
+       for (i = tp->ty_nfields; i; i--, fld++) {
+               if (! compressed) fprintf(db_out, "%s = ", fld->fld_name);
+               if (fld->fld_bitsize != fld->fld_type->ty_size << 3) {
+                       /* apparently a bit field */
+                       /* ??? */
+                       fprintf(db_out, "<bitfield, %d, %d>", fld->fld_bitsize, fld->fld_type->ty_size);
+               }
+               else print_val(fld->fld_type, addr+(fld->fld_pos>>3), compressed, indent, AB);
+               if (compressed && i > 1) {
+                       fprintf(db_out, ", ...");
+                       break;
+               } 
+               if (i > 1) {
+                       fputc(',', db_out);
+               }
+               fprintf(db_out, "\n%*c", i > 1 ? indent : indent - 4, ' ');
+       }
+       indent -= 4;
+       fprintf(db_out, currlang->close_struct_display);
+       break;
+       }
+  case T_UNION:
+       fprintf(db_out, "<union>");
+       break;
+  case T_ENUM:
+       print_literal(tp,  tp->ty_size == 1 
+                          ? (*addr & 0xFF)
+                          : tp->ty_size == 2
+                             ? (BUFTOS(addr) & 0xFFFF)
+                             : (int) BUFTOL(addr));
+       break;
+  case T_PROCEDURE: {
+       register p_scope sc = get_scope_from_addr((t_addr) BUFTOA(addr));
+
+       if (sc && sc->sc_definedby) {
+               fprintf(db_out, sc->sc_definedby->sy_idf->id_text);
+               break;
+       }
+       }
+       /* Fall through */
+  case T_POINTER:
+       fprintf(db_out, currlang->addr_fmt, (long) BUFTOA(addr));
+       break;
+  case T_FILE:
+       fprintf(db_out, "<file>");
+       break;
+  case T_SET: {
+       long    val = tp->ty_setlow;
+       p_type  base = tp->ty_setbase;
+       long    nelements = tp->ty_size << 3;
+       int     count = 0;
+       int     rsft = 3 + (int_size == 2 ? 1 : 2);
+       long    mask = int_size == 2 ? 0xFFFF : 0xFFFFFFFF;
+
+       if (base->ty_class == T_SUBRANGE) base = base->ty_base;
+       if (compressed) {
+               fprintf(db_out, currlang->open_set_display);
+       }
+       else {
+               fprintf(db_out, "\n%*c%s%*c",
+                       indent,
+                       ' ',
+                       currlang->open_set_display,
+                       4-strlen(currlang->open_set_display), ' ');
+       }
+       indent += 4;
+       for (i = 0; i < nelements; i++) {
+               if (*((int *) addr + (i >> rsft)) & (1 << (i & mask))) {
+                       count++;
+                       if (count > 1) {
+                               if (compressed) {
+                                       fprintf(db_out, ", ...");
+                                       break;
+                               }
+                               fprintf(db_out, ",\n%*c", indent , ' ');
+                       }
+                       switch(base->ty_class) {
+                       case T_INTEGER:
+                               print_integer(base, val+i);
+                               break;
+                       case T_UNSIGNED:
+                               print_unsigned(base, val+i);
+                               break;
+                       case T_ENUM:
+                               print_literal(base, (int)val+i);
+                               break;
+                       default:
+                               assert(0);
+                       }
+               } 
+       }
+       if (! compressed) {
+               fprintf(db_out, "\n%*c", indent-4 , ' ');
+       }
+       indent -= 4;
+       fprintf(db_out, currlang->close_set_display);
+       }
+       break;
+  case T_REAL: {
+       double val = tp->ty_size == float_size
+               ? BUFTOF(addr)
+               : BUFTOD(addr);
+       fprintf(db_out, currlang->real_fmt, val);
+       break;
+       }
+  case T_UNSIGNED:
+       print_unsigned(tp, tp->ty_size == 1 
+                               ? (*addr & 0xFF)
+                               : tp->ty_size == 2
+                                   ? (BUFTOS(addr) & 0xFFFF)
+                                   : BUFTOL(addr));
+       break;
+  case T_INTEGER:
+       print_integer(tp, tp->ty_size == 1 
+                               ? *addr
+                               : tp->ty_size == 2
+                                   ? BUFTOS(addr)
+                                   : BUFTOL(addr));
+       break;
+  case T_STRING:
+       (*currlang->printstring)(addr);
+       break;
+  default:
+       assert(0);
+       break;
+  }
+}
+
+int
+print_sym(sym)
+  p_symbol     sym;
+{
+  char         *buf;
+  char         *AB;
+
+  if (get_value(sym, &buf, &AB)) {
+       fputs(" = ", db_out);
+       print_val(sym->sy_type, buf, 0, 0, AB);
+       if (buf) free(buf);
+       if (AB) free(AB);
+       fputs("\n", db_out);
+       return 1;
+  }
+  return 0;
+}
diff --git a/util/grind/rd.c b/util/grind/rd.c
new file mode 100644 (file)
index 0000000..40c292d
--- /dev/null
@@ -0,0 +1,134 @@
+/* $Header$ */
+
+/* a.out file reading ... */
+
+#include "rd.h"
+
+#if defined(sun) && defined(mc68020)
+
+#include <a.out.h>
+#include <stdio.h>
+
+static FILE *inf;
+static struct exec bh;
+static long seg_strings;
+static struct outhead hh;
+
+#define readf(a, b, c) (fread((char *)(a), (b), (int)(c), inf))
+
+int
+rd_open(f)
+  char *f;
+{
+  if ((inf = fopen(f, "r")) == NULL) return 0;
+  return 1;
+}
+
+rd_ohead(h)
+  struct outhead       *h;
+{
+  if (! readf(&bh, sizeof(struct exec), 1)) rd_fatal();
+  if (N_BADMAG(bh)) rd_fatal();
+
+  h->oh_magic = O_CONVERTED;
+  h->oh_stamp = 0;
+  h->oh_nsect = 4;
+  h->oh_nname = 3 + bh.a_syms / sizeof(struct nlist);
+  h->oh_nrelo = (bh.a_trsize + bh.a_drsize) / sizeof(struct reloc_info_68k);
+  h->oh_flags = h->oh_nrelo ? HF_LINK : 0;
+  if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
+  h->oh_nemit = bh.a_text + bh.a_data;
+  if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
+  fseek(inf, N_STROFF(bh), 0);
+  h->oh_nchar = getw(inf) + 6 + 6 + 5 - 4; /* ".text", ".data", ".bss",
+                                             minus the size word */
+  seg_strings = h->oh_nchar - 17;
+  if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
+  fseek(inf, sizeof(struct exec) + bh.a_text + bh.a_data, 0);
+  hh = *h;
+}
+
+/*ARGSUSED1*/
+rd_name(names, count)
+  register struct outname      *names;
+  unsigned int         count;  /* ignored; complete namelist is read */
+{
+  names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh);
+  names->on_desc = 0; names->on_type = S_MIN | S_SCT;
+  names++;
+  names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 6;
+  names->on_desc = 0; names->on_type = (S_MIN+2) | S_SCT;
+  names++;
+  names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 12;
+  names->on_desc = 0; names->on_type = (S_MIN+3) | S_SCT;
+  names++;
+  count = bh.a_syms / sizeof(struct nlist);
+  while (count > 0) {
+       struct nlist n;
+
+       if (! readf(&n, sizeof(struct nlist), 1)) rd_fatal();
+       count--;
+       names->on_desc = n.n_desc;
+       if (n.n_un.n_strx - 4 < 0) names->on_foff = 0;
+       else names->on_foff = OFF_CHAR(hh) - 4 + n.n_un.n_strx;
+       names->on_valu = n.n_value;
+
+       if (n.n_type & N_STAB) {
+               names->on_type = n.n_type << 8;
+               names++;
+               continue;
+       }
+       switch(n.n_type & ~N_EXT) {
+       case N_ABS:
+               names->on_type = S_ABS;
+               break;
+       case N_TEXT:
+               names->on_type = S_MIN;
+               break;
+       case N_DATA:
+               names->on_type = S_MIN + 2;
+               names->on_valu -= bh.a_text;
+               break;
+       case N_BSS:
+               names->on_type = S_MIN + 3;
+               names->on_valu -= bh.a_text + bh.a_data;
+               break;
+       case N_UNDF:
+               if (! names->on_valu) {
+                       names->on_type = S_UND;
+                       break;
+               }
+               names->on_type = (S_MIN + 3) | S_COM;
+               break;
+       case N_FN:
+               names->on_type = S_FIL;
+               break;
+       default:
+               rd_fatal();
+       }
+       if (n.n_type & N_EXT) names->on_type |= S_EXT;
+       names++;
+  }
+}
+
+extern char    *strcpy();
+
+rd_string(strings, count)
+  register char        *strings;
+  long count;
+{
+  if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
+  fseek(inf, N_STROFF(bh)+4, 0);
+  if (! readf(strings, (int)count-17, 1)) rd_fatal();
+  strings += count-17;
+  strcpy(strings, ".text"); strings += 6;
+  strcpy(strings, ".data"); strings += 6;
+  strcpy(strings, ".bss");
+}
+
+rd_close()
+{
+  fclose(inf);
+}
+
+#endif
diff --git a/util/grind/rd.h b/util/grind/rd.h
new file mode 100644 (file)
index 0000000..57aa924
--- /dev/null
@@ -0,0 +1,5 @@
+/* $Header$ */
+
+#include       <out.h>
+
+#define O_CONVERTED    0x202
diff --git a/util/grind/run.c b/util/grind/run.c
new file mode 100644 (file)
index 0000000..2ae582e
--- /dev/null
@@ -0,0 +1,523 @@
+/* $Header$ */
+
+/* Running a process and communication */
+
+#include <signal.h>
+#include <stdio.h>
+#include <assert.h>
+#include <alloc.h>
+
+#include "ops.h"
+#include "message.h"
+#include "position.h"
+#include "tree.h"
+#include "file.h"
+#include "symbol.h"
+#include "idf.h"
+#include "scope.h"
+
+#define MAXARG 128
+
+extern char    *strncpy();
+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;
+
+int            db_ss;
+
+static int     catch_sigpipe();
+static int     stopped();
+static int     uputm(), ugetm();
+static int     fild1[2], fild2[2];     /* pipe file descriptors */
+
+int
+init_run()
+{
+  /* take file descriptors so that listing cannot take them */
+  int i;
+
+  for (i = IN_FD; i <= OUT_FD; i++) close(i);
+  if (pipe(fild1) < 0 ||
+      pipe(fild2) < 0 ||
+      fild1[0] != IN_FD ||
+      fild2[1] != OUT_FD) {
+       return 0;
+  }
+  to_child = fild1[1];
+  from_child = fild2[0];
+  return 1;
+}
+
+int
+start_child(p)
+  p_tree       p;
+{
+  /* start up the process to be debugged and set up communication */
+
+  char *argp[MAXARG];                          /* argument list */
+  register p_tree pt = p->t_args[0], pt1;
+  unsigned int nargs = 1;                      /* #args */
+  char *in_redirect = 0;                       /* standard input redirected */
+  char *out_redirect = 0;                      /* standard output redirected */
+
+  signal_child(SIGKILL); /* like families in China, this debugger is only
+                           allowed one child
+                        */
+
+  /* first check arguments and redirections and build argument list */
+  while (pt) {
+       switch(pt->t_oper) {
+       case OP_LINK:
+               pt1 = pt->t_args[1];
+               pt = pt->t_args[0];
+               continue;
+       case OP_NAME:
+               if (nargs < (MAXARG-1)) {
+                       argp[nargs++] = pt->t_str;
+               }
+               else {
+                       error("too many arguments");
+                       return 0;
+               }
+               break;
+       case OP_INPUT:
+               if (in_redirect) {
+                       error("input redirected twice?");
+                       return 0;
+               }
+               in_redirect = pt->t_str;
+               break;
+       case OP_OUTPUT:
+               if (out_redirect) {
+                       error("output redirected twice?");
+                       return 0;
+               }
+               out_redirect = pt->t_str;
+               break;
+       }
+       if (pt != pt1) pt = pt1;
+       else break;
+  }
+  argp[0] = AObj;
+  argp[nargs] = 0;
+
+  /* create child process */
+  child_pid = fork();
+  if (child_pid < 0) {
+       error("could not create child");
+       return 0;
+  }
+  if (child_pid == 0) {
+       /* this is the child process */
+       close(fild1[1]);
+       close(fild2[0]);
+
+       signal(SIGINT, SIG_IGN);
+
+       /* I/O redirection */
+       if (in_redirect) {
+               int fd;
+               close(0);
+               if ((fd = open(in_redirect, 0)) < 0) {
+                       error("could not open input file");
+                       exit(-1);
+               }
+               if (fd != 0) {
+                       dup2(fd, 0);
+                       close(fd);
+               }
+       }
+       if (out_redirect) {
+               int fd;
+               close(1);
+               if ((fd = creat(in_redirect, 0666)) < 0) {
+                       error("could not open output file");
+                       exit(-1);
+               }
+               if (fd != 1) {
+                       dup2(fd, 1);
+                       close(fd);
+               }
+       }
+
+       /* and run process to be debugged */
+       execv(AObj, argp);
+       error("could not exec %s", AObj);
+       exit(-1);
+  }
+
+  /* debugger */
+  close(fild1[0]);
+  close(fild2[1]);
+
+  pipe(fild1);         /* to occupy file descriptors */
+  signal(SIGPIPE, catch_sigpipe);
+  if (! wait_for_child((char *) 0)) {
+       error("child not responding");
+       return 0;
+  }
+  do_items();
+  if (! restoring) send_cont(1);
+  return 1;
+}
+
+int
+wait_for_child(s)
+  char *s;             /* to pass on to 'stopped' */
+{
+  struct message_hdr m;
+
+  if (child_pid) {
+       if (ugetm(&m)) {
+               return stopped(s, (t_addr) m.m_size);
+       }
+       return 0;
+  }
+  return 1;
+}
+
+signal_child(sig)
+{
+  if (child_pid) {
+       kill(child_pid, sig);
+       if (sig == SIGKILL) {
+               wait(&child_status);
+               init_run();
+       }
+  }
+}
+
+static int
+catch_sigpipe()
+{
+  child_pid = 0;
+}
+
+
+static int
+ureceive(p, c)
+  char *p;
+  long c;
+{
+  int  i;
+
+  if (! child_pid) return 0;
+
+  while (c >= 0x1000) {
+       i = read(from_child, p, 0x1000);
+       if (i <= 0) {
+               if (i == 0) child_pid = 0;
+               return 0;
+       }
+       p += i;
+       c -= i;
+  }
+  while (c > 0) {
+       i = read(from_child, p, (int)c);
+       if (i <= 0) {
+               if (i == 0) child_pid = 0;
+               return 0;
+       }
+       p += i;
+       c -= i;
+  }
+  return c == 0;
+}
+
+static int
+usend(p, c)
+  char *p;
+  long c;
+{
+  int  i;
+
+  while (c >= 0x1000) {
+       i = write(to_child, p, 0x1000);
+       if (i < 0) return 0;
+       p += i;
+       c -= i;
+  }
+  while (c > 0) {
+       i = write(to_child, p, (int)c);
+       if (i < 0) return 0;
+       p += i;
+       c -= i;
+  }
+  return 1;
+}
+
+static int
+ugetm(message)
+  struct message_hdr *message;
+{
+  if (! ureceive((char *) message, (long) sizeof(struct message_hdr))) {
+       return 0;
+  }
+  if (debug) printf("Got %d\n", message->m_type);
+  return 1;
+}
+
+static int
+uputm(message)
+  struct message_hdr *message;
+{
+  if (! usend((char *) message, (long) sizeof(struct message_hdr))) {
+       return 0;
+  }
+  if (debug) printf("Sent %d\n", message->m_type);
+  return 1;
+}
+
+static struct message_hdr      answer;
+static int     single_stepping;
+
+static int
+stopped(s, a)
+  char *s;     /* stop message */
+  t_addr a;    /* address where stopped */
+{
+  p_position pos;
+
+  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);
+  }
+  return 1;
+}
+
+static int
+could_send(m, stop_message)
+  struct message_hdr   *m;
+{
+  int  type;
+  t_addr a;
+  for (;;) {
+       if (child_pid) {
+               if (! uputm(m) ||
+                   ! ugetm(&answer)) {
+                       if (child_pid) {
+                               error("something wrong!");
+                               return 1;
+                       }
+                       wait(&child_status);
+                       init_run();
+                       if (child_status & 0177) {
+                               fprintf(db_out,
+                                       "Child died with signal %d\n",
+                                       child_status & 0177);
+                       }
+                       else {
+                               fprintf(db_out,
+                                       "Child terminated, exit status %d\n",
+                                       child_status >> 8);
+                       }
+                       return 1;
+               }
+               a = answer.m_size;
+               type = answer.m_type;
+               if (m->m_type & DB_RUN) {
+                       /* run command */
+                       CurrentScope = get_scope_from_addr((t_addr) a);
+                       if (! item_addr_actions(a) &&
+                           ( type == DB_SS || type == OK)) {
+                               /* no explicit breakpoints at this position.
+                                  Also, child did not stop because of
+                                  SETSS or SETSSF, otherwise we would
+                                  have gotten END_SS.
+                                  So, continue.
+                               */
+                               if ((m->m_type & ~ DB_SS) != CONT) {
+                                       m->m_type = CONT | (m->m_type & DB_SS);
+                               }
+                               continue;
+                       }
+                       if (type != END_SS && single_stepping) {
+                               m->m_type = CLRSS;
+                               uputm(m) && ugetm(&answer);
+                       }
+                       single_stepping = 0;
+               }
+               if (stop_message) stopped("stopped", a);
+               return 1;
+       }
+       return 0;
+  }
+  /*NOTREACHED*/
+}
+
+int
+get_bytes(size, from, to)
+  long size;
+  t_addr from;
+  char *to;
+{
+  struct message_hdr   m;
+
+  m.m_type = GETBYTES;
+  m.m_size = size;
+  ATOBUF(m.m_buf, (char *) from);
+
+  if (! could_send(&m, 0)) {
+       return 0;
+  }
+
+  assert(answer.m_type == DATA && answer.m_size == m.m_size);
+
+  return ureceive(to, answer.m_size);
+}
+
+int
+get_dump(globmessage, globbuf, stackmessage, stackbuf)
+  struct message_hdr *globmessage, *stackmessage;
+  char **globbuf, **stackbuf;
+{
+  struct message_hdr   m;
+
+  m.m_type = DUMP;
+  if (! could_send(&m, 0)) {
+       return 0;
+  }
+  assert(answer.m_type == DGLOB);
+  *globmessage = answer;
+  *globbuf = Malloc((unsigned) answer.m_size);
+  if (! ureceive(*globbuf, answer.m_size) || ! ugetm(stackmessage)) {
+       free(*globbuf);
+       return 0;
+  }
+  assert(stackmessage->m_type == DSTACK);
+  *stackbuf = Malloc((unsigned) stackmessage->m_size);
+  if (! ureceive(*stackbuf, stackmessage->m_size)) {
+       free(*globbuf);
+       free(*stackbuf);
+       return 0;
+  }
+  ATOBUF(globmessage->m_buf+SP_OFF*pointer_size,
+        BUFTOA(stackmessage->m_buf+SP_OFF*pointer_size));
+  return 1;
+}
+
+int
+put_dump(globmessage, globbuf, stackmessage, stackbuf)
+  struct message_hdr *globmessage, *stackmessage;
+  char *globbuf, *stackbuf;
+{
+  struct message_hdr m;
+
+  if (! child_pid) {
+       restoring = 1;
+       start_child(run_command);
+       restoring = 0;
+  }
+  return       uputm(globmessage) &&
+               usend(globbuf, globmessage->m_size) &&
+               uputm(stackmessage) &&
+               usend(stackbuf, stackmessage->m_size) &&
+               ugetm(&m) && stopped("restored", m.m_size);
+}
+
+t_addr *
+get_EM_regs(level)
+  int  level;
+{
+  struct message_hdr   m;
+  static t_addr buf[5];
+  register t_addr *to = &buf[0];
+
+  m.m_type = GETEMREGS;
+  m.m_size = level;
+
+  if (! could_send(&m, 0)) {
+       return 0;
+  }
+  *to++ = (t_addr) BUFTOA(answer.m_buf);
+  *to++ = (t_addr) BUFTOA(answer.m_buf+pointer_size);
+  *to++ = (t_addr) BUFTOA(answer.m_buf+2*pointer_size);
+  *to++ = (t_addr) BUFTOA(answer.m_buf+3*pointer_size);
+  *to++ = (t_addr) BUFTOA(answer.m_buf+4*pointer_size);
+  return buf;
+}
+
+int
+set_pc(PC)
+  t_addr       PC;
+{
+  struct message_hdr   m;
+
+  m.m_type = SETEMREGS;
+  m.m_size = 0;
+  ATOBUF(m.m_buf+PC_OFF*pointer_size, (char *)PC);
+  return could_send(&m, 0);
+}
+
+int
+send_cont(stop_message)
+  int  stop_message;
+{
+  struct message_hdr   m;
+
+  m.m_type = (CONT | (db_ss ? DB_SS : 0));
+  m.m_size = 0;
+  return could_send(&m, stop_message);
+}
+
+int
+do_single_step(type, count)
+  int  type;
+  long count;
+{
+  struct message_hdr   m;
+
+  m.m_type = type | (db_ss ? DB_SS : 0);
+  m.m_size = count;
+  single_stepping = 1;
+  if (could_send(&m, 1)) {
+       return 1;
+  }
+  single_stepping = 0;
+  return 0;
+}
+
+int
+set_or_clear_breakpoint(a, type)
+  t_addr       a;
+  int  type;
+{
+  struct message_hdr m;
+
+  if (a == ILL_ADDR || a == NO_ADDR) return 0;
+
+  m.m_type = type;
+  m.m_size = a;
+  if (debug) printf("%s breakpoint at 0x%lx\n", type == SETBP ? "setting" : "clearing", (long) a);
+  if (! could_send(&m, 0)) { }
+
+  return 1;
+}
+
+int
+set_or_clear_trace(start, end, type)
+  t_addr start, end;
+  int  type;
+{
+  struct message_hdr m;
+
+  m.m_type = type;
+  ATOBUF(m.m_buf, (char *) start);
+  ATOBUF(m.m_buf+pointer_size, (char *) end);
+  if (debug) printf("%s trace at [0x%lx,0x%lx]\n", type == SETTRACE ? "setting" : "clearing", (long) start, (long) end);
+  if (! could_send(&m, 0)) { }
+
+  return 1;
+}
diff --git a/util/grind/scope.cc b/util/grind/scope.cc
new file mode 100644 (file)
index 0000000..11863fa
--- /dev/null
@@ -0,0 +1,131 @@
+/* Scope mechanism */
+
+/* $Header$ */
+
+#include       <assert.h>
+#include       <alloc.h>
+#include       <out.h>
+
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+#include       "type.h"
+#include       "symbol.h"
+#include       "scope.h"
+#include       "avl.h"
+
+p_scope PervasiveScope, CurrentScope, FileScope;
+
+/* STATICALLOCDEF "scope" 10 */
+
+static AVL_tree        ScopeTree;
+
+static int
+cmp_starts(s1, s2)
+  char *s1, *s2;
+{
+  register p_scope c1 = (p_scope)s1, c2 = (p_scope)s2;
+
+  return c1->sc_start < c2->sc_start
+        ? -1
+        : c1->sc_start == c2->sc_start
+          ? 0
+          : 1;
+}
+
+/*ARGSUSED*/
+open_scope(name, has_activation)
+  p_symbol name;
+  int has_activation;
+{
+  register p_scope sc = new_scope();
+
+  sc->sc_has_activation_record = has_activation;
+  sc->sc_static_encl = CurrentScope;
+  sc->sc_definedby = name;
+  sc->sc_proclevel = CurrentScope->sc_proclevel;
+                       /* sc_proclevel possibly reset by caller */
+  CurrentScope = sc;
+}
+
+init_scope()
+{
+  register p_scope sc = new_scope();
+
+  PervasiveScope = sc;
+  CurrentScope = sc;
+  open_scope((p_symbol) 0, 0);         /* this one will be closed at the
+                                          first N_SO
+                                       */
+  ScopeTree = create_avl_tree(cmp_starts);
+}
+
+close_scope()
+{
+  register p_scope sc = CurrentScope;
+
+  assert(sc != 0);
+  CurrentScope = sc->sc_static_encl;
+}
+
+add_scope_addr(scope)
+  p_scope      scope;
+{
+  add_to_avl_tree(ScopeTree, (char *)scope);
+}
+
+/* extern p_scope      get_scope_from_addr(t_addr a);
+   Returns the scope of the code at address 'a', or 0 if it could not be found.
+*/
+p_scope
+get_scope_from_addr(a)
+  t_addr a;
+{
+  t_scope sc;
+
+  sc.sc_start = a;
+  return (p_scope) find_ngt(ScopeTree, (char *) &sc);
+}
+
+/* extern p_scope      get_next_scope_from_addr(t_addr a);
+   Returns the scope following the one of the code at address 'a',
+   and that has an activation record,
+   or 0 if it could not be found.
+*/
+p_scope
+get_next_scope_from_addr(a)
+  t_addr a;
+{
+  t_scope sc;
+
+  sc.sc_start = a;
+  for (;;) {
+       p_scope psc = (p_scope) find_nlt(ScopeTree, (char *) &sc);
+       if (! psc || psc->sc_has_activation_record) return psc;
+       sc.sc_start = psc->sc_start+1;
+  }
+  /*NOTREACHED*/
+}
+
+/* extern int  has_static_link(p_scope sc);
+   Returns 1 if the procedure of this scope takes a static link.
+*/
+int
+has_static_link(sc)
+  register p_scope     sc;
+{
+  return sc->sc_proclevel > 1;
+}
+
+/* extern p_scope      base_scope(p_scope sc);
+   Returns the closest enclosing scope of 'sc' that has an activation record.
+*/
+p_scope
+base_scope(sc)
+  register p_scope     sc;
+{
+  while (sc && ! sc->sc_has_activation_record) {
+       sc = sc->sc_static_encl;
+  }
+  return sc;
+}
diff --git a/util/grind/scope.h b/util/grind/scope.h
new file mode 100644 (file)
index 0000000..20b4c78
--- /dev/null
@@ -0,0 +1,54 @@
+/* scope structure */
+
+/* $Header$ */
+
+typedef struct scope {
+  struct scope *sc_static_encl;        /* linked list of enclosing scopes */
+  struct symbol *sc_symbs;             /* symbols defined in this scope */
+  struct symbol *sc_definedby;         /* symbol defining this scope */
+  long         sc_start;               /* start address of code of this scope */
+  long         sc_bp_opp;              /* first breakpoint opportunity */
+  short                sc_proclevel;           /* proc level of this scope */
+  char         sc_has_activation_record;
+} t_scope, *p_scope;
+
+extern p_scope PervasiveScope, CurrentScope, FileScope;
+
+/* extern      init_scope();
+   Initializes the scope routines.
+*/
+extern init_scope();
+
+/* extern      open_scope(struct symbol *name, int has_activation);
+   Opens a new scope and assigns it to CurrentScope; The new scope is defined
+   by 'name' and if 'has_activation' is set, it has an activation record.
+*/
+extern open_scope();
+
+/* extern      close_scope();
+   Closes the current scope; CurrentScope becomes the statically enclosing
+   scope.
+*/
+extern close_scope();
+
+/* extern      add_scope_addr(p_scope sc);
+   Adds scope 'sc' to the list of scopes that have an address at runtime.
+*/
+extern add_scope_addr();
+
+/* extern p_scope      get_scope_from_addr(t_addr a);
+   Returns the scope of the code at address 'a', or 0 if it could not be found.
+*/
+extern p_scope get_scope_from_addr();
+
+/* extern p_scope      get_next_scope_from_addr(t_addr a);
+   Returns the scope following the one of the code at address 'a',
+   and that has an activation record,
+   or 0 if it could not be found.
+*/
+extern p_scope get_next_scope_from_addr();
+
+/* extern p_scope      base_scope(p_scope sc);
+   Returns the closest enclosing scope of 'sc' that has an activation record.
+*/
+extern p_scope base_scope();
diff --git a/util/grind/sizes.h b/util/grind/sizes.h
new file mode 100644 (file)
index 0000000..90cd6ae
--- /dev/null
@@ -0,0 +1,8 @@
+/* For the time being ... */
+
+#define SZ_INT         4
+#define SZ_SHORT       2
+#define SZ_POINTER     4
+#define SZ_LONG                4
+#define SZ_FLOAT       4
+#define SZ_DOUBLE      8
diff --git a/util/grind/symbol.c b/util/grind/symbol.c
new file mode 100644 (file)
index 0000000..57704e2
--- /dev/null
@@ -0,0 +1,237 @@
+/* $Header$ */
+
+/* Symbol handling */
+
+#include       <alloc.h>
+#include       <out.h>
+#include       <stb.h>
+#include       <assert.h>
+
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+#include       "type.h"
+#include       "symbol.h"
+#include       "scope.h"
+#include       "tree.h"
+#include       "operator.h"
+
+p_symbol       currfile;
+
+p_symbol
+NewSymbol(s, scope, class, nam)
+  char *s;
+  register p_scope scope;
+  struct outname *nam;
+{
+  register p_symbol sym;
+  
+  sym = new_symbol();
+  sym->sy_idf = str2idf(s, 0);
+  sym->sy_scope = scope;
+  sym->sy_prev_sc = scope->sc_symbs;
+  scope->sc_symbs = sym;
+  sym->sy_next = sym->sy_idf->id_def;
+  sym->sy_idf->id_def = sym;
+  sym->sy_class = class;
+  switch(class) {
+  case MODULE:
+  case PROC:
+  case FUNCTION:
+  case VAR:
+  case REGVAR:
+  case LOCVAR:
+  case VARPAR:
+       sym->sy_name.nm_value = nam->on_valu;
+       break;
+  default:
+       break;
+  }
+  return sym;
+}
+
+/* Lookup a definition for 'id' in scope 'scope' with class in the 'class'
+   bitset.
+*/
+p_symbol
+Lookup(id, scope, class)
+  struct idf *id;
+  p_scope scope;
+  int  class;
+{
+  register p_symbol p = id ? id->id_def : 0;
+
+  while (p) {
+       if (p->sy_scope == scope && (p->sy_class & class)) {
+               return p;
+       }
+       p = p->sy_next;
+  }
+  return (p_symbol) 0;
+}
+
+/* Lookup a definition for 'id' with class in the 'class' bitset,
+   starting in scope 'sc' and also looking in enclosing scopes.
+*/
+p_symbol
+Lookfromscope(id, class, sc)
+  register struct idf *id;
+  int  class;
+  register p_scope     sc;
+{
+  if (! id) return (p_symbol) 0;
+
+  while (sc) {
+       register p_symbol sym = id->id_def;
+       while (sym) {
+               if (sym->sy_scope == sc && (sym->sy_class & class)) {
+                       return sym;
+               }
+               sym = sym->sy_next;
+       }
+       sc = sc->sc_static_encl;
+  }
+  return (p_symbol) 0;
+}
+
+/* Lookup a definition for 'id' with class in the 'class' bitset,
+   starting in scope 'CurrentScope' and also looking in enclosing scopes.
+*/
+p_symbol
+Lookfor(id, class)
+  register struct idf *id;
+  int  class;
+{
+  return Lookfromscope(id, class, CurrentScope);
+}
+
+extern char *strrindex();
+
+p_symbol
+add_file(s)
+  char *s;
+{
+  register p_symbol sym = NewSymbol(s,
+                                   PervasiveScope,
+                                   FILESYM,
+                                   (struct outname *) 0);
+  register char *p;
+
+  sym->sy_file = new_file();
+  sym->sy_file->f_sym = sym;
+  p = strrindex(s, '.');
+  if (p) {
+       char c = *p;
+       p_symbol sym1;
+
+       *p = 0;
+       sym1 = NewSymbol(Salloc(s, (unsigned) strlen(s)+1),
+                        PervasiveScope,
+                        FILELINK,
+                        (struct outname *) 0);
+       *p = c;
+       sym1->sy_filelink = sym;
+  }
+  return sym;
+}
+
+/* Determine if the OP_SELECT tree indicated by 'p' could lead to scope 'sc'.
+*/
+static int
+consistent(p, sc)
+  p_tree       p;
+  p_scope      sc;
+{
+  p_tree       arg;
+  p_symbol     sym;
+
+  assert(p->t_oper == OP_SELECT);
+  sc = sc->sc_static_encl;
+  if (!sc) return 0;
+
+  p = p->t_args[0];
+
+  switch(p->t_oper) {
+  case OP_NAME:
+       sym = Lookfromscope(p->t_idf, FILELINK|FILESYM|PROC|MODULE, sc);
+       return sym != 0;
+
+  case OP_SELECT:
+       arg = p->t_args[1];
+       sym = Lookfromscope(arg->t_idf, FILELINK|FILESYM|PROC|MODULE, sc);
+       if (sym == 0) return 0;
+       return consistent(p, sym->sy_scope);
+
+  default:
+       assert(0);
+  }
+  return 0;    /* notreached? */
+}
+
+/* Try to find the name referred to in the node indicated by 'p', and
+   try to be just a little bit intelligent about it.
+*/
+p_symbol
+identify(p, class_set)
+  p_tree       p;
+  int          class_set;
+{
+  p_symbol     sym = 0;
+  register p_symbol s;
+  p_tree       arg;
+
+  switch(p->t_oper) {
+  case OP_NAME:
+       if (! p->t_sc) p->t_sc = CurrentScope;
+       sym = Lookfromscope(p->t_idf, class_set, p->t_sc);
+       if (sym) {
+               /* Found it. */
+               break;
+       }
+
+       /* We could not find it using scope p->t_sc; now we try to identify
+          it using class_set. If this results in only one definition, we
+          take this one.
+       */
+       s = p->t_idf->id_def;
+       while (s) {
+               if (s->sy_class & class_set) {
+                       if (sym) {
+                               error("could not identify \"%s\"", p->t_str);
+                               sym = 0;
+                               break;
+                       }
+                       sym = s;
+               }
+               s = s->sy_next;
+       }
+       if (!sym && !s) {
+               error("could not find \"%s\"", p->t_str);
+       }
+       break;
+
+  case OP_SELECT:
+       arg = p->t_args[1];
+       assert(arg->t_oper == OP_NAME);
+       s = arg->t_idf->id_def;
+       sym = 0;
+       while (s) {
+               if ((s->sy_class & class_set) && consistent(p, s->sy_scope)) {
+                       if (sym) {
+                               error("could not identify \"%s\"", arg->t_str);
+                               sym = 0;
+                       }
+                       sym = s;
+               }
+               s = s->sy_next;
+       }
+       if (!sym && !s) {
+               error("could not find \"%s\"", arg->t_str);
+       }
+       break;
+
+  default:
+       assert(0);
+  }
+  return sym;
+}
diff --git a/util/grind/symbol.hh b/util/grind/symbol.hh
new file mode 100644 (file)
index 0000000..251b755
--- /dev/null
@@ -0,0 +1,58 @@
+/* $Header$
+   Symbol table data structure.
+   Each identifier structure refers to a list of possible meanings of this
+   identifier. Each of these meanings is represented by a "symbol" structure.
+*/
+
+typedef union constant {       /* depends on type */
+  long co_ival;
+  double co_rval;
+  char *co_sval;
+  char *co_setval;
+} t_const, *p_const;
+
+typedef struct name {
+  long nm_value;               /* address or offset */
+  struct scope *nm_scope;      /* for names that define a scope */
+} t_name, *p_name;
+
+typedef struct symbol {
+  struct symbol        *sy_next;       /* link to next meaning */
+  struct symbol        *sy_prev_sc;    /* link to previous decl in scope */
+  struct type  *sy_type;       /* type of symbol */
+  int          sy_class;
+#define CONST          0x0001
+#define TYPE           0x0002
+#define TAG            0x0004
+#define MODULE         0x0008
+#define PROC           0x0010
+#define FUNCTION       0x0020
+#define VAR            0x0040
+#define REGVAR         0x0080
+#define LOCVAR         0x0100
+#define VARPAR         0x0200
+/* #define SYMENTRY    0x0400  /* a non-dbx entry */
+#define FILESYM                0x0800  /* a filename */
+#define FILELINK       0x1000  /* a filename without its suffix */
+  struct idf   *sy_idf;        /* reference back to its idf structure */
+  struct scope *sy_scope;      /* scope in which this symbol resides */
+  union {
+       t_const syv_const;      /* CONST */
+       t_name  syv_name;
+/*     struct outname syv_onam;        /* for non-dbx entries */
+       struct file *syv_file;          /* for FILESYM */
+       struct symbol *syv_fllink;      /* for FILELINK */
+  }    sy_v;
+#define sy_const       sy_v.syv_const
+#define sy_name                sy_v.syv_name
+#define sy_onam                sy_v.syv_onam
+#define sy_file                sy_v.syv_file
+#define sy_filelink    sy_v.syv_fllink
+} t_symbol, *p_symbol;
+
+/* ALLOCDEF "symbol" 50 */
+
+extern p_symbol        NewSymbol(), Lookup(), Lookfor(), Lookfromscope(), add_file();
+extern p_symbol identify();
+
+extern p_symbol        currfile;
diff --git a/util/grind/tok_tools.amk b/util/grind/tok_tools.amk
new file mode 100644 (file)
index 0000000..994c922
--- /dev/null
@@ -0,0 +1,15 @@
+MAKE_TOKFILE = make.tokfile;
+MAKE_TOKCASE = make.tokcase;
+
+%tool gen_tokens (
+    csrc:      %in  [type = C-src, gen_tokens, persistent];
+    tokfile:   %out [type = LLgen-src] => get($csrc, LL-dest);
+    symbols:   %out [type = C-src, b]  => get($csrc, cc-dest);
+    mktok:     %in  [type = command]   => $MAKE_TOKFILE;
+    mkcase:    %in  [type = command]   => $MAKE_TOKCASE;
+)
+{
+    exec($mktok,  stdin => $csrc, stdout => $tokfile);
+    exec($mkcase, stdin => $csrc, stdout => $symbols);
+    echo({$tokfile, 'and', $symbols, 'created'});
+};
diff --git a/util/grind/tokenname.c b/util/grind/tokenname.c
new file mode 100644 (file)
index 0000000..7e378d7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ * Author: Ceriel J.H. Jacobs
+ */
+
+/* T O K E N   D E F I N I T I O N S */
+
+/* $Header$ */
+
+#include       "tokenname.h"
+#include       "Lpars.h"
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+
+/*     To centralize the declaration of %tokens, their presence in this
+       file is taken as their declaration. The Makefile will produce
+       a grammar file (tokenfile.g) from this file. This scheme ensures
+       that all tokens have a printable name.
+       Also, the "token2str.c" file is produced from this file.
+*/
+
+#if 0
+struct tokenname tkspec[] =    {       /* the names of the special tokens */
+       {NAME, "name"},
+       {STRING, "string"},
+       {INTEGER, "number"},
+       {REAL, "real"},
+       {CHAR, "char"},
+       {0, ""}
+};
+#endif
+
+struct tokenname tkidf[] =     {       /* names of the identifier tokens */
+       {LIST, "list"},
+       {XFILE, "file"},
+       {RUN, "run"},
+       {RERUN, "rerun"},
+       {STOP, "stop"},
+       {WHEN, "when"},
+       {AT, "at"},
+       {IN, "in"},
+       {ON, "on"},
+       {IF, "if"},
+       {CONT, "cont"},
+       {STEP, "step"},
+       {NEXT, "next"},
+       {REGS, "regs"},
+       {WHERE, "where"},
+       {STATUS, "status"},
+       {DELETE, "delete"},
+       {PRINT, "print"},
+       {DUMP, "dump"},
+       {RESTORE, "restore"},
+       {TRACE, "trace"},
+       {-1, "quit"},
+       {0, ""}
+};
+
+#if 0
+struct tokenname tkinternal[] = {      /* internal keywords    */
+       {0, "0"}
+};
+
+struct tokenname tkstandard[] =        {       /* standard identifiers */
+       {0, ""}
+};
+#endif
+
+/* Some routines to handle tokennames */
+
+reserve(resv)
+       register struct tokenname *resv;
+{
+       /*      The names of the tokens described in resv are entered
+               as reserved words.
+       */
+       register struct idf *p;
+
+       while (resv->tn_symbol) {
+               p = str2idf(resv->tn_name, 0);
+               if (!p) fatal("out of Memory");
+               p->id_reserved = resv->tn_symbol;
+               resv++;
+       }
+}
diff --git a/util/grind/tokenname.h b/util/grind/tokenname.h
new file mode 100644 (file)
index 0000000..b3a4720
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ * Author: Ceriel J.H. Jacobs
+ */
+
+/* T O K E N N A M E   S T R U C T U R E */
+
+/* $Header$ */
+
+struct tokenname       {       /*      Used for defining the name of a
+                                       token as identified by its symbol
+                               */
+       int tn_symbol;
+       char *tn_name;
+};
diff --git a/util/grind/tree.c b/util/grind/tree.c
new file mode 100644 (file)
index 0000000..112cbed
--- /dev/null
@@ -0,0 +1,594 @@
+/* $Header$ */
+
+#include       <stdio.h>
+#include       <varargs.h>
+#include       <assert.h>
+#include       <alloc.h>
+#include       <out.h>
+
+#include       "operator.h"
+#include       "position.h"
+#include       "file.h"
+#include       "idf.h"
+#include       "tree.h"
+#include       "message.h"
+#include       "scope.h"
+#include       "symbol.h"
+#include       "langdep.h"
+
+extern FILE    *db_out;
+extern t_lineno        currline;
+extern long    pointer_size;
+extern char    *strrindex();
+
+p_tree         run_command;
+
+/*VARARGS1*/
+p_tree
+mknode(va_alist)
+  va_dcl
+{
+  va_list ap;
+  register p_tree p = new_tree();
+
+  va_start(ap);
+  {
+       register int i, na;
+
+       p->t_oper = va_arg(ap, int);
+       switch(p->t_oper) {
+       case OP_NAME:
+               p->t_idf = va_arg(ap, struct idf *);
+               p->t_str = va_arg(ap, char *);
+               break;
+       case OP_INTEGER:
+               p->t_ival = va_arg(ap, long);
+               break;
+       case OP_AT:
+               p->t_lino = va_arg(ap, long);
+               p->t_filename = va_arg(ap, char *);
+               break;
+       case OP_NEXT:
+       case OP_STEP:
+       case OP_REGS:
+       case OP_DELETE:
+       case OP_RESTORE:
+               p->t_ival = va_arg(ap, long);
+               break;
+       default:
+               na = nargs(p->t_oper);
+               assert(na <= MAXARGS);
+               for (i = 0; i < na; i++) {
+                       p->t_args[i] = va_arg(ap, p_tree);
+               }
+               break;
+       }
+  }
+  va_end(ap);
+  return p;
+}
+
+freenode(p)
+  register p_tree      p;
+{
+  register int na, i;
+
+  if (! p) return;
+  switch(p->t_oper) {
+  case OP_NAME:
+  case OP_INTEGER:
+  case OP_AT:
+  case OP_CONT:
+  case OP_NEXT:
+  case OP_STEP:
+  case OP_REGS:
+  case OP_DELETE:
+       break;
+  default:
+       na = nargs(p->t_oper);
+       assert(na <= MAXARGS);
+       for (i = 0; i < na; i++) {
+               freenode(p->t_args[i]);
+       }
+       break;
+  }
+  free_tree(p);
+}
+
+print_node(p, top_level)
+  register p_tree      p;
+{
+  if (!p) return;
+  switch(p->t_oper) {
+  case OP_LIST:
+       fputs("list ", db_out);
+       if (p->t_args[0]) {
+               print_node(p->t_args[0], 0);
+               if (p->t_args[1]) {
+                       fputs(", ", db_out);
+                       print_node(p->t_args[1], 0);
+               }
+       }
+       break;
+  case OP_PRINT:
+       fputs("print ", db_out);
+       print_node(p->t_args[0], 0);
+       break;
+  case OP_FILE:
+       fputs("file ", db_out);
+       print_node(p->t_args[0], 0);
+       break;
+  case OP_DELETE:
+       fprintf(db_out, "delete %d", p->t_ival);
+       break;
+  case OP_REGS:
+       fprintf(db_out, "regs %d", p->t_ival);
+       break;
+  case OP_NEXT:
+       fprintf(db_out, "next %d", p->t_ival);
+       break;
+  case OP_STEP:
+       fprintf(db_out, "step %d", p->t_ival);
+       break;
+  case OP_STATUS:
+       fputs("status", db_out);
+       break;
+  case OP_DUMP:
+       fputs("dump ", db_out);
+       print_position(p->t_address, 1);
+       break;
+  case OP_RESTORE:
+       fprintf(db_out, "restore %d", p->t_ival);
+       break;
+  case OP_WHERE:
+       fputs("where", db_out);
+       break;
+  case OP_CONT:
+       fputs("cont", db_out);
+       if (p->t_args[0]) {
+               fprintf(db_out, " %d", p->t_args[0]->t_ival);
+       }
+       if (p->t_args[1]) {
+               fputs(" ", db_out);
+               print_node(p->t_args[1], 0);
+       }
+       break;
+
+  case OP_WHEN:
+       fputs("when ", db_out);
+       if (p->t_address != NO_ADDR) {
+               print_position(p->t_address, 1);
+       }
+       else print_node(p->t_args[0], 0);
+       if (p->t_args[1]) {
+               fputs(" if ", db_out);
+               print_node(p->t_args[1], 0);
+       }
+       p = p->t_args[2];
+       fputs(" { ", db_out);
+       while (p->t_oper == OP_LINK) {
+               print_node(p->t_args[0], 0);
+               fputs("; ", db_out);
+               p = p->t_args[1];
+       }
+       print_node(p, 0);
+       fputs(" }", db_out);
+       break;
+  case OP_STOP:
+       fputs("stop ", db_out);
+       if (p->t_address != NO_ADDR) {
+               print_position(p->t_address, 1);
+       }
+       else print_node(p->t_args[0], 0);
+       if (p->t_args[1]) {
+               fputs(" if ", db_out);
+               print_node(p->t_args[1], 0);
+       }
+       break;
+  case OP_TRACE:
+       fputs("trace ", db_out);
+       if (p->t_args[2]) {
+               fputs("on ", db_out);
+               print_node(p->t_args[2], 0);
+               fputs(" ", db_out);
+       }
+       if (p->t_address != NO_ADDR) {
+               print_position(p->t_address, 1);
+       }
+       else print_node(p->t_args[0], 0);
+       if (p->t_args[1]) {
+               fputs(" if ", db_out);
+               print_node(p->t_args[1], 0);
+       }
+       break;
+  case OP_AT:
+       fprintf(db_out, "at \"%s\":%ld", p->t_filename, p->t_lino);
+       break;
+  case OP_IN:
+       fputs("in ", db_out);
+       print_node(p->t_args[0], 0);
+       break;
+  case OP_SELECT:
+       print_node(p->t_args[0], 0);
+       fputs("`", db_out);
+       print_node(p->t_args[1], 0);
+       break;
+  case OP_NAME:
+       fputs(p->t_str, db_out);
+       break;
+  case OP_INTEGER:
+       fprintf(db_out, "%d", p->t_ival);
+       break;
+  }
+  if (top_level) fputs("\n", db_out);
+}
+
+int
+repeatable(com)
+  p_tree       com;
+{
+  switch(com->t_oper) {
+  case OP_CONT:
+  case OP_NEXT:
+  case OP_STEP:
+  case OP_LIST:
+  case OP_STATUS:
+  case OP_PRINT:
+       return 1;
+  }
+  return 0;
+}
+
+int
+in_status(com)
+  p_tree       com;
+{
+  switch(com->t_oper) {
+  case OP_STOP:
+  case OP_WHEN:
+  case OP_TRACE:
+  case OP_DUMP:
+       return 1;
+  }
+  return 0;
+}
+
+eval(p)
+  p_tree       p;
+{
+  if (p) (*operators[p->t_oper].op_fun)(p);
+}
+
+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,
+             p->t_args[1] ? (int) p->t_args[1]->t_ival : (int) currline+9);
+       currline = p->t_args[1] ? p->t_args[1]->t_ival + 1 : currline + 10;
+  }
+  else fprintf(db_out, "no current file\n");
+}
+
+do_file(p)
+  p_tree       p;
+{
+  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 fprintf(db_out, "no current file\n");
+}
+
+newfile(id)
+  register struct idf  *id;
+{
+  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;
+  }
+  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, 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]);
+
+  if (a == ILL_ADDR) {
+       return;
+  }
+
+  p->t_address = a;
+  add_to_item_list(p);
+  if (a != NO_ADDR) {
+       if (! set_or_clear_breakpoint(a, SETBP)) {
+               error("could not set breakpoint");
+       }
+  }
+}
+
+do_trace(p)
+  p_tree       p;
+{
+  t_addr a;
+  t_addr e;
+
+  p->t_address = NO_ADDR;
+  if (p->t_args[0]) {
+       a = get_pos(p->t_args[0]);
+       if (a == ILL_ADDR) return;
+       if (p->t_args[0]->t_oper == OP_AT) {
+               e = a;
+               p->t_address = a;
+       }
+       else {
+               p_scope sc = get_next_scope_from_addr(a+1);
+
+               if (sc) e = sc->sc_start - 1;
+               else e = 0xffffffff;
+       }
+       if (! set_or_clear_trace(a, e, SETTRACE)) {
+               error("could not set trace");
+       }
+  }
+  add_to_item_list(p);
+}
+
+do_continue(p)
+  p_tree       p;
+{
+  int count;
+
+  if (p) {
+       count = p->t_args[0]->t_ival;
+       if (p->t_args[1]) {
+               t_addr  a = get_addr_from_position(&(p->t_args[1]->t_pos));
+               p_scope sc = get_scope_from_addr(a);
+
+               if (a == ILL_ADDR || base_scope(sc) != base_scope(CurrentScope) ||
+                   ! set_pc(a)) {
+                       error("cannot continue at line %d",
+                             p->t_args[1]->t_lino);
+                       return;
+               }
+       }
+  }
+  else count = 1;
+  while (count--) {
+       if (! send_cont(count==0)) {
+               error("no debuggee");
+               break;
+       }
+  }
+}
+
+do_step(p)
+  p_tree       p;
+{
+  if (! do_single_step(SETSS, p->t_ival)) {
+       error("no debuggee");
+  }
+}
+
+do_next(p)
+  p_tree       p;
+{
+
+  if (! do_single_step(SETSSF, p->t_ival)) {
+       error("no debuggee");
+  }
+}
+
+extern t_addr  *get_EM_regs();
+
+do_regs(p)
+  p_tree       p;
+{
+  t_addr       *buf;
+  int          n = p->t_ival;
+
+  if (! (buf = get_EM_regs(n))) {
+       error("no debuggee");
+       return;
+  }
+  fprintf(db_out, "EM registers %d levels back:\n", n);
+  fprintf(db_out, "\tLocalBase =\t0x%lx\n\tArgumentBase =\t0x%lx\n", 
+               (long) buf[LB_OFF], (long) buf[AB_OFF]);
+  fprintf(db_out, "\tProgramCounter=\t0x%lx\n\tHeapPointer = \t0x%lx\n",
+               (long) buf[PC_OFF],
+               (long) buf[HP_OFF]);
+  fprintf(db_out, "\tStackPointer =\t0x%lx\n", (long) buf[SP_OFF]);
+}
+
+/*ARGSUSED*/
+do_where(p)
+  p_tree       p;
+{
+  int i = 0;
+
+  for (;;) {
+       t_addr AB;
+       t_addr PC;
+       p_scope sc;
+       t_addr *buf;
+
+       if (! (buf = get_EM_regs(i++))) {
+               error("no debuggee");
+               return;
+       }
+       AB = buf[AB_OFF];
+       PC = buf[PC_OFF];
+       if (! AB) break;
+       sc = base_scope(get_scope_from_addr(PC));
+       if (! sc || sc->sc_start > PC) break;
+       fprintf(db_out, "%s(", sc->sc_definedby->sy_idf->id_text);
+       print_params(sc->sc_definedby->sy_type, AB, has_static_link(sc));
+       fputs(") ", db_out);
+       print_position(PC, 0);
+       fputs("\n", db_out);
+  }
+}
+
+/*ARGSUSED*/
+do_status(p)
+  p_tree       p;
+{
+  print_items();
+}
+
+extern p_tree  remove_from_item_list();
+
+do_delete(p)
+  p_tree       p;
+{
+  p = remove_from_item_list((int) p->t_ival);
+
+  if (p) switch(p->t_oper) {
+  case OP_WHEN:
+  case OP_STOP: {
+       t_addr a = get_pos(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]);
+       
+       if (a != ILL_ADDR && a != NO_ADDR) {
+               t_addr e;
+               if (p->t_args[0]->t_oper == OP_AT) {
+                       e = a;
+               }
+               else {
+                       p_scope sc = get_next_scope_from_addr(a+1);
+
+                       if (sc) e = sc->sc_start - 1;
+                       else e = 0xffffffff;
+               }
+               set_or_clear_trace(a, e, CLRTRACE);
+       }
+       break;
+       }
+  case OP_DUMP:
+       free_dump(p);
+  }
+  freenode(p);
+}
+
+do_print(p)
+  p_tree       p;
+{
+  p_symbol sym;
+
+  switch(p->t_oper) {
+  case OP_PRINT:
+       do_print(p->t_args[0]);
+       break;
+  case OP_LINK:
+       do_print(p->t_args[0]);
+       do_print(p->t_args[1]);
+       break;
+  case OP_NAME:
+  case OP_SELECT:
+       sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR);
+       if (! sym) return;
+       print_node(p, 0);
+       if (! print_sym(sym)) {
+               fputs(" currently not available\n", db_out);
+               break;
+       }
+  }
+}
+
+perform(p, a)
+  register p_tree      p;
+  t_addr               a;
+{
+  switch(p->t_oper) {
+  case OP_WHEN:
+       p = p->t_args[2];
+       while (p->t_oper == OP_LINK) {
+               eval(p->t_args[0]);
+               p = p->t_args[1];
+       }
+       eval(p);
+       break;
+  case OP_TRACE:
+       if (p->t_args[0] && p->t_args[0]->t_oper == OP_IN) {
+               register p_scope sc = base_scope(CurrentScope);
+       
+               if (sc != get_scope_from_addr(p->t_args[0]->t_address)) {
+                       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]);
+       }
+       break;
+  default:
+       assert(0);
+  }
+}
diff --git a/util/grind/tree.hh b/util/grind/tree.hh
new file mode 100644 (file)
index 0000000..052030e
--- /dev/null
@@ -0,0 +1,32 @@
+/* $Header$ */
+
+#define MAXARGS        3
+
+typedef struct tree {
+  int  t_oper;         /* operator */
+  t_addr t_address;    /* some operators use an address */
+  int  t_itemno;       /* item number in status list */
+  union {
+       long tt_ival;
+       struct {
+               struct idf *tt_idf;
+               char *tt_str;
+               struct scope *tt_scope; 
+       } tt_x;
+       struct tree *tt_args[MAXARGS];
+       t_position tt_pos;
+  } t_xxxx;
+#define t_ival t_xxxx.tt_ival
+#define t_idf  t_xxxx.tt_x.tt_idf
+#define t_str  t_xxxx.tt_x.tt_str
+#define t_sc   t_xxxx.tt_x.tt_scope
+#define t_args t_xxxx.tt_args
+#define t_lino t_xxxx.tt_pos.lineno
+#define t_filename t_xxxx.tt_pos.filename
+#define t_pos  t_xxxx.tt_pos
+} t_tree, *p_tree;
+
+/* ALLOCDEF "tree" 100 */
+
+extern p_tree  mknode();
+extern p_tree  run_command;
diff --git a/util/grind/type.c b/util/grind/type.c
new file mode 100644 (file)
index 0000000..111f1f4
--- /dev/null
@@ -0,0 +1,387 @@
+/* $Header$ */
+
+/* Routines to create type structures */
+
+#include <alloc.h>
+#include <assert.h>
+
+#include "type.h"
+#include "sizes.h"
+#include "symbol.h"
+#include "scope.h"
+#include "message.h"
+#include "langdep.h"
+
+p_type int_type, char_type, short_type, long_type;
+p_type uint_type, uchar_type, ushort_type, ulong_type;
+p_type void_type, incomplete_type;
+p_type float_type, double_type;
+p_type string_type;
+
+long   int_size = SZ_INT,
+       char_size = 1,
+       short_size = SZ_SHORT,
+       long_size = SZ_LONG,
+       pointer_size = SZ_POINTER;
+
+long   float_size = SZ_FLOAT,
+       double_size = SZ_DOUBLE;
+
+struct bounds {
+       long low, high;
+};
+
+static struct bounds ibounds[2] = {
+       { -128, 127 },
+       { -32768, 32767 }
+};
+
+static struct bounds ubounds[2] = {
+       { 0, 255 },
+       { 0, 65535 }
+};
+
+static long max_int[8], max_uns[8];
+
+struct integer_types {
+       long    maxval;
+       p_type  type;
+};
+
+static struct integer_types i_types[4];
+static struct integer_types u_types[5];
+
+#define ufit(n, nb)    Xfit(n, nb, ubounds)
+#define ifit(n, nb)    Xfit(n, nb, ibounds)
+#define Xfit(n, nb, b) ((n) >= (b)[(nb)-1].low && (n) <= (b)[(nb)-1].high)
+
+/* Create a subrange type, but is it really a subrange? */
+p_type
+subrange_type(A, base_index, c1, c2, result_index)
+  int *base_index, *result_index;
+  long c1, c2;
+{
+  int itself = 0;
+  register p_type p;
+  p_type base_type;
+
+  if (!A) {
+       /* Subrange of itself is a special case ... */
+       if (result_index &&
+          result_index[0] == base_index[0] &&
+          result_index[1] == base_index[1]) {
+
+               /* c1 = 0 and c2 = 0 -> void */
+               if (c1 == 0 && c2 == 0) {
+                       return void_type;
+               }
+
+               /* c1 = 0 and c2 = 127 -> char ??? */
+               if (c1 == 0 && c2 == 127) {
+                       return char_type;
+               }
+               itself = 1;
+       }
+  }
+
+  if (itself) base_type = int_type; else base_type = *(tp_lookup(base_index));
+
+  if (! A) {
+       /* c2 = 0 and c1 > 0 -> real */
+       if (c2 == 0 && c1 > 0) {
+               if (c1 == float_size) return float_type;
+               return double_type;
+       }
+
+       /* c1 = 0 and base_index indicates int_type or itself -> unsigned,
+          c1 = -c2 - 1 and base_index indicates int_type or itself -> integer
+       */
+       if (itself || base_type == int_type) {
+               register struct integer_types *ip = 0;
+               if (c1 == 0) {
+                       ip = &u_types[0];
+               }
+               else if (c1 == -c2 - 1) {
+                       ip = &i_types[0];
+               }
+               if (ip) {
+                       while (ip->maxval != 0 && ip->maxval != c2) ip++;
+                       if (ip->maxval) return ip->type;
+               }
+       }
+  }
+  /* if we get here, it actually is a subrange type */
+  p = new_type();
+  p->ty_class = T_SUBRANGE;
+  p->ty_low = c1;
+  p->ty_up = c2;
+  p->ty_base = base_type;
+  p->ty_A = A;
+
+  /* determine size of subrange type */
+  p->ty_size = base_type->ty_size;
+  if (!A && p->ty_base == uint_type) {
+       if (ufit(p->ty_up, 1)) {
+               p->ty_size = 1;
+       }
+       else if (ufit(p->ty_up, (int)short_size)) {
+               p->ty_size = short_size;
+       }
+  }
+  if (!A && p->ty_base == int_type) {
+       if (ifit(p->ty_up, 1) && ifit(p->ty_low, 1)) {
+               p->ty_size = 1;
+       }
+       else if (ifit(p->ty_up, (int)short_size) &&
+                ifit(p->ty_low, (int)short_size)) {
+               p->ty_size = short_size;
+       }
+  }
+
+  return p;
+}
+
+static long
+nel(tp)
+  register p_type tp;
+{
+  switch(tp->ty_class) {
+  case T_SUBRANGE:
+       if (tp->ty_A) return 0;
+       if (tp->ty_low <= tp->ty_up) return tp->ty_up - tp->ty_low + 1;
+       return tp->ty_low - tp->ty_up + 1;
+  case T_UNSIGNED:
+  case T_INTEGER:
+       if (tp->ty_size == 1) return 256;
+       if (tp->ty_size == 2) return 65536L;
+       assert(0);
+       break;
+  case T_ENUM:
+       return tp->ty_nenums;
+  default:
+       assert(0);
+       break;
+  }
+  return 0;
+}
+
+p_type
+array_type(bound_type, el_type)
+  p_type bound_type, el_type;
+{
+  register p_type tp = new_type();
+
+  tp->ty_class = T_ARRAY;
+  tp->ty_index = bound_type;
+  tp->ty_elements = el_type;
+  tp->ty_size = (*currlang->arrayelsize)(el_type->ty_size) * nel(bound_type);
+  return tp;
+}
+
+p_type
+basic_type(fund, size)
+  int  fund;
+  long size;
+{
+  register p_type      p = new_type();
+
+  p->ty_class = fund;
+  p->ty_size = size;
+  return p;
+}
+
+set_bounds(tp)
+  register p_type      tp;
+{
+  /* Determine the size and low of a set type */
+  register p_type base = tp->ty_setbase;
+
+  if (base->ty_class == T_SUBRANGE) {
+       tp->ty_size = (base->ty_up - base->ty_low + 7) >> 3;
+       tp->ty_setlow = base->ty_low;
+  }
+  else if (base->ty_class == T_INTEGER) {
+       tp->ty_size = (max_int[(int)base->ty_size] + 1) >>  2;
+       tp->ty_setlow = -max_int[(int)base->ty_size] - 1;
+  }
+  else {
+       assert(base->ty_class == T_UNSIGNED);
+       tp->ty_size = (max_uns[(int)base->ty_size] + 1) >>  3;
+       tp->ty_setlow = 0;
+  }
+}
+
+init_types()
+{
+  register int i = 0;
+  register long x = 0;
+
+  while (x >= 0) {
+       i++;
+       x = (x << 8) + 0377;
+       max_uns[i] = x;
+       max_int[i] = x & ~(1L << (8*i - 1));
+  }
+  int_type = basic_type(T_INTEGER, int_size);
+  long_type = basic_type(T_INTEGER, long_size);
+  short_type = basic_type(T_INTEGER, short_size);
+  char_type = basic_type(T_INTEGER, char_size);
+  uint_type = basic_type(T_UNSIGNED, int_size);
+  ulong_type = basic_type(T_UNSIGNED, long_size);
+  ushort_type = basic_type(T_UNSIGNED, short_size);
+  uchar_type = basic_type(T_UNSIGNED, char_size);
+  string_type = basic_type(T_STRING, 0L);
+  void_type = basic_type(T_VOID, 0L);
+  incomplete_type = basic_type(T_INCOMPLETE, 0L);
+  float_type = basic_type(T_REAL, float_size);
+  double_type = basic_type(T_REAL, double_size);
+
+  i_types[0].maxval = max_int[(int)int_size]; i_types[0].type = int_type;
+  i_types[1].maxval = max_int[(int)short_size]; i_types[1].type = short_type;
+  i_types[2].maxval = max_int[(int)long_size]; i_types[2].type = long_type;
+  u_types[0].maxval = max_uns[(int)int_size]; u_types[0].type = uint_type;
+  u_types[1].maxval = max_uns[(int)short_size]; u_types[1].type = ushort_type;
+  u_types[2].maxval = max_uns[(int)long_size]; u_types[2].type = ulong_type;
+  u_types[3].maxval = max_uns[1]; u_types[3].type = uchar_type;
+}
+
+/*
+ * Some code to handle type indices, which are pairs of integers.
+ * What we need is a two-dimensional array, but we don't know how large
+ * it is going to be, so we use a list of rows instead.
+ */
+static struct tp_index {
+  unsigned     len;
+  p_type       *row;
+} *list_row;
+static unsigned list_len;
+
+#define NINCR 10
+  
+p_type *
+tp_lookup(type_index)
+  int *type_index;
+{
+  register int i;
+  register struct tp_index *p;
+
+  while (type_index[0] >= list_len) {
+       if (list_len) {
+               list_row = (struct tp_index *) Realloc((char *) list_row,
+                               (list_len += NINCR) * sizeof(struct tp_index));
+       }
+       else    list_row = (struct tp_index *)
+                       Malloc((list_len = NINCR) * sizeof(struct tp_index));
+       for (i = NINCR; i > 0; i--) {
+               list_row[list_len - i].len = 0;
+       }
+  }
+  p = &list_row[type_index[0]];
+  while (type_index[1] >= p->len) {
+       if (p->len) {
+               p->row = (p_type *) Realloc((char *) p->row,
+                               (p->len += NINCR) * sizeof(p_type));
+       }
+       else    p->row = (p_type *) Malloc((p->len = NINCR) * sizeof(p_type));
+       for (i = NINCR; i > 0; i--) {
+               p->row[p->len - i] = 0;
+       }
+  }
+  return &(p->row[type_index[1]]);
+}
+
+clean_tp_tab()
+{
+  if (list_len) {
+       register int i = list_len;
+
+       while (--i >= 0) {
+               register int j = list_row[i].len;
+               if (j) {
+                       while (--j > 0) {
+                               p_type p = list_row[i].row[j];
+                               if (p == incomplete_type) {
+                                       error("incomplete type (%d,%d) 0x%x", i, j, &list_row[i].row[j]);
+                               }
+                       }
+                       free((char *) list_row[i].row);
+               }
+       }
+       free((char *) list_row);
+       list_len = 0;
+       list_row = 0;
+  }
+}
+
+end_literal(tp, maxval)
+  register p_type tp;
+  long maxval;
+{
+  tp->ty_literals = (struct literal *)
+       Realloc((char *) tp->ty_literals,
+               tp->ty_nenums * sizeof(struct literal));
+  if (ufit(maxval, 1)) tp->ty_size = 1;
+  else if (ufit(maxval, (int)short_size)) tp->ty_size = short_size;
+  else tp->ty_size = int_size;
+}
+
+long
+param_size(t, v)
+  int  v;
+  p_type t;
+{
+  if (v == 'i' || v == 'v') {
+       /* addresss; only exception is a conformant array, which also
+          takes a descriptor.
+       */
+       if (t->ty_class == T_ARRAY &&
+           t->ty_index->ty_class == T_SUBRANGE &&
+           t->ty_index->ty_A) {
+               return pointer_size + 3 * int_size;
+       }
+       return pointer_size;
+  }
+  return ((t->ty_size + int_size - 1) / int_size) * int_size;
+}
+
+add_param_type(v, s)
+  int  v;              /* 'v' or 'i' for address, 'p' for value */
+  p_symbol s;          /* parameter itself */
+{
+  register p_scope sc = base_scope(s->sy_scope);
+  register p_type prc_type;
+
+  if (! sc) return;
+  prc_type = sc->sc_definedby->sy_type;
+  assert(prc_type->ty_class == T_PROCEDURE);
+
+  prc_type->ty_nparams++;
+  prc_type->ty_params = (struct param *) Realloc((char *) prc_type->ty_params, 
+                               (unsigned)prc_type->ty_nparams * sizeof(struct param));
+  prc_type->ty_params[prc_type->ty_nparams - 1].par_type = s->sy_type;
+  prc_type->ty_params[prc_type->ty_nparams - 1].par_kind = v;
+  prc_type->ty_nbparams += param_size(s->sy_type, v);
+}
+
+/* Compute the size of a parameter of dynamic size
+*/
+
+long
+compute_size(tp, AB)
+  p_type       tp;
+  char         *AB;
+{
+  long low, high;
+
+  assert(tp->ty_class == T_ARRAY);
+  assert(tp->ty_index->ty_class == T_SUBRANGE);
+  assert(tp->ty_index->ty_A != 0);
+
+  if (tp->ty_index->ty_A & 1) {
+       low = BUFTOI(AB+tp->ty_index->ty_low);
+  } else low = tp->ty_index->ty_low;
+  if (tp->ty_index->ty_A & 2) {
+       high = BUFTOI(AB+tp->ty_index->ty_up);
+  } else high = tp->ty_index->ty_up;
+  return (high - low + 1) * tp->ty_elements->ty_size;
+}
diff --git a/util/grind/type.hh b/util/grind/type.hh
new file mode 100644 (file)
index 0000000..0ddc228
--- /dev/null
@@ -0,0 +1,118 @@
+/* $Header$ */
+
+/* internal type representation */
+
+/* structure for struct/union elements */
+struct fields {
+  long fld_pos;                        /* position of field */
+  long fld_bitsize;            /* size in bits */
+  struct type *fld_type;       /* type of field */
+  char *fld_name;              /* name of field */
+};
+
+/* structure for enumeration literals */
+struct literal {
+  long lit_val;                        /* value of literal */
+  char *lit_name;              /* name of literal */
+};
+
+/* structure for parameters */
+struct param {
+  struct type *par_type;       /* type of parameter */
+  char par_kind;               /* kind of parameter ('p', 'i', or 'v') */
+};
+
+typedef struct type {
+  short                ty_class;
+#define T_SUBRANGE      1
+#define T_ARRAY                 2
+#define T_STRUCT        3
+#define T_UNION                 4
+#define T_ENUM          5
+#define T_POINTER       6
+#define T_FILE          7
+#define T_PROCEDURE     8
+#define T_SET           9
+#define T_REAL         10
+#define T_INTEGER      11
+#define T_VOID         12
+#define T_UNSIGNED     13
+#define T_STRING       14      /* only for string constants ... */
+#define T_INCOMPLETE   100
+  short                ty_flags;
+#define T_CROSS                0x0001
+  long         ty_size;
+  union {
+     /* cross references */
+     char          *typ_tag;
+#define ty_tag         ty_v.typ_tag
+     /* procedures/functions: */
+     struct {
+       int         typ_nparams;
+       struct type *typ_retval;
+       struct param *typ_params;
+       long        typ_nbparams;
+     } ty_proc;
+#define ty_nparams     ty_v.ty_proc.typ_nparams
+#define ty_retval      ty_v.ty_proc.typ_retval
+#define ty_params      ty_v.ty_proc.typ_params
+#define ty_nbparams    ty_v.ty_proc.typ_nbparams
+     /* pointers, files: */
+     struct type *typ_ptrto;
+#define ty_ptrto       ty_v.typ_ptrto
+#define ty_fileof      ty_v.typ_ptrto
+     /* arrays: */
+     struct {
+       struct type *typ_index;
+       struct type *typ_elements;
+     } ty_array;
+#define ty_index       ty_v.ty_array.typ_index
+#define ty_elements    ty_v.ty_array.typ_elements
+     /* subranges: */
+     struct {
+       long typ_low, typ_up;
+       int typ_A;
+       struct type *typ_base;
+     } ty_subrange;
+#define ty_A           ty_v.ty_subrange.typ_A
+#define ty_low         ty_v.ty_subrange.typ_low
+#define ty_up          ty_v.ty_subrange.typ_up
+#define ty_base                ty_v.ty_subrange.typ_base
+     /* structures/unions: */
+     struct {
+       unsigned typ_nfields;           /* number of field structures */
+       struct fields *typ_fields;
+     } ty_struct;
+#define ty_nfields     ty_v.ty_struct.typ_nfields
+#define ty_fields      ty_v.ty_struct.typ_fields
+     /* enumerations: */
+     struct {
+       unsigned typ_nenums;            /* number of enumeration literals */
+       struct literal *typ_literals;
+     } ty_enum;
+#define ty_nenums      ty_v.ty_enum.typ_nenums
+#define ty_literals    ty_v.ty_enum.typ_literals
+     /* bit sets: */
+     struct {
+       struct type *typ_setbase;       /* base type of set elements */
+       long typ_setlow;                /* low bound */
+     } ty_set;
+#define ty_setbase     ty_v.ty_set.typ_setbase
+#define ty_setlow      ty_v.ty_set.typ_setlow
+  } ty_v;
+} t_type, *p_type;
+
+/* ALLOCDEF "type" 50 */
+
+extern p_type
+       subrange_type(),
+       array_type(),
+       *tp_lookup();
+extern long
+       param_size(),
+       compute_size();
+
+extern p_type  char_type, uchar_type,
+               long_type, double_type, string_type;
+extern p_type  void_type, incomplete_type;
+
diff --git a/util/grind/value.c b/util/grind/value.c
new file mode 100644 (file)
index 0000000..42d3de2
--- /dev/null
@@ -0,0 +1,125 @@
+/* $Header$ */
+
+#include <alloc.h>
+
+#include "position.h"
+#include "scope.h"
+#include "symbol.h"
+#include "type.h"
+#include "message.h"
+
+int stack_offset;              /* for up and down commands */
+
+extern long pointer_size;
+extern t_addr *get_EM_regs();
+
+/* Get the value of the symbol indicated by sym.
+   Return 0 on failure,
+         1 on success.
+   On success, 'buf' contains the value, and 'AB' may contain the parameters
+   of the procedure invocation containing sym.
+   For both of these, storage is allocated by Malloc; this storage must
+   be freed by caller (I don't like this any more than you do, but caller
+   does not know sizes).
+*/
+int
+get_value(sym, buf, AB)
+  register p_symbol    sym;
+  char **buf, **AB;
+{
+  p_type       tp = sym->sy_type;
+  long         size = tp->ty_size;
+  int          retval = 0;
+  t_addr       *EM_regs;
+  int          i;
+  p_scope      sc, symsc;
+
+  *buf = 0;
+  *AB = 0;
+  switch(sym->sy_class) {
+  case VAR:
+       /* exists if child exists; nm_value contains addres */
+       *buf = Malloc((unsigned) size);
+       if (get_bytes(size, (t_addr) sym->sy_name.nm_value, *buf)) {
+               retval = 1;
+       }
+       break;
+
+  case VARPAR:
+  case LOCVAR:
+       /* first find the stack frame in which it resides */
+       symsc = base_scope(sym->sy_scope);
+
+       /* now symsc contains the scope where the storage for sym is
+          allocated. Now find it on the stack of child.
+       */
+       i = stack_offset;
+       for (;;) {
+               sc = 0;
+               if (! (EM_regs = get_EM_regs(i++))) {
+                       /* no child? */
+                       break;
+               }
+               if (! EM_regs[AB_OFF]) {
+                       /* no more frames */
+                       break;
+               }
+               sc = base_scope(get_scope_from_addr(EM_regs[PC_OFF]));
+               if (! sc || sc->sc_start > EM_regs[PC_OFF]) {
+                       sc = 0;
+                       break;
+               }
+               if (sc == symsc) break;         /* found it */
+       }
+
+       if (! sc) break;        /* not found */
+
+       if (sym->sy_class == LOCVAR) {
+               /* Either local variable or value parameter */
+               *buf = Malloc((unsigned) size);
+               if (get_bytes(size,
+                             EM_regs[sym->sy_name.nm_value < 0 
+                                       ? LB_OFF 
+                                       : AB_OFF
+                                    ] +
+                                 (t_addr) sym->sy_name.nm_value,
+                             *buf)) {
+                       retval = 1;
+               }
+               break;
+       }
+
+       /* If we get here, we have a var parameter. Get the parameters
+          of the current procedure invocation.
+       */
+       {
+               p_type proctype = sc->sc_definedby->sy_type;
+
+               size = proctype->ty_nbparams;
+               if (has_static_link(sc)) size += pointer_size;
+               *AB = Malloc((unsigned) size);
+               if (! get_bytes(size, EM_regs[AB_OFF], *AB)) {
+                       break;
+               }
+               if ((size = tp->ty_size) == 0) {
+                       size = compute_size(tp, *AB);
+               }
+       }
+       *buf = Malloc((unsigned) size);
+       if (get_bytes(size,
+                     (t_addr) BUFTOA(*AB+sym->sy_name.nm_value),
+                     *buf)) {
+               retval = 1;
+       }
+       break;
+  }
+
+  if (retval == 0) {
+       if (*buf) free(*buf);
+       if (*AB) free(*AB);
+       *buf = 0;
+       *AB = 0;
+  }
+
+  return retval;
+}