Jspice3
front.c
Go to the documentation of this file.
1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5  1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * The front-end command loop.
10  */
11 
12 #include "spice.h"
13 #include "cpdefs.h"
14 #include "suffix.h"
15 
16 /* Stuff to do control structures. We keep a history (seperate from the
17  * cshpar history, for now at least) of commands and their event numbers,
18  * with a block considered as a statement. In a goto, the first word in
19  * co_text is where to go, likewise for label. For conditional controls,
20  * we have to call ft_getpnames and ft_evaluate each time, since the
21  * dvec pointers will change... Also we should do variable and backquote
22  * substitution each time...
23  */
24 
25 struct control {
26  int co_type; /* One of CO_* ... */
27  wordlist *co_cond; /* if, while, dowhile */
28  char *co_foreachvar; /* foreach */
29  int co_numtimes; /* repeat, break & continue levels */
30  wordlist *co_text; /* Ordinary text and foreach values. */
31  struct control *co_parent; /* If this is inside a block. */
32  struct control *co_children; /* The contents of this block. */
33  struct control *co_elseblock; /* For if-then-else. */
34  struct control *co_next;
35  struct control *co_prev;
36 } ;
37 
38 
39 /* named control blocks */
40 struct block {
41  char *bl_name;
42  struct control *bl_cont;
43 } ;
44 
45 static void *BlockBase; /* hash header for control blocks */
46 
47 static bool cp_noexec; /* supress command execution on source */
48 
49 #define CO_UNFILLED 0
50 #define CO_STATEMENT 1
51 #define CO_WHILE 2
52 #define CO_DOWHILE 3
53 #define CO_IF 4
54 #define CO_FOREACH 5
55 #define CO_BREAK 6
56 #define CO_CONTINUE 7
57 #define CO_LABEL 8
58 #define CO_GOTO 9
59 #define CO_REPEAT 10
60 
61 /* We have to keep the control structures in a stack, so that when we do
62  * a 'source', we can push a fresh set onto the top... Actually there have
63  * to be two stacks -- one for the pointer to the list of control structs,
64  * and one for the 'current command' pointer...
65  */
66 
67 #define CONTROLSTACKSIZE 256 /* Better be enough. */
68 
70 static int stackp = 0;
71 
72 /* Struct from doblock() */
73 
74 struct retinfo {
75  int type; /* one of defines below */
76  union {
77  char *label;
78  int num;
79  } rt;
80 };
81 
82 #define NORMAL 1
83 #define BROKEN 2
84 #define CONTINUED 3
85 #define LABEL 4
86 
87 
88 #ifdef __STDC__
89 static void set_block(wordlist*);
90 static void eval_block(struct control*);
91 static void doblock(struct control*,struct retinfo*);
92 static wordlist *quicksub(wordlist*);
93 static void add_block(char*);
94 static struct control *findlabel(char*,struct control*);
95 static void freecontrol(struct control*);
96 static void docommand(wordlist*);
97 static struct comm *findcom(char*);
98 static wordlist *getcommand(char*);
99 static void pwlist(wordlist*,char*);
100 static void dodump(struct control*);
101 #else
102 static void set_block();
103 static void eval_block();
104 static void doblock();
105 static wordlist *quicksub();
106 static void add_block();
107 static struct control *findlabel();
108 static void freecontrol();
109 static void docommand();
110 static struct comm *findcom();
111 static wordlist *getcommand();
112 static void pwlist();
113 static void dodump();
114 #endif
115 
116 
117 /* Are we waiting for a command? This lets signal handling be
118 more clever. */
119 
120 bool cp_cwait = false;
121 char *cp_csep = ";";
122 
123 bool cp_dounixcom = false;
124 
125 
126 /* If there is an argument, give this to cshpar to use instead of stdin. In
127  * a few places, we call cp_evloop again if it returns 1 and exit (or close
128  * a file) if it returns 0... Because of the way sources are done, we can't
129  * allow the control structures to get blown away every time we return --
130  * probably every time we type source at the keyboard and every time a
131  * source returns to keyboard input is ok though -- use ft_controlreset.
132  */
133 
134 static char *noredirect[] = { "stop", NULL } ; /* Only one?? */
135 
136 void
138 
139 /* Manipulation of named control blocks */
140 wordlist *wl;
141 {
142  char *fname = NULL;
143  bool remove = false;
144  bool print = false;
145  bool add = false;
146  bool bind = false;
147  bool success;
148  wordlist *ww, *wn;
149  struct control *c;
150  struct block *b;
151 
152  if (wl) {
153  wl = wl_copy(wl);
154  for (ww = wl; wl; wl = wn) {
155  wn = wl->wl_next;
156  if (*wl->wl_word != '-')
157  continue;
158  else if (strchr(wl->wl_word,'f') || strchr(wl->wl_word,'d'))
159  remove = true;
160  else if (strchr(wl->wl_word,'p') || strchr(wl->wl_word,'t'))
161  print = true;
162  else if (strchr(wl->wl_word,'a'))
163  add = true;
164  else if (strchr(wl->wl_word,'b'))
165  bind = true;
166  else
167  continue;
168  if (wl->wl_prev)
169  wl->wl_prev->wl_next = wl->wl_next;
170  if (wl->wl_next)
171  wl->wl_next->wl_prev = wl->wl_prev;
172  if (ww == wl)
173  ww = wl->wl_next;
174  txfree(wl->wl_word);
175  txfree((char*)wl);
176  }
177  if (ww) {
178  fname = copy(ww->wl_word);
179  wl_free(ww);
180  }
181  }
182 
183  if (fname == NULL) {
184  if (bind) {
185  cp_bind(NULL);
186  return;
187  }
188  out_init();
189 
190  ww = wn = (wordlist*)htab_wl(BlockBase);
191  while (ww) {
192  out_printf("%s",ww->wl_word);
193  if (print || remove)
194  b = (struct block *)htab_get(ww->wl_word,BlockBase);
195  if (print) {
196  out_send(":\n");
197  for (c = b->bl_cont; c; c = c->co_next)
198  dodump(c);
199  }
200  else
201  out_send("\n");
202  if (remove) {
203  /* keep #_ and ## blocks, associated with circuits */
204  if (*b->bl_name != '#') {
205  cp_unbind(b->bl_name);
206  freecontrol(b->bl_cont);
207  tfree(b->bl_name);
208  txfree((char*)b);
210  }
211  }
212  ww = ww->wl_next;
213  }
214  wl_free(wn);
215  return;
216  }
217 
218  if (!print && !remove && !add && !bind)
219  add = true;
220 
221  if (print && !add) {
222  out_init();
223  b = (struct block *)htab_get(fname,BlockBase);
224  if (b) {
225  out_printf("%s:\n",b->bl_name);
226  if (print) {
227  for (c = b->bl_cont; c; c = c->co_next)
228  dodump(c);
229  }
230  }
231  }
232  if (remove) {
233  cp_unbind(fname);
234  cp_freeblock(fname);
235  }
236  if (add) {
237  cp_noexec = true;
238  success = cp_block(fname);
239  cp_noexec = false;
240  if (success)
241  add_block(fname);
242  else
243  fprintf(cp_err,"Error: %s not found, no block added.\n",fname);
244  }
245  if (print && add) {
246  out_init();
247  b = (struct block *)htab_get(fname,BlockBase);
248  if (b) {
249  out_printf("%s:\n",b->bl_name);
250  if (print) {
251  for (c = b->bl_cont; c; c = c->co_next)
252  dodump(c);
253  }
254  }
255  }
256  if (bind) {
257  cp_bind(fname);
258  }
259  txfree(fname);
260 }
261 
262 
263 void
265 
266 char *name;
267 wordlist *wl;
268 {
269  bool inter = cp_interactive;
270 
271  cp_interactive = false;
272  cp_pushcontrol();
273  cp_noexec = true;
274  for ( ; wl; wl = wl->wl_next)
275  cp_evloop(wl->wl_word);
276  cp_noexec = false;
277  cp_popcontrol();
278  cp_interactive = inter;
279  add_block(name);
280 }
281 
282 
283 bool
285 
286 char *name;
287 {
288 
289  if (htab_get(name,BlockBase))
290  return (true);
291  return (false);
292 }
293 
294 
295 void
297 
298 /* delete the named block from the list */
299 char *name;
300 {
301  struct block *b;
302 
303  if (!name || *name == '\0') return;
304 
305  b = (struct block *)htab_get(name,BlockBase);
306  if (b) {
307  tfree(b->bl_name);
308  freecontrol(b->bl_cont);
309  txfree((char*)b);
310  htab_delete(name,BlockBase);
311  }
312 }
313 
314 
315 int
316 cp_evloop(string)
317 
318 char *string;
319 {
320  wordlist *wlist, *ww;
321 /*
322 commented stuff is for mtrace
323 FILE *xfp;
324 */
325 
326  for (;;) {
327  wlist = getcommand(string);
328  if (wlist == NULL) {
329  /* End of file or end of user input,
330  could also be a syntax error */
331  if (!string) {
332  if (cend[stackp] && cend[stackp]->co_parent)
333  cp_resetcontrol();
334  cp_event--;
335  continue;
336  }
337  return (0);
338  }
339  if ((wlist->wl_word == NULL) || (*wlist->wl_word == '\0')) {
340  /* User just typed return. */
341  tfree(wlist->wl_word);
342  tfree(wlist);
343  if (string)
344  return (1);
345  cp_event--;
346  continue;
347  }
348 
349  /* Just a check... */
350  for (ww = wlist; ww; ww = ww->wl_next)
351  if (!ww->wl_word) {
352  fprintf(cp_err,
353  "cp_evloop: Internal Error: NULL word pointer.\n");
354  continue;
355  }
356 
357  set_block(wlist);
358 /*
359 if (!string) {
360 xfp = fopen("mtemp","a");
361 wl_print(wlist,xfp);
362 fprintf(xfp,"\n");
363 }
364 */
365  wl_free(wlist);
366  if (cend[stackp] && !cend[stackp]->co_parent && !cp_noexec) {
367  eval_block(cend[stackp]);
368  freecontrol(control[stackp]);
369  control[stackp] = cend[stackp] = NULL;
370  }
371  if (string)
372  return (1); /* The return value is irrelevant. */
373 /*
374 cp_periodic();
375 mt_dump(xfp);
376 fclose(xfp);
377 */
378  }
379 }
380 
381 
382 static void
384 
385 wordlist *wl;
386 {
387  struct control *cur;
388  wordlist *ww;
389  struct control *x;
390 
391  /* Add wl to the control structure list. If cend->co_type
392  * is CO_UNFILLED, the last line was the beginning of a
393  * block, and this is the unfilled first statement.
394  */
395 
396 #define newblock cur->co_children = alloc(struct control); \
397  cur->co_children->co_parent = cur; \
398  cur = cur->co_children; \
399  cur->co_type = CO_UNFILLED;
400 
401  cur = cend[stackp];
402 
403  if (cur && (cur->co_type != CO_UNFILLED)) {
404  cur->co_next = alloc(struct control);
405  cur->co_next->co_prev = cur;
406  cur->co_next->co_parent = cur->co_parent;
407  cur = cur->co_next;
408  }
409  else if (!cur)
410  control[stackp] = cur = alloc(struct control);
411 
412  if (eq(wl->wl_word, "while")) {
413  cur->co_type = CO_WHILE;
414  cur->co_cond = wl_copy(wl->wl_next);
415  if (!cur->co_cond) {
416  fprintf(stderr,"Error: missing while condition.\n");
417  }
418  newblock;
419  }
420  else if (eq(wl->wl_word, "dowhile")) {
421  cur->co_type = CO_DOWHILE;
422  cur->co_cond = wl_copy(wl->wl_next);
423  if (!cur->co_cond) {
424  fprintf(stderr,"Error: missing dowhile condition.\n");
425  }
426  newblock;
427  }
428  else if (eq(wl->wl_word, "repeat")) {
429  cur->co_type = CO_REPEAT;
430  if (!wl->wl_next) {
431  cur->co_numtimes = -1;
432  }
433  else {
434  char *s = NULL;
435  double *dd;
436 
437  ww = quicksub(wl);
438  if (ww && ww->wl_next)
439  s = ww->wl_next->wl_word;
440 
441  dd = ft_numparse(&s, false);
442  if (dd) {
443  if (*dd < 0) {
444  fprintf(cp_err,
445  "Error: can't repeat a negative number of times.\n");
446  *dd = 0.0;
447  }
448  cur->co_numtimes = (int) *dd;
449  }
450  else
451  fprintf(cp_err,
452  "Error: bad repeat argument %s.\n",s ? s : "");
453  if (ww)
454  wl_free(ww);
455  }
456  newblock;
457  }
458  else if (eq(wl->wl_word, "if")) {
459  cur->co_type = CO_IF;
460  cur->co_cond = wl_copy(wl->wl_next);
461  if (!cur->co_cond) {
462  fprintf(stderr,"Error: missing if condition.\n");
463  }
464  newblock;
465  }
466  else if (eq(wl->wl_word, "foreach")) {
467  cur->co_type = CO_FOREACH;
468  ww = wl;
469  if (ww->wl_next) {
470  ww = ww->wl_next;
471  cur->co_foreachvar = copy(ww->wl_word);
472  ww = ww->wl_next;
473  }
474  else
475  fprintf(stderr,"Error: missing foreach variable.\n");
476  ww = wl_copy(ww);
477  cp_doglob(&ww);
478  cur->co_text = ww;
479  newblock;
480  }
481  else if (eq(wl->wl_word, "label")) {
482  cur->co_type = CO_LABEL;
483  if (wl->wl_next) {
484  cur->co_text = wl_copy(wl->wl_next);
485  /* I think of everything, don't I? */
486  cp_addkword(CT_LABEL, wl->wl_next->wl_word);
487  if (wl->wl_next->wl_next)
488  fprintf(cp_err,
489  "Warning: ignored extra junk after label.\n");
490  }
491  else
492  fprintf(stderr, "Error: missing label.\n");
493  }
494  else if (eq(wl->wl_word, "goto")) {
495  /* Incidentally, this won't work if the values 1 and
496  * 2 ever get to be valid character pointers -- I
497  * think it's reasonably safe to assume they aren't...
498  */
499  cur->co_type = CO_GOTO;
500  if (wl->wl_next) {
501  cur->co_text = wl_copy(wl->wl_next);
502  if (wl->wl_next->wl_next)
503  fprintf(cp_err,
504  "Warning: ignored extra junk after goto.\n");
505  }
506  else
507  fprintf(stderr, "Error: missing label.\n");
508  }
509  else if (eq(wl->wl_word, "continue")) {
510  cur->co_type = CO_CONTINUE;
511  if (wl->wl_next) {
512  cur->co_numtimes = scannum(wl->wl_next->wl_word);
513  if (wl->wl_next->wl_next)
514  fprintf(cp_err,
515  "Warning: ignored extra junk after continue %d.\n",
516  cur->co_numtimes);
517  }
518  else
519  cur->co_numtimes = 1;
520  }
521  else if (eq(wl->wl_word, "break")) {
522  cur->co_type = CO_BREAK;
523  if (wl->wl_next) {
524  cur->co_numtimes = scannum(wl->wl_next->wl_word);
525  if (wl->wl_next->wl_next)
526  fprintf(cp_err,
527  "Warning: ignored extra junk after break %d.\n",
528  cur->co_numtimes);
529  }
530  else
531  cur->co_numtimes = 1;
532  }
533  else if (eq(wl->wl_word, "end")) {
534  /* Throw away this thing. */
535  if (!cur->co_parent) {
536  fprintf(stderr, "Error: no block to end.\n");
537  cur->co_type = CO_UNFILLED;
538  }
539  else if (cur->co_prev) {
540  cur->co_prev->co_next = NULL;
541  x = cur;
542  cur = cur->co_parent;
543  tfree(x);
544  }
545  else {
546  x = cur;
547  cur = cur->co_parent;
548  cur->co_children = NULL;
549  tfree(x);
550  }
551  }
552  else if (eq(wl->wl_word, "else")) {
553  if (!cur->co_parent ||
554  (cur->co_parent->co_type != CO_IF)) {
555  fprintf(stderr, "Error: misplaced else.\n");
556  cur->co_type = CO_UNFILLED;
557  }
558  else {
559  if (cur->co_prev)
560  cur->co_prev->co_next = NULL;
561  else
562  cur->co_parent->co_children = NULL;
563  cur->co_parent->co_elseblock = cur;
564  cur->co_prev = NULL;
565  }
566  }
567  else {
568  cur->co_type = CO_STATEMENT;
569  cur->co_text = wl_copy(wl);
570  }
571  cend[stackp] = cur;
572 }
573 
574 
575 static void
577 
578 struct control *x;
579 {
580  struct retinfo ri;
581 
582  /* We have to toss this do-while loop in here so
583  * that gotos at the top level will work.
584  */
585  do {
586  doblock(x, &ri);
587  switch (ri.type) {
588 
589  case NORMAL:
590  break;
591 
592  case BROKEN:
593  fprintf(cp_err,
594 "Error: break not in loop or too many break levels given.\n");
595  break;
596 
597  case CONTINUED:
598  fprintf(cp_err,
599 "Error: continue not in loop or too many continue levels given.\n");
600  break;
601 
602  case LABEL:
603  x = findlabel(ri.rt.label,control[stackp]);
604  if (!x)
605  fprintf(cp_err,
606  "Error: label %s not found.\n",ri.rt.label);
607  txfree(ri.rt.label);
608  }
609  if (x)
610  x = x->co_next;
611  } while (x);
612 }
613 
614 
615 /* Execute a block. There can be a number of return values from this routine.
616  * NORMAL indicates a normal termination
617  * BROKEN indicates a break -- if the caller is a breakable loop,
618  * terminate it, otherwise pass the break upwards
619  * CONTINUED indicates a continue -- if the caller is a continuable loop,
620  * continue, else pass the continue upwards
621  * Any other return code is considered a pointer to a string which is
622  * a label somewhere -- if this label is present in the block,
623  * goto it, otherwise pass it up. Note that this prevents jumping
624  * into a loop, which is good.
625  * Note that here is where we expand variables, ``, and globs for controls.
626  * The 'num' argument is used by break n and continue n.
627  */
628 
629 static void
630 doblock(bl, info)
631 
632 struct control *bl;
633 struct retinfo *info;
634 {
635  struct control *ch, *cn = NULL;
636  wordlist *wl, *ww;
637  struct retinfo ri;
638 
639  switch (bl->co_type) {
640 
641  case CO_WHILE:
642  while (bl->co_cond && cp_istrue(bl->co_cond)) {
643  for (ch = bl->co_children; ch; ch = cn) {
644  cn = ch->co_next;
645  doblock(ch, &ri);
646  switch (ri.type) {
647 
648  case NORMAL:
649  break;
650 
651  case BROKEN: /* Break. */
652  if (ri.rt.num < 2) {
653  info->type = NORMAL;
654  }
655  else {
656  info->rt.num = ri.rt.num - 1;
657  info->type = BROKEN;
658  }
659  return;
660 
661  case CONTINUED: /* Continue. */
662  if (ri.rt.num < 2) {
663  cn = NULL;
664  break;
665  }
666  else {
667  info->rt.num = ri.rt.num - 1;
668  info->type = CONTINUED;
669  return;
670  }
671 
672  case LABEL:
673  cn = findlabel(ri.rt.label, bl->co_children);
674  if (!cn) {
675  info->type = LABEL;
676  info->rt.label = ri.rt.label;
677  return;
678  }
679  txfree(ri.rt.label);
680  }
681  }
682  }
683  break;
684 
685  case CO_DOWHILE:
686  do {
687  for (ch = bl->co_children; ch; ch = cn) {
688  cn = ch->co_next;
689  doblock(ch, &ri);
690  switch (ri.type) {
691 
692  case NORMAL:
693  break;
694 
695  case BROKEN: /* Break. */
696  if (ri.rt.num < 2) {
697  info->type = NORMAL;
698  }
699  else {
700  info->rt.num = ri.rt.num - 1;
701  info->type = BROKEN;
702  }
703  return;
704 
705  case CONTINUED: /* Continue. */
706  if (ri.rt.num < 2) {
707  cn = NULL;
708  break;
709  }
710  else {
711  info->rt.num = ri.rt.num - 1;
712  info->type = CONTINUED;
713  return;
714  }
715 
716  case LABEL:
717  cn = findlabel(ri.rt.label, bl->co_children);
718  if (!cn) {
719  info->type = LABEL;
720  info->rt.label = ri.rt.label;
721  return;
722  }
723  txfree(ri.rt.label);
724  }
725  }
726  } while (bl->co_cond && cp_istrue(bl->co_cond));
727  break;
728 
729  case CO_REPEAT:
730  while ((bl->co_numtimes > 0) ||
731  (bl->co_numtimes == -1)) {
732  if (bl->co_numtimes != -1)
733  bl->co_numtimes--;
734  for (ch = bl->co_children; ch; ch = cn) {
735  cn = ch->co_next;
736  doblock(ch, &ri);
737  switch (ri.type) {
738 
739  case NORMAL:
740  break;
741 
742  case BROKEN: /* Break. */
743  if (ri.rt.num < 2) {
744  info->type = NORMAL;
745  }
746  else {
747  info->rt.num = ri.rt.num - 1;
748  info->type = BROKEN;
749  }
750  return;
751 
752  case CONTINUED: /* Continue. */
753  if (ri.rt.num < 2) {
754  cn = NULL;
755  break;
756  }
757  else {
758  info->rt.num = ri.rt.num - 1;
759  info->type = CONTINUED;
760  return;
761  }
762 
763  case LABEL:
764  cn = findlabel(ri.rt.label, bl->co_children);
765  if (!cn) {
766  info->type = LABEL;
767  info->rt.label = ri.rt.label;
768  return;
769  }
770  txfree(ri.rt.label);
771  }
772  }
773  }
774  break;
775 
776  case CO_IF:
777  if (bl->co_cond && cp_istrue(bl->co_cond)) {
778  for (ch = bl->co_children; ch; ch = cn) {
779  cn = ch->co_next;
780  doblock(ch, &ri);
781  if (ri.type == LABEL) {
782  cn = findlabel(ri.rt.label,bl->co_children);
783  if (!cn) {
784  info->type = LABEL;
785  info->rt.label = ri.rt.label;
786  return;
787  }
788  txfree(ri.rt.label);
789  }
790  else if (ri.type != NORMAL) {
791  info->type = ri.type;
792  info->rt.num = ri.rt.num;
793  return;
794  }
795  }
796  }
797  else {
798  for (ch = bl->co_elseblock; ch; ch = cn) {
799  cn = ch->co_next;
800  doblock(ch, &ri);
801  if (ri.type == LABEL) {
802  cn = findlabel(ri.rt.label,bl->co_elseblock);
803  if (!cn) {
804  info->type = LABEL;
805  info->rt.label = ri.rt.label;
806  return;
807  }
808  txfree(ri.rt.label);
809  }
810  else if (ri.type != NORMAL) {
811  info->type = ri.type;
812  info->rt.num = ri.rt.num;
813  return;
814  }
815  }
816  }
817  break;
818 
819  case CO_FOREACH:
820  ww = quicksub(bl->co_text);
821  for (wl = ww; wl; wl = wl->wl_next) {
822  cp_vset(bl->co_foreachvar, VT_STRING,wl->wl_word);
823  for (ch = bl->co_children; ch; ch = cn) {
824  cn = ch->co_next;
825  doblock(ch, &ri);
826  switch (ri.type) {
827 
828  case NORMAL:
829  break;
830 
831  case BROKEN: /* Break. */
832  if (ri.rt.num < 2) {
833  info->type = NORMAL;
834  }
835  else {
836  info->rt.num = ri.rt.num - 1;
837  info->type = BROKEN;
838  }
839  return;
840 
841  case CONTINUED: /* Continue. */
842  if (ri.rt.num < 2) {
843  cn = NULL;
844  break;
845  }
846  else {
847  info->rt.num = ri.rt.num - 1;
848  info->type = CONTINUED;
849  return;
850  }
851 
852  case LABEL:
853  cn = findlabel(ri.rt.label, bl->co_children);
854  if (!cn) {
855  info->type = LABEL;
856  info->rt.label = ri.rt.label;
857  return;
858  }
859  txfree(ri.rt.label);
860  }
861  }
862  }
863  wl_free(ww);
864  break;
865 
866  case CO_BREAK:
867  if (bl->co_numtimes > 0) {
868  info->rt.num = bl->co_numtimes;
869  info->type = BROKEN;
870  return;
871  }
872  fprintf(cp_err, "Warning: break %d a no-op\n",
873  bl->co_numtimes);
874  break;
875 
876  case CO_CONTINUE:
877  if (bl->co_numtimes > 0) {
878  info->rt.num = bl->co_numtimes;
879  info->type = CONTINUED;
880  return;
881  }
882  fprintf(cp_err, "Warning: continue %d a no-op\n",
883  bl->co_numtimes);
884  break;
885 
886  case CO_GOTO:
887  wl = quicksub(bl->co_text);
888  if (wl) {
889  if (wl->wl_word) {
890  info->type = LABEL;
891  info->rt.label = copy(wl->wl_word);
892  return;
893  }
894  wl_free(wl);
895  }
896  break;
897 
898  case CO_LABEL:
899  /* Do nothing. */
900  break;
901 
902  case CO_STATEMENT:
903  docommand(wl_copy(bl->co_text));
904  break;
905 
906  case CO_UNFILLED:
907  /* There was probably an error here... */
908  fprintf(cp_err, "Warning: ignoring previous error.\n");
909  break;
910 
911  default:
912  fprintf(cp_err,
913  "doblock: Internal Error: bad block type %d.\n",
914  bl->co_type);
915  }
916  info->type = NORMAL;
917 }
918 
919 
920 static wordlist *
922 
923 wordlist *wl;
924 {
925  wordlist *nwl;
926 
927  nwl = wl_copy(wl);
928  cp_doglob(&nwl);
929  cp_bquote(&nwl);
930  cp_variablesubst(&nwl);
931  return (nwl);
932 }
933 
934 
935 static void
937 
938 /* add the new block to the list of named blocks */
939 char *name;
940 {
941  struct block *b;
942 
943  if (!name || *name == '\0') return;
944  if (!control[stackp+1]) {
945  fprintf(cp_err, "Error: block is empty, not added.\n");
946  return;
947  }
948 
949  b = (struct block *)htab_get(name,BlockBase);
950  if (b)
951  freecontrol(b->bl_cont);
952  else {
953  b = alloc(struct block);
954  b->bl_name = copy(name);
955  if (BlockBase == NULL)
956  BlockBase = htab_init();
957  htab_add(name,(void*)b,BlockBase);
958  }
959  b->bl_cont = control[stackp+1];
960  control[stackp+1] = cend[stackp+1] = NULL;
961 }
962 
963 
964 void
966 
967 /* execute the control structure either named, or the one just above
968  * if name is NULL
969  */
970 char *name;
971 {
972  struct control *x;
973  struct block *b = NULL;
974 
975  ++stackp;
976  if (name) {
977  b = (struct block *)htab_get(name,BlockBase);
978  if (!b) {
979  fprintf(cp_err,"Error: named block %s not found.\n",name);
980  return;
981  }
982  }
983  if (b) {
984  x = control[stackp];
985  control[stackp] = b->bl_cont;
986  eval_block(control[stackp]);
987  control[stackp] = x;
988  }
989  else
990  eval_block(control[stackp]);
991  --stackp;
992 }
993 
994 
995 static struct control *
997 
998 char *s;
999 struct control *ct;
1000 {
1001  while (ct) {
1002  if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word))
1003  break;
1004  ct = ct->co_next;
1005  }
1006  return (ct);
1007 }
1008 
1009 
1010 static void
1012 
1013 /* free the control structure */
1014 struct control *cntrl;
1015 {
1016  struct control *cc, *cd;
1017 
1018  for (cc = cntrl; cc; cc = cd) {
1019  wl_free(cc->co_cond);
1020  wl_free(cc->co_text);
1021  tfree(cc->co_foreachvar);
1022  if (cc->co_children)
1023  freecontrol(cc->co_children);
1024  if (cc->co_elseblock)
1026  cd = cc->co_next;
1027  tfree(cc);
1028  }
1029 }
1030 
1031 
1032 void
1034 
1035 /* This blows away the control structures... */
1036 {
1037  if (cend[stackp] && cend[stackp]->co_parent)
1038  fprintf(cp_err, "Warning: EOF before block terminated\n");
1039  for (stackp = 0; stackp < CONTROLSTACKSIZE; stackp++) {
1040  if (!control[stackp]) break;
1041  freecontrol(control[stackp]);
1042  control[stackp] = cend[stackp] = NULL;
1043  }
1044  stackp = 0;
1045  (void) cp_kwswitch(CT_LABEL, (char *) NULL);
1046  return;
1047 }
1048 
1049 
1050 void
1052 
1053 /* Push or pop a new control structure set... */
1054 {
1055  if (cp_debug)
1056  fprintf(cp_err, "pop: stackp: %d -> %d\n", stackp, stackp - 1);
1057  if (stackp < 1)
1058  fprintf(cp_err, "cp_popcontrol: Internal Error: stack empty\n");
1059  else
1060  stackp--;
1061  return;
1062 }
1063 
1064 
1065 void
1067 {
1068  if (cp_debug)
1069  fprintf(cp_err, "push: stackp: %d -> %d\n", stackp, stackp + 1);
1070  if (stackp > CONTROLSTACKSIZE - 2) {
1071  fprintf(cp_err, "Error: stack overflow -- max depth = %d\n",
1073  stackp = 0;
1074  }
1075  else {
1076  stackp++;
1077  freecontrol(control[stackp]);
1078  control[stackp] = cend[stackp] = NULL;
1079  }
1080  return;
1081 }
1082 
1083 
1084 
1085 void
1087 
1088 /* And this returns to the top level (for use in the interrupt handlers). */
1089 {
1090  stackp = 0;
1091  if (cend[stackp])
1092  while (cend[stackp]->co_parent)
1093  cend[stackp] = cend[stackp]->co_parent;
1094  return;
1095 }
1096 
1097 
1098 /* Note that we only do io redirection when we get to here - we also
1099  * postpone some other things until now.
1100  * NOTE! wlist is freed.
1101  */
1102 
1103 static void
1105 
1106 wordlist *wlist;
1107 {
1108  char *r, *s, *t;
1109  char *lcom;
1110  int nargs;
1111  int i;
1112  struct comm *command;
1113  wordlist *wl, *nextc, *ee, *rwlist;
1114  struct block *b;
1115  FILE *lastin, *lastout, *lasterr;
1116  bool tmpintr;
1117 
1118  if (cp_debug) {
1119  printf("docommand ");
1120  wl_print(wlist, stdout);
1121  (void) putc('\n', stdout);
1122  }
1123 
1124  /* do periodic sorts of things */
1125  cp_periodic();
1126 
1127  /* Do all the things that used to be done by cshpar when the line
1128  * was read...
1129  */
1130  cp_variablesubst(&wlist);
1131  pwlist(wlist, "After variable substitution");
1132 
1133  cp_bquote(&wlist);
1134  pwlist(wlist, "After backquote substitution");
1135 
1136  cp_doglob(&wlist);
1137  pwlist(wlist, "After globbing");
1138 
1139  if (!wlist || !wlist->wl_word)
1140  return;
1141 
1142  /* Now loop through all of the commands given. */
1143  rwlist = wlist;
1144  do {
1145  for (nextc = wlist; nextc; nextc = nextc->wl_next)
1146  if (eq(nextc->wl_word, cp_csep))
1147  break;
1148 
1149  /* Temporarily hide the rest of the command... */
1150  if (nextc && nextc->wl_prev)
1151  nextc->wl_prev->wl_next = NULL;
1152  ee = wlist->wl_prev;
1153  if (ee)
1154  wlist->wl_prev = NULL;
1155 
1156  if (nextc == wlist) {
1157  /* There was no text... */
1158  goto out;
1159  }
1160 
1161  /* And do the redirection. */
1162  cp_ioreset();
1163  for (i = 0; noredirect[i]; i++)
1164  if (eq(wlist->wl_word, noredirect[i]))
1165  break;
1166  if (!noredirect[i]) {
1167  cp_redirect(&wlist);
1168  if (wlist == NULL) {
1169  cp_ioreset();
1170  return;
1171  }
1172  }
1173 
1174  /* Get rid of all the 8th bits now... */
1175  cp_striplist(wlist);
1176 
1177  s = wlist->wl_word;
1178 
1179  /* initialize the more'd output */
1180  out_init();
1181 
1182  /* First check the named blocks. */
1183  b = (struct block *)htab_get(s,BlockBase);
1184  if (b) {
1185  struct control *x;
1186 
1187  cp_pusharg(wlist);
1188  lastin = cp_curin;
1189  lastout = cp_curout;
1190  lasterr = cp_curerr;
1191  cp_curin = cp_in;
1192  cp_curout = cp_out;
1193  cp_curerr = cp_err;
1194  tmpintr = cp_interactive;
1195  cp_interactive = false;
1196 
1197  /* replace call to cp_execcontrol() */
1198  ++stackp;
1199  x = control[stackp];
1200  control[stackp] = b->bl_cont;
1201  eval_block(control[stackp]);
1202  control[stackp] = x;
1203  --stackp;
1204 
1205  cp_interactive = tmpintr;
1206  cp_curin = lastin;
1207  cp_curout = lastout;
1208  cp_curerr = lasterr;
1209  cp_poparg();
1210  goto out;
1211  }
1212  command = findcom(s);
1213  if (!command) {
1214  if (cp_oddcomm(s,wlist))
1215  goto out;
1216  if (cp_dounixcom && cp_unixcom(wlist))
1217  goto out;
1218  fprintf(cp_err,"%s: no such command available in %s\n",
1219  s, cp_program);
1220  goto out;
1221  }
1222  else if (ft_nutmeg && command->co_spiceonly) {
1223  /* If it's there but spiceonly, and this is nutmeg, error. */
1224  fprintf(cp_err,"%s: command available only in spice\n",s);
1225  goto out;
1226  }
1227 
1228  nargs = 0;
1229  for (wl = wlist->wl_next; wl; wl = wl->wl_next)
1230  nargs++;
1231  if (command->co_stringargs) {
1232  lcom = wl_flatten(wlist->wl_next);
1233  (*command->co_func) (lcom);
1234  tfree(lcom);
1235  }
1236  else {
1237  if (nargs < command->co_minargs) {
1238  if (command->co_argfn) {
1239  (*command->co_argfn) (wlist->wl_next, command);
1240  }
1241  else {
1242  fprintf(cp_err, "%s: too few args.\n", s);
1243  }
1244  }
1245  else if (nargs > command->co_maxargs) {
1246  fprintf(cp_err, "%s: too many args.\n", s);
1247  }
1248  else
1249  (*command->co_func) (wlist->wl_next);
1250  }
1251 
1252 out:
1253  /* Now fix the pointers and advance wlist. */
1254  wlist->wl_prev = ee;
1255  if (nextc) {
1256  if (nextc->wl_prev)
1257  nextc->wl_prev->wl_next = nextc;
1258  wlist = nextc->wl_next;
1259  }
1260  } while (nextc && wlist);
1261 
1262  wl_free(rwlist);
1263  cp_ioreset();
1264  return;
1265 }
1266 
1267 
1268 static struct comm *
1270 
1271 char *cmd;
1272 {
1273  static void *comhash;
1274  int i;
1275 
1276  if (!comhash) {
1277  comhash = htab_init();
1278  for (i = 0; cp_coms[i].co_comname; i++)
1279  htab_add(cp_coms[i].co_comname,(void*)&cp_coms[i],comhash);
1280  }
1281  return (struct comm *)htab_get(cmd,comhash);
1282 }
1283 
1284 
1285 /* Get a command. This does all the bookkeeping things like turning
1286  * command completion on and off...
1287  */
1288 
1289 static wordlist *
1290 getcommand(string)
1291 
1292 char *string;
1293 {
1294  wordlist *wlist;
1295  int i, j;
1296  static char buf[64];
1297  struct control *c;
1298 
1299  if (cp_debug)
1300  fprintf(cp_err, "calling getcommand %s\n",
1301  string ? string : "");
1302  cp_altprompt = NULL;
1303  if (cend[stackp]) {
1304  i = 0;
1305  for (c = cend[stackp]->co_parent; c; c = c->co_parent)
1306  i++;
1307  if (i) {
1308  for (j = 0; j < i; j++)
1309  buf[j] = '>';
1310  buf[j] = ' ';
1311  buf[j + 1] = '\0';
1312  cp_altprompt = buf;
1313  }
1314  }
1315  cp_cwait = true;
1316  wlist = cp_parse(string);
1317  cp_cwait = false;
1318  if (cp_debug) {
1319  printf("getcommand ");
1320  wl_print(wlist, stdout);
1321  (void) putc('\n', stdout);
1322  }
1323  return (wlist);
1324 }
1325 
1326 
1327 /* This is also in cshpar.c ... */
1328 
1329 static void
1330 pwlist(wlist, name)
1331 
1332 wordlist *wlist;
1333 char *name;
1334 {
1335  wordlist *wl;
1336 
1337  if (!cp_debug)
1338  return;
1339  fprintf(cp_err, "%s : [ ", name);
1340  for (wl = wlist; wl; wl = wl->wl_next)
1341  fprintf(cp_err, "%s ", wl->wl_word);
1342  fprintf(cp_err, "]\n");
1343  return;
1344 }
1345 
1346 
1347 static int indent;
1348 
1349 /* ARGSUSED */
1350 void
1352 
1353 wordlist *wl;
1354 {
1355  struct control *c;
1356 
1357  out_init();
1358  indent = 0;
1359  for (c = control[stackp]; c; c = c->co_next)
1360  dodump(c);
1361  return;
1362 }
1363 
1364 
1365 #define tab(num) for (i = 0; i < num; i++) out_send(" ");
1366 
1367 static void
1369 
1370 struct control *cc;
1371 {
1372  int i;
1373  struct control *tc;
1374 
1375  switch (cc->co_type) {
1376  case CO_UNFILLED:
1377  tab(indent);
1378  out_printf( "(unfilled)\n");
1379  break;
1380  case CO_STATEMENT:
1381  tab(indent);
1382  out_wlprint(cc->co_text);
1383  out_send("\n");
1384  break;
1385  case CO_WHILE:
1386  tab(indent);
1387  out_printf( "while ");
1388  out_wlprint(cc->co_cond);
1389  out_send("\n");
1390  indent += 8;
1391  for (tc = cc->co_children; tc; tc = tc->co_next)
1392  dodump(tc);
1393  indent -= 8;
1394  tab(indent);
1395  out_printf( "end\n");
1396  break;
1397  case CO_REPEAT:
1398  tab(indent);
1399  out_printf( "repeat ");
1400  if (cc->co_numtimes != -1)
1401  out_printf( "%d\n", cc->co_numtimes);
1402  else
1403  out_send("\n");
1404  indent += 8;
1405  for (tc = cc->co_children; tc; tc = tc->co_next)
1406  dodump(tc);
1407  indent -= 8;
1408  tab(indent);
1409  out_printf( "end\n");
1410  break;
1411  case CO_DOWHILE:
1412  tab(indent);
1413  out_printf( "dowhile ");
1414  out_wlprint(cc->co_cond);
1415  out_send("\n");
1416  indent += 8;
1417  for (tc = cc->co_children; tc; tc = tc->co_next)
1418  dodump(tc);
1419  indent -= 8;
1420  tab(indent);
1421  out_printf( "end\n");
1422  break;
1423  case CO_IF:
1424  tab(indent);
1425  out_printf( "if ");
1426  out_wlprint(cc->co_cond);
1427  out_send("\n");
1428  indent += 8;
1429  for (tc = cc->co_children; tc; tc = tc->co_next)
1430  dodump(tc);
1431  indent -= 8;
1432  tab(indent);
1433  out_printf( "end\n");
1434  break;
1435  case CO_FOREACH:
1436  tab(indent);
1437  out_printf( "foreach %s ", cc->co_foreachvar);
1438  out_wlprint(cc->co_text);
1439  out_send("\n");
1440  indent += 8;
1441  for (tc = cc->co_children; tc; tc = tc->co_next)
1442  dodump(tc);
1443  indent -= 8;
1444  tab(indent);
1445  out_printf( "end\n");
1446  break;
1447  case CO_BREAK:
1448  tab(indent);
1449  if (cc->co_numtimes != 1)
1450  out_printf( "break %d\n", cc->co_numtimes);
1451  else
1452  out_printf( "break\n");
1453  break;
1454  case CO_CONTINUE:
1455  tab(indent);
1456  if (cc->co_numtimes != 1)
1457  out_printf( "continue %d\n",
1458  cc->co_numtimes);
1459  else
1460  out_printf( "continue\n");
1461  break;
1462  case CO_LABEL:
1463  tab(indent);
1464  out_printf( "label %s\n", cc->co_text->wl_word);
1465  break;
1466  case CO_GOTO:
1467  tab(indent);
1468  out_printf( "goto %s\n", cc->co_text->wl_word);
1469  break;
1470  default:
1471  tab(indent);
1472  out_printf( "bad type %d\n", cc->co_type);
1473  break;
1474  }
1475  return;
1476 }
1477 
void cp_redirect()
void cp_ioreset()
Definition: cshpar.c:349
static int indent
Definition: front.c:1347
static char buf[MAXPROMPT]
Definition: arg.c:18
void wl_print()
#define eq(a, b)
Definition: misc.h:29
bool cp_cwait
Definition: front.c:120
static struct control * findlabel()
char * label
Definition: front.c:77
Definition: subckt.c:18
void cp_vset()
void out_wlprint()
#define CO_WHILE
Definition: front.c:51
int cp_event
Definition: lexical.c:49
static int stackp
Definition: front.c:70
struct control * bl_cont
Definition: front.c:42
struct control * co_elseblock
Definition: front.c:33
void out_printf()
bool cp_isblockdef(char *name)
Definition: front.c:284
struct control * co_next
Definition: front.c:34
Definition: cddefs.h:119
void htab_delete()
int co_numtimes
Definition: front.c:29
static bool cp_noexec
Definition: front.c:47
void cp_pushcontrol()
Definition: front.c:1066
int num
Definition: front.c:78
void cp_bind()
int co_type
Definition: front.c:26
#define newblock
char * cp_csep
Definition: front.c:121
#define CO_IF
Definition: front.c:53
#define CO_LABEL
Definition: front.c:57
static void * BlockBase
Definition: front.c:45
#define CO_UNFILLED
Definition: front.c:49
double * ft_numparse()
int scannum()
void cp_periodic()
Definition: cpitf.c:318
FILE * cp_curerr
Definition: cshpar.c:77
static void doblock()
int(* co_argfn)()
Definition: cpdefs.h:30
wordlist * cp_parse()
void cp_bquote()
#define tab(num)
Definition: front.c:1365
#define CONTROLSTACKSIZE
Definition: front.c:67
Definition: library.c:18
#define CO_REPEAT
Definition: front.c:59
#define LABEL
Definition: front.c:85
#define CO_BREAK
Definition: front.c:55
void cp_doglob()
struct comm * cp_coms
Definition: main.c:163
Definition: cpdefs.h:20
static struct control * cend[CONTROLSTACKSIZE]
Definition: front.c:69
#define alloc(type)
Definition: cdmacs.h:21
bool cp_block()
void cp_unbind()
int cp_evloop(char *string)
Definition: front.c:316
int co_maxargs
Definition: cpdefs.h:29
char * copy()
#define NORMAL
Definition: front.c:82
void * htab_wl()
void cp_poparg()
Definition: variable.c:1500
bool co_spiceonly
Definition: cpdefs.h:24
FILE * cp_curin
Definition: cshpar.c:75
void wl_free()
#define CONTINUED
Definition: front.c:84
static void dodump()
FILE * cp_err
Definition: help.c:101
void * htab_init()
Definition: hash.c:27
static void eval_block()
struct wordlist * wl_prev
Definition: cpstd.h:24
void cp_pusharg()
#define BROKEN
Definition: front.c:83
bool cp_interactive
Definition: help.c:100
#define tfree(x)
Definition: cdmacs.h:22
Definition: front.c:74
void txfree()
#define NULL
Definition: spdefs.h:121
static char * noredirect[]
Definition: front.c:134
struct control * co_children
Definition: front.c:32
FILE * cp_out
Definition: help.c:101
char * cp_program
Definition: main.c:43
#define CO_STATEMENT
Definition: front.c:50
static double c
Definition: vectors.c:16
static void add_block()
#define VT_STRING
Definition: cpstd.h:63
Definition: front.c:40
Definition: front.c:25
#define CO_DOWHILE
Definition: front.c:52
Definition: cpstd.h:21
void cp_popcontrol()
Definition: front.c:1051
static void docommand()
static struct comm * findcom()
bool cp_oddcomm()
wordlist * co_text
Definition: front.c:30
static wordlist * quicksub()
void cp_freeblock(char *name)
Definition: front.c:296
void cp_variablesubst()
#define CO_CONTINUE
Definition: front.c:56
char * bl_name
Definition: front.c:41
void cp_toplevel()
Definition: front.c:1086
bool cp_istrue()
char * co_foreachvar
Definition: front.c:28
Definition: netlist.c:477
void cp_addblock(char *name, wordlist *wl)
Definition: front.c:264
Definition: cddefs.h:162
void htab_add()
int type
Definition: front.c:75
static void set_block()
void * htab_get()
void out_send()
#define CO_GOTO
Definition: front.c:58
struct wordlist * wl_next
Definition: cpstd.h:23
bool cp_dounixcom
Definition: front.c:123
bool ft_nutmeg
Definition: main.c:161
void cp_striplist()
void cp_execcontrol(char *name)
Definition: front.c:965
char * wl_word
Definition: cpstd.h:22
static wordlist * getcommand()
void cp_resetcontrol()
Definition: front.c:1033
union retinfo::@16 rt
void(* co_func)()
Definition: cpdefs.h:22
char * cp_altprompt
Definition: lexical.c:53
FILE * cp_curout
Definition: cshpar.c:76
#define CT_LABEL
Definition: cpdefs.h:78
bool co_stringargs
Definition: cpdefs.h:23
FILE * cp_in
Definition: help.c:101
void cp_addkword()
struct control * co_parent
Definition: front.c:31
bool cp_unixcom()
struct control * co_prev
Definition: front.c:35
static void freecontrol()
void com_cdump(wordlist *wl)
Definition: front.c:1351
char * co_comname
Definition: cpdefs.h:21
char * wl_flatten()
#define CO_FOREACH
Definition: front.c:54
Definition: cddefs.h:192
wordlist * co_cond
Definition: front.c:27
bool cp_debug
Definition: cshpar.c:61
void com_codeblock(wordlist *wl)
Definition: front.c:137
static void pwlist()
void out_init()
Definition: output.c:128
char * cp_kwswitch()
wordlist * wl_copy()