Initial version
This commit is contained in:
		
							parent
							
								
									f614fc6dc3
								
							
						
					
					
						commit
						dbf9a060c2
					
				
					 53 changed files with 6156 additions and 0 deletions
				
			
		
							
								
								
									
										141
									
								
								util/grind/Amakefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								util/grind/Amakefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 ; | ||||
| } ; | ||||
							
								
								
									
										40
									
								
								util/grind/LLgen.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								util/grind/LLgen.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'}); | ||||
| }; | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								util/grind/PROBLEMS
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								util/grind/PROBLEMS
									
										
									
									
									
										Normal file
									
								
							|  | @ -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. | ||||
							
								
								
									
										3
									
								
								util/grind/READ_ME
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								util/grind/READ_ME
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| This is GRIND (GRind Is Not Dbx). This program is still being developed, | ||||
| so behaviour may change without notice. | ||||
| 
 | ||||
							
								
								
									
										5
									
								
								util/grind/ack-defs.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								util/grind/ack-defs.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| # definition of EMHOME | ||||
| 
 | ||||
| %if (%not defined(EMHOME), { | ||||
|     EMHOME = /usr/proj/em/Work; | ||||
| }); | ||||
							
								
								
									
										245
									
								
								util/grind/avl.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								util/grind/avl.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										43
									
								
								util/grind/avl.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								util/grind/avl.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
							
								
								
									
										43
									
								
								util/grind/cc_hh_tools.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								util/grind/cc_hh_tools.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'}); | ||||
| }; | ||||
							
								
								
									
										71
									
								
								util/grind/char.ct
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								util/grind/char.ct
									
										
									
									
									
										Normal file
									
								
							|  | @ -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}; | ||||
							
								
								
									
										24
									
								
								util/grind/char_tools.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								util/grind/char_tools.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'}); | ||||
| }; | ||||
							
								
								
									
										48
									
								
								util/grind/class.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								util/grind/class.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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[]; | ||||
							
								
								
									
										590
									
								
								util/grind/commands.g
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										590
									
								
								util/grind/commands.g
									
										
									
									
									
										Normal file
									
								
							|  | @ -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"); | ||||
| } | ||||
| } | ||||
							
								
								
									
										679
									
								
								util/grind/dbx_string.g
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										679
									
								
								util/grind/dbx_string.g
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										194
									
								
								util/grind/dbxread.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								util/grind/dbxread.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
							
								
								
									
										65
									
								
								util/grind/dump.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								util/grind/dump.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
							
								
								
									
										13
									
								
								util/grind/expr.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								util/grind/expr.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										38
									
								
								util/grind/file.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								util/grind/file.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 */ | ||||
							
								
								
									
										15
									
								
								util/grind/idf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								util/grind/idf.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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> | ||||
							
								
								
									
										21
									
								
								util/grind/idf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								util/grind/idf.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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> | ||||
							
								
								
									
										163
									
								
								util/grind/itemlist.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								util/grind/itemlist.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										47
									
								
								util/grind/langdep.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								util/grind/langdep.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										32
									
								
								util/grind/langdep.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								util/grind/langdep.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
							
								
								
									
										146
									
								
								util/grind/list.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								util/grind/list.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
							
								
								
									
										121
									
								
								util/grind/main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								util/grind/main.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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"); | ||||
| } | ||||
							
								
								
									
										26
									
								
								util/grind/make.allocd
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								util/grind/make.allocd
									
										
									
									
									
										Executable file
									
								
							|  | @ -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))\ | ||||
| :' | ||||
							
								
								
									
										6
									
								
								util/grind/make.next
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								util/grind/make.next
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| sed -n ' | ||||
| s:^.*[ 	]ALLOCDEF[ 	].*"\(.*\)".*$:struct \1 *h_\1 = 0;\ | ||||
| #ifdef DEBUG\ | ||||
| int cnt_\1 = 0;\ | ||||
| #endif:p | ||||
| ' $* | ||||
							
								
								
									
										18
									
								
								util/grind/make.ops
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								util/grind/make.ops
									
										
									
									
									
										Executable file
									
								
							|  | @ -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 | ||||
							
								
								
									
										36
									
								
								util/grind/make.tokcase
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										36
									
								
								util/grind/make.tokcase
									
										
									
									
									
										Executable file
									
								
							|  | @ -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-- | ||||
							
								
								
									
										6
									
								
								util/grind/make.tokfile
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								util/grind/make.tokfile
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| sed ' | ||||
| /{[A-Z]/!d | ||||
| s/.*{// | ||||
| s/,.*// | ||||
| s/.*/%token	&;/ | ||||
| ' | ||||
							
								
								
									
										59
									
								
								util/grind/message.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								util/grind/message.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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))) | ||||
							
								
								
									
										61
									
								
								util/grind/modula-2.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								util/grind/modula-2.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										14
									
								
								util/grind/op_tools.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								util/grind/op_tools.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'}); | ||||
| }; | ||||
							
								
								
									
										12
									
								
								util/grind/operator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								util/grind/operator.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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) | ||||
							
								
								
									
										24
									
								
								util/grind/operators.ot
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								util/grind/operators.ot
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										196
									
								
								util/grind/position.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								util/grind/position.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										57
									
								
								util/grind/position.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								util/grind/position.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
							
								
								
									
										322
									
								
								util/grind/print.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								util/grind/print.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										134
									
								
								util/grind/rd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								util/grind/rd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										5
									
								
								util/grind/rd.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								util/grind/rd.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| /* $Header$ */ | ||||
| 
 | ||||
| #include	<out.h> | ||||
| 
 | ||||
| #define O_CONVERTED	0x202 | ||||
							
								
								
									
										523
									
								
								util/grind/run.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										523
									
								
								util/grind/run.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										131
									
								
								util/grind/scope.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								util/grind/scope.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										54
									
								
								util/grind/scope.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								util/grind/scope.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
							
								
								
									
										8
									
								
								util/grind/sizes.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								util/grind/sizes.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										237
									
								
								util/grind/symbol.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								util/grind/symbol.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										58
									
								
								util/grind/symbol.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								util/grind/symbol.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
							
								
								
									
										15
									
								
								util/grind/tok_tools.amk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								util/grind/tok_tools.amk
									
										
									
									
									
										Normal file
									
								
							|  | @ -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'}); | ||||
| }; | ||||
							
								
								
									
										88
									
								
								util/grind/tokenname.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								util/grind/tokenname.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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++; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										17
									
								
								util/grind/tokenname.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								util/grind/tokenname.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| }; | ||||
							
								
								
									
										594
									
								
								util/grind/tree.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										594
									
								
								util/grind/tree.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										32
									
								
								util/grind/tree.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								util/grind/tree.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
							
								
								
									
										387
									
								
								util/grind/type.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								util/grind/type.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
							
								
								
									
										118
									
								
								util/grind/type.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								util/grind/type.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| 
 | ||||
							
								
								
									
										125
									
								
								util/grind/value.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								util/grind/value.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue