Pristine Ack-5.5
[Ack-5.5.git] / util / grind / tree.c
1 /* $Id: tree.c,v 1.17 1995/08/17 14:32:55 ceriel Exp $ */
2
3 #include        <stdio.h>
4 #include        <assert.h>
5 #include        <alloc.h>
6 #include        <out.h>
7 #if __STDC__
8 #include        <stdarg.h>
9 #else
10 #include        <varargs.h>
11 #endif
12
13 #include        "operator.h"
14 #include        "position.h"
15 #include        "file.h"
16 #include        "idf.h"
17 #include        "tree.h"
18 #include        "scope.h"
19 #include        "symbol.h"
20 #include        "langdep.h"
21 #include        "type.h"
22 #include        "expr.h"
23 #include        "misc.h"
24
25 extern FILE     *db_out;
26 t_lineno        currline;
27 t_lineno        listline;
28 extern char     *strrindex();
29 extern int      interrupted;
30
31 #if __STDC__
32 /*VARARGS1*/
33 p_tree
34 mknode(int op, ...)
35 {
36   va_list ap;
37   register p_tree p = new_tree();
38
39   va_start(ap, op);
40   {
41         register int i, na;
42
43         p->t_oper = op;
44 #else
45 /*VARARGS1*/
46 p_tree
47 mknode(va_alist)
48   va_dcl
49 {
50   va_list ap;
51   register p_tree p = new_tree();
52
53   va_start(ap);
54   {
55         register int i, na;
56
57         p->t_oper = va_arg(ap, int);
58 #endif
59         switch(p->t_oper) {
60         case OP_NAME:
61         case OP_HELP:
62                 p->t_idf = va_arg(ap, struct idf *);
63                 p->t_str = va_arg(ap, char *);
64                 break;
65         case OP_STRING:
66                 p->t_sval = va_arg(ap, char *);
67                 break;
68         case OP_REAL:
69                 p->t_fval = va_arg(ap, double);
70                 break;
71         case OP_AT:
72                 p->t_lino = va_arg(ap, long);
73                 p->t_filename = va_arg(ap, char *);
74                 break;
75         case OP_INTEGER:
76                 p->t_ival = va_arg(ap, long);
77                 break;
78         default:
79                 na = nargs(p->t_oper);
80                 assert(na <= MAXARGS);
81                 for (i = 0; i < na; i++) {
82                         p->t_args[i] = va_arg(ap, p_tree);
83                 }
84                 break;
85         }
86   }
87   va_end(ap);
88   return p;
89 }
90
91 freenode(p)
92   register p_tree       p;
93 {
94   register int na, i;
95
96   if (! p) return;
97   na = nargs(p->t_oper);
98   assert(na <= MAXARGS);
99   for (i = 0; i < na; i++) {
100         freenode(p->t_args[i]);
101   }
102   free_tree(p);
103 }
104
105 t_addr
106 get_addr_from_node(p)
107   p_tree        p;
108 {
109   t_addr        a = ILL_ADDR;
110   register p_symbol sym;
111
112   if (! p) return NO_ADDR;
113   if (p->t_address != 0) return p->t_address;
114   switch(p->t_oper) {
115   case OP_AT:
116         if (! p->t_filename &&
117             (! listfile || ! (p->t_filename = listfile->sy_idf->id_text))) {
118                 error("no current file");
119                 break;
120         }
121         a = get_addr_from_position(&(p->t_pos));
122         if (a == ILL_ADDR) {
123                 error("could not determine address of \"%s\":%d",
124                         p->t_filename, p->t_lino);
125                 break;
126         }
127         p->t_address = a;
128         break;
129         
130   case OP_IN:
131         a =  get_addr_from_node(p->t_args[0]);
132
133         if (p->t_args[1]) {
134                 p_scope sc;
135
136                 a = get_addr_from_node(p->t_args[1]);
137                 sc = base_scope(get_scope_from_addr(a));
138                 sym = identify(p->t_args[0], FUNCTION|PROC|MODULE);
139                 if (! sym->sy_name.nm_scope ||
140                     ! sym->sy_name.nm_scope->sc_bp_opp) {
141                         error("could not determine address of \"%s\"", p->t_str);
142                         a = ILL_ADDR;
143                         break;
144                 }
145                 if (sc->sc_definedby != sym) {
146                         error("inconsistent address");
147                         a = ILL_ADDR;
148                         break;
149                 }
150         }
151         p->t_address = a;
152         break;
153
154   case OP_NAME:
155   case OP_SELECT:
156         sym = identify(p, FUNCTION|PROC|MODULE);
157         if (! sym) {
158                 break;
159         }
160         if (! sym->sy_name.nm_scope || ! sym->sy_name.nm_scope->sc_bp_opp) {
161                 error("could not determine address of \"%s\"", p->t_str);
162                 break;
163         }
164         a = sym->sy_name.nm_scope->sc_bp_opp;
165         break;
166
167   default:
168         assert(0);
169   }
170   return a;
171 }
172
173 static int      ommit_commas = 0;
174
175 print_node(f, p, top_level)
176   register p_tree       p;
177   register FILE         *f;
178 {
179   if (!p) return;
180   switch(p->t_oper) {
181   case OP_LOG:
182         fputs("log ", f);
183         print_node(f, p->t_args[0], 0);
184         break;
185   case OP_PRCOMM:
186         fputs("rerun ?", f);
187         break;
188   case OP_RUN:
189         fputs("run ", f);
190         ommit_commas = 1;
191         print_node(f, p->t_args[0], 0);
192         ommit_commas = 0;
193         break;
194   case OP_LIST:
195         fputs("list ", f);
196         if (p->t_args[0]) {
197                 print_node(f, p->t_args[0], 0);
198                 if (p->t_args[1]) {
199                         if (p->t_args[1]->t_ival >= 0) {
200                                 fputs(", ", f);
201                                 print_node(f, p->t_args[1], 0);
202                         }
203                         else  {
204                                 if (p->t_args[1]->t_ival < -100000000) {
205                                         fputs("-", f);
206                                 }
207                                 else print_node(f, p->t_args[1], 0);
208                         }
209                 }
210         }
211         break;
212   case OP_PRINT:
213         fputs("print ", f);
214         print_node(f, p->t_args[0], 0);
215         break;
216   case OP_SOURCE:
217         fputs("source ", f);
218         print_node(f, p->t_args[0], 0);
219         break;
220   case OP_ENABLE:
221         fputs("enable ", f);
222         print_node(f, p->t_args[0], 0);
223         break;
224   case OP_DISABLE:
225         fputs("disable ", f);
226         print_node(f, p->t_args[0], 0);
227         break;
228   case OP_DISPLAY:
229         fputs("display ", f);
230         print_node(f, p->t_args[0], 0);
231         break;
232   case OP_LINK:
233         print_node(f, p->t_args[0], 0);
234         if (! ommit_commas) fputs(", ", f);
235         else putc(' ', f);
236         print_node(f, p->t_args[1], 0);
237         break;
238   case OP_FILE:
239         fputs("file ", f);
240         print_node(f, p->t_args[0], 0);
241         break;
242   case OP_FRAME:
243         fputs("frame ", f);
244         print_node(f, p->t_args[0], 0);
245         break;
246   case OP_UP:
247         fputs("frame +", f);
248         print_node(f, p->t_args[0], 0);
249         break;
250   case OP_DOWN:
251         fputs("frame -", f);
252         print_node(f, p->t_args[0], 0);
253         break;
254   case OP_SET:
255         fputs("set ", f);
256         print_node(f, p->t_args[0], 0);
257         fputs(" to ", f);
258         print_node(f, p->t_args[1], 0);
259         break;
260   case OP_FIND:
261         fputs("find ", f);
262         print_node(f, p->t_args[0], 0);
263         break;
264   case OP_WHICH:
265         fputs("which ", f);
266         print_node(f, p->t_args[0], 0);
267         break;
268   case OP_DELETE:
269         fputs("delete ", f);
270         print_node(f, p->t_args[0], 0);
271         break;
272   case OP_REGS:
273         fputs("regs ", f);
274         print_node(f, p->t_args[0], 0);
275         break;
276   case OP_NEXT:
277         fputs("next ", f);
278         print_node(f, p->t_args[0], 0);
279         break;
280   case OP_STEP:
281         fputs("step ", f);
282         print_node(f, p->t_args[0], 0);
283         break;
284   case OP_STATUS:
285         fputs("status", f);
286         break;
287   case OP_DUMP:
288         fputs("dump ", f);
289         (void) print_position(p->t_address, 1);
290         break;
291   case OP_RESTORE:
292         fputs("restore ", f);
293         print_node(f, p->t_args[0], 0);
294         break;
295   case OP_WHERE:
296         fputs("where ", f);
297         print_node(f, p->t_args[0], 0);
298         break;
299   case OP_HELP:
300         fputs("help ", f);
301         print_node(f, p->t_args[0], 0);
302         break;
303   case OP_CONT:
304         fputs("cont", f);
305         if (p->t_args[0]) {
306                 fprintf(f, " %ld", p->t_args[0]->t_ival);
307         }
308         if (p->t_args[1]) {
309                 fputs(" ", f);
310                 print_node(f, p->t_args[1], 0);
311         }
312         break;
313
314   case OP_WHEN:
315         fputs("when ", f);
316         if (p->t_address != NO_ADDR) {
317                 (void) print_position(p->t_address, 1);
318         }
319         else print_node(f, p->t_args[0], 0);
320         if (p->t_args[1]) {
321                 fputs(" if ", f);
322                 print_node(f, p->t_args[1], 0);
323         }
324         p = p->t_args[2];
325         fputs(" { ", f);
326         while (p && p->t_oper == OP_LINK) {
327                 print_node(f, p->t_args[0], 0);
328                 fputs("; ", f);
329                 p = p->t_args[1];
330         }
331         print_node(f, p, 0);
332         fputs(" }", f);
333         break;
334   case OP_STOP:
335         fputs("stop ", f);
336         if (p->t_address != NO_ADDR) {
337                 (void) print_position(p->t_address, 1);
338         }
339         else print_node(f, p->t_args[0], 0);
340         if (p->t_args[1]) {
341                 fputs(" if ", f);
342                 print_node(f, p->t_args[1], 0);
343         }
344         break;
345   case OP_TRACE:
346         fputs("trace ", f);
347         if (p->t_args[2]) {
348                 fputs("on ", f);
349                 print_node(f, p->t_args[2], 0);
350                 fputs(" ", f);
351         }
352         if (p->t_address != NO_ADDR) {
353                 (void) print_position(p->t_address, 1);
354         }
355         else print_node(f, p->t_args[0], 0);
356         if (p->t_args[1]) {
357                 fputs(" if ", f);
358                 print_node(f, p->t_args[1], 0);
359         }
360         break;
361   case OP_AT:
362         fprintf(f, "at \"%s\":%d", p->t_filename, (int) p->t_lino);
363         break;
364   case OP_IN:
365         fputs("in ", f);
366         print_node(f, p->t_args[0], 0);
367         fputs(" ", f);
368         print_node(f, p->t_args[1], 0);
369         break;
370   case OP_SELECT:
371         print_node(f, p->t_args[0], 0);
372         fputs("`", f);
373         print_node(f, p->t_args[1], 0);
374         break;
375   case OP_OUTPUT:
376         fprintf(f, "> %s ", p->t_str);
377         break;
378   case OP_INPUT:
379         fprintf(f, "< %s ", p->t_str);
380         break;
381   case OP_NAME:
382         fputs(p->t_str, f);
383         break;
384   case OP_INTEGER:
385         fprintf(f, currlang->decint_fmt, p->t_ival);
386         break;
387   case OP_STRING:
388         (*currlang->printstring)(f, p->t_sval, strlen(p->t_sval));
389         break;
390   case OP_REAL:
391         fprintf(f, currlang->real_fmt, p->t_fval);
392         break;
393   case OP_FORMAT:
394         print_node(f, p->t_args[0], 0);
395         fputs("\\", f);
396         print_node(f, p->t_args[1], 0);
397         break;
398   case OP_UNOP:
399   case OP_BINOP:
400         (*currlang->printop)(f, p);
401         break;
402   default:
403         assert(0);
404   }
405   if (top_level) fputs("\n", f);
406 }
407
408 int
409 repeatable(com)
410   p_tree        com;
411 {
412   switch(com->t_oper) {
413   case OP_CONT:
414         com->t_args[0]->t_ival = 1;
415         freenode(com->t_args[1]);
416         com->t_args[1] = 0;
417         return 1;
418   case OP_NEXT:
419   case OP_STEP:
420         freenode(com->t_args[0]);
421         com->t_args[0] = 0;
422         return 1;
423   case OP_LIST:
424         freenode(com->t_args[0]);
425         com->t_args[0] = 0;
426         freenode(com->t_args[1]);
427         com->t_args[1] = 0;
428         return 1;
429   }
430   return 0;
431 }
432
433 int
434 in_status(com)
435   p_tree        com;
436 {
437   switch(com->t_oper) {
438   case OP_PRCOMM:
439         /* not really in status but may not be removed */
440   case OP_STOP:
441   case OP_WHEN:
442   case OP_TRACE:
443   case OP_DUMP:
444   case OP_DISPLAY:
445         return 1;
446   }
447   return 0;
448 }
449
450 eval(p)
451   p_tree        p;
452 {
453   if (p && operators[p->t_oper].op_fun) (*operators[p->t_oper].op_fun)(p);
454 }
455
456 newfile(id)
457   register struct idf   *id;
458 {
459   register p_symbol sym = Lookup(id, PervasiveScope, FILESYM);
460
461   if (listfile != sym) listline = 1;
462   listfile = sym;
463   if (! listfile) {
464         listline = 1;
465         listfile = add_file(id->id_text);
466         listfile->sy_file->f_scope = FileScope;
467   }
468   find_language(strrindex(id->id_text, '.'));
469 }
470
471 int     in_wheninvoked;
472
473 perform(p, a)
474   register p_tree       p;
475   t_addr                a;
476 {
477   switch(p->t_oper) {
478   case OP_WHEN:
479         if (p->t_args[1] && ! eval_cond(p->t_args[1])) break;
480         p = p->t_args[2];
481         in_wheninvoked++;
482         while (p && p->t_oper == OP_LINK) {
483                 if (interrupted) return;
484                 if (p->t_args[0]) eval(p->t_args[0]);
485                 p = p->t_args[1];
486         }
487         if (interrupted) return;
488         if (p) eval(p);
489         in_wheninvoked--;
490         break;
491   case OP_TRACE:
492         if (p->t_args[0] && p->t_args[0]->t_oper == OP_IN) {
493                 register p_scope sc = base_scope(CurrentScope);
494         
495                 if (sc != get_scope_from_addr(p->t_args[0]->t_address)) {
496                         break;
497                 }
498         }
499         if (interrupted) return;
500         if (p->t_args[1] && ! eval_cond(p->t_args[1])) break;
501         list_position(get_position_from_addr(a));
502         if (p->t_args[2]) do_print(p->t_args[2]);
503         break;
504   default:
505         assert(0);
506   }
507 }
508
509 list_position(pos)
510   p_position    pos;
511 {
512   newfile(str2idf(pos->filename, 1));
513   currfile = listfile;
514   currline = pos->lineno;
515   lines(currfile->sy_file, (int)currline, (int)1);
516   listline = 0;
517 }