]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/spin/spinlex.c
merge
[plan9front.git] / sys / src / cmd / spin / spinlex.c
1 /***** spin: spinlex.c *****/
2
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
4 /* All Rights Reserved.  This software is for educational purposes only.  */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code.  Permission is given to distribute this code provided that  */
7 /* this introductory message is not removed and no monies are exchanged.  */
8 /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9 /*             http://spinroot.com/                                       */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11
12 #include <stdlib.h>
13 #include "spin.h"
14 #include "y.tab.h"
15
16 #define MAXINL  16      /* max recursion depth inline fcts */
17 #define MAXPAR  32      /* max params to an inline call */
18 #define MAXLEN  512     /* max len of an actual parameter text */
19
20 typedef struct IType {
21         Symbol *nm;             /* name of the type */
22         Lextok *cn;             /* contents */
23         Lextok *params;         /* formal pars if any */
24         char   **anms;          /* literal text for actual pars */
25         char   *prec;           /* precondition for c_code or c_expr */
26         int    dln, cln;        /* def and call linenr */
27         Symbol *dfn, *cfn;      /* def and call filename */
28         struct IType *nxt;      /* linked list */
29 } IType;
30
31 typedef struct C_Added {
32         Symbol *s;
33         Symbol *t;
34         Symbol *ival;
35         struct C_Added *nxt;
36 } C_Added;
37
38 extern RunList  *X;
39 extern ProcList *rdy;
40 extern Symbol   *Fname;
41 extern Symbol   *context, *owner;
42 extern YYSTYPE  yylval;
43 extern short    has_last, has_code;
44 extern int      verbose, IArgs, hastrack, separate;
45
46 short   has_stack = 0;
47 int     lineno  = 1;
48 char    yytext[2048];
49 FILE    *yyin, *yyout;
50
51 static C_Added  *c_added, *c_tracked;
52 static IType    *Inline_stub[MAXINL];
53 static char     *ReDiRect;
54 static char     *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN];
55 static unsigned char    in_comment=0;
56 static int      IArgno = 0, Inlining = -1;
57 static int      check_name(char *);
58
59 #if 1
60 #define Token(y)        { if (in_comment) goto again; \
61                         yylval = nn(ZN,0,ZN,ZN); return y; }
62
63 #define ValToken(x, y)  { if (in_comment) goto again; \
64                         yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; }
65
66 #define SymToken(x, y)  { if (in_comment) goto again; \
67                         yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; }
68 #else
69 #define Token(y)        { yylval = nn(ZN,0,ZN,ZN); \
70                         if (!in_comment) return y; else goto again; }
71
72 #define ValToken(x, y)  { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \
73                         if (!in_comment) return y; else goto again; }
74
75 #define SymToken(x, y)  { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \
76                         if (!in_comment) return y; else goto again; }
77 #endif
78
79 static int      getinline(void);
80 static void     uninline(void);
81
82 #if 1
83 #define Getchar()       ((Inlining<0)?getc(yyin):getinline())
84 #define Ungetch(c)      {if (Inlining<0) ungetc(c,yyin); else uninline(); }
85
86 #else
87
88 static int
89 Getchar(void)
90 {       int c;
91         if (Inlining<0)
92                 c = getc(yyin);
93         else
94                 c = getinline();
95 #if 1
96         printf("<%c>", c);
97 #endif
98         return c;
99 }
100
101 static void
102 Ungetch(int c)
103 {
104         if (Inlining<0)
105                 ungetc(c,yyin);
106         else
107                 uninline();
108 #if 1
109         printf("<bs>");
110 #endif
111 }
112 #endif
113
114 static int
115 notquote(int c)
116 {       return (c != '\"' && c != '\n');
117 }
118
119 int
120 isalnum_(int c)
121 {       return (isalnum(c) || c == '_');
122 }
123
124 static int
125 isalpha_(int c)
126 {       return isalpha(c);      /* could be macro */
127 }
128        
129 static int
130 isdigit_(int c)
131 {       return isdigit(c);      /* could be macro */
132 }
133
134 static void
135 getword(int first, int (*tst)(int))
136 {       int i=0; char c;
137
138         yytext[i++]= (char) first;
139         while (tst(c = Getchar()))
140         {       yytext[i++] = c;
141                 if (c == '\\')
142                         yytext[i++] = Getchar();        /* no tst */
143         }
144         yytext[i] = '\0';
145         Ungetch(c);
146 }
147
148 static int
149 follow(int tok, int ifyes, int ifno)
150 {       int c;
151
152         if ((c = Getchar()) == tok)
153                 return ifyes;
154         Ungetch(c);
155
156         return ifno;
157 }
158
159 static IType *seqnames;
160
161 static void
162 def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms)
163 {       IType *tmp;
164         char *nw = (char *) emalloc((int) strlen(ptr)+1);
165         strcpy(nw, ptr);
166
167         for (tmp = seqnames; tmp; tmp = tmp->nxt)
168                 if (!strcmp(s->name, tmp->nm->name))
169                 {       non_fatal("procedure name %s redefined",
170                                 tmp->nm->name);
171                         tmp->cn = (Lextok *) nw;
172                         tmp->params = nms;
173                         tmp->dln = ln;
174                         tmp->dfn = Fname;
175                         return;
176                 }
177         tmp = (IType *) emalloc(sizeof(IType));
178         tmp->nm = s;
179         tmp->cn = (Lextok *) nw;
180         tmp->params = nms;
181         if (strlen(prc) > 0)
182         {       tmp->prec = (char *) emalloc((int) strlen(prc)+1);
183                 strcpy(tmp->prec, prc);
184         }
185         tmp->dln = ln;
186         tmp->dfn = Fname;
187         tmp->nxt = seqnames;
188         seqnames = tmp;
189 }
190
191 void
192 gencodetable(FILE *fd)
193 {       IType *tmp;
194         char *q;
195         int cnt;
196
197         if (separate == 2) return;
198
199         fprintf(fd, "struct {\n");
200         fprintf(fd, "   char *c; char *t;\n");
201         fprintf(fd, "} code_lookup[] = {\n");
202
203         if (has_code)
204         for (tmp = seqnames; tmp; tmp = tmp->nxt)
205                 if (tmp->nm->type == CODE_FRAG
206                 ||  tmp->nm->type == CODE_DECL)
207                 {       fprintf(fd, "\t{ \"%s\", ",
208                                 tmp->nm->name);
209                         q = (char *) tmp->cn;
210
211                         while (*q == '\n' || *q == '\r' || *q == '\\')
212                                 q++;
213
214                         fprintf(fd, "\"");
215                         cnt = 0;
216                         while (*q && cnt < 1024) /* pangen1.h allows 2048 */
217                         {       switch (*q) {
218                                 case '"':
219                                         fprintf(fd, "\\\"");
220                                         break;
221                                 case '%':
222                                         fprintf(fd, "%%");
223                                         break;
224                                 case '\n':
225                                         fprintf(fd, "\\n");
226                                         break;
227                                 default:
228                                         putc(*q, fd);
229                                         break;
230                                 }
231                                 q++; cnt++;
232                         }
233                         if (*q) fprintf(fd, "...");
234                         fprintf(fd, "\"");
235                         fprintf(fd, " },\n");
236                 }
237
238         fprintf(fd, "   { (char *) 0, \"\" }\n");
239         fprintf(fd, "};\n");
240 }
241
242 static int
243 iseqname(char *t)
244 {       IType *tmp;
245
246         for (tmp = seqnames; tmp; tmp = tmp->nxt)
247         {       if (!strcmp(t, tmp->nm->name))
248                         return 1;
249         }
250         return 0;
251 }
252
253 static int
254 getinline(void)
255 {       int c;
256
257         if (ReDiRect)
258         {       c = *ReDiRect++;
259                 if (c == '\0')
260                 {       ReDiRect = (char *) 0;
261                         c = *Inliner[Inlining]++;
262                 }
263         } else
264                 c = *Inliner[Inlining]++;
265
266         if (c == '\0')
267         {       lineno = Inline_stub[Inlining]->cln;
268                 Fname  = Inline_stub[Inlining]->cfn;
269                 Inlining--;
270 #if 0
271                 if (verbose&32)
272                 printf("spin: line %d, done inlining %s\n",
273                         lineno, Inline_stub[Inlining+1]->nm->name);
274 #endif
275                 return Getchar();
276         }
277         return c;
278 }
279
280 static void
281 uninline(void)
282 {
283         if (ReDiRect)
284                 ReDiRect--;
285         else
286                 Inliner[Inlining]--;
287 }
288
289 IType *
290 find_inline(char *s)
291 {       IType *tmp;
292
293         for (tmp = seqnames; tmp; tmp = tmp->nxt)
294                 if (!strcmp(s, tmp->nm->name))
295                         break;
296         if (!tmp)
297                 fatal("cannot happen, missing inline def %s", s);
298         return tmp;
299 }
300
301 void
302 c_state(Symbol *s, Symbol *t, Symbol *ival)     /* name, scope, ival */
303 {       C_Added *r;
304
305         r = (C_Added *) emalloc(sizeof(C_Added));
306         r->s = s;       /* pointer to a data object */
307         r->t = t;       /* size of object, or "global", or "local proctype_name"  */
308         r->ival = ival;
309         r->nxt = c_added;
310         c_added = r;
311 }
312
313 void
314 c_track(Symbol *s, Symbol *t, Symbol *stackonly)        /* name, size */
315 {       C_Added *r;
316
317         r = (C_Added *) emalloc(sizeof(C_Added));
318         r->s = s;
319         r->t = t;
320         r->ival = stackonly;    /* abuse of name */
321         r->nxt = c_tracked;
322         c_tracked = r;
323
324         if (stackonly != ZS)
325         {       if (strcmp(stackonly->name, "\"Matched\"") == 0)
326                         r->ival = ZS;   /* the default */
327                 else if (strcmp(stackonly->name, "\"UnMatched\"") != 0
328                      &&  strcmp(stackonly->name, "\"unMatched\"") != 0
329                      &&  strcmp(stackonly->name, "\"StackOnly\"") != 0)
330                         non_fatal("expecting '[Un]Matched', saw %s", stackonly->name);
331                 else
332                         has_stack = 1;
333         }
334 }
335
336 char *
337 jump_etc(char *op)
338 {       char *p = op;
339
340         /* kludgy - try to get the type separated from the name */
341
342         while (*p == ' ' || *p == '\t')
343                 p++;    /* initial white space */
344         while (*p != ' ' && *p != '\t')
345                 p++;    /* type name */
346         while (*p == ' ' || *p == '\t')
347                 p++;    /* white space */
348         while (*p == '*')
349                 p++;    /* decorations */
350         while (*p == ' ' || *p == '\t')
351                 p++;    /* white space */
352
353         if (*p == '\0')
354                 fatal("c_state format (%s)", op);
355
356         if (strchr(p, '[')
357         &&  !strchr(p, '{'))
358         {       non_fatal("array initialization error, c_state (%s)", p);
359                 return (char *) 0;
360         }
361
362         return p;
363 }
364
365 void
366 c_add_globinit(FILE *fd)
367 {       C_Added *r;
368         char *p, *q;
369
370         fprintf(fd, "void\nglobinit(void)\n{\n");
371         for (r = c_added; r; r = r->nxt)
372         {       if (r->ival == ZS)
373                         continue;
374
375                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
376                 {       for (q = r->ival->name; *q; q++)
377                         {       if (*q == '\"')
378                                         *q = ' ';
379                                 if (*q == '\\')
380                                         *q++ = ' '; /* skip over the next */
381                         }
382                         p = jump_etc(r->s->name);       /* e.g., "int **q" */
383                         if (p)
384                         fprintf(fd, "   now.%s = %s;\n", p, r->ival->name);
385
386                 } else
387                 if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0)
388                 {       for (q = r->ival->name; *q; q++)
389                         {       if (*q == '\"')
390                                         *q = ' ';
391                                 if (*q == '\\')
392                                         *q++ = ' '; /* skip over the next */
393                         }
394                         p = jump_etc(r->s->name);       /* e.g., "int **q" */
395                         if (p)
396                         fprintf(fd, "   %s = %s;\n", p, r->ival->name); /* no now. prefix */
397
398         }       }
399         fprintf(fd, "}\n");
400 }
401
402 void
403 c_add_locinit(FILE *fd, int tpnr, char *pnm)
404 {       C_Added *r;
405         char *p, *q, *s;
406         int frst = 1;
407
408         fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr);
409         for (r = c_added; r; r = r->nxt)
410                 if (r->ival != ZS
411                 &&  strncmp(r->t->name, " Local", strlen(" Local")) == 0)
412                 {       for (q = r->ival->name; *q; q++)
413                                 if (*q == '\"')
414                                         *q = ' ';
415                         
416                         p = jump_etc(r->s->name);       /* e.g., "int **q" */
417
418                         q = r->t->name + strlen(" Local");
419                         while (*q == ' ' || *q == '\t')
420                                 q++;                    /* process name */
421
422                         s = (char *) emalloc(strlen(q)+1);
423                         strcpy(s, q);
424
425                         q = &s[strlen(s)-1];
426                         while (*q == ' ' || *q == '\t')
427                                 *q-- = '\0';
428
429                         if (strcmp(pnm, s) != 0)
430                                 continue;
431
432                         if (frst)
433                         {       fprintf(fd, "\tuchar *this = pptr(h);\n");
434                                 frst = 0;
435                         }
436
437                         if (p)
438                         fprintf(fd, "           ((P%d *)this)->%s = %s;\n",
439                                 tpnr, p, r->ival->name);
440
441                 }
442         fprintf(fd, "}\n");
443 }
444
445 /* tracking:
446         1. for non-global and non-local c_state decls: add up all the sizes in c_added
447         2. add a global char array of that size into now
448         3. generate a routine that memcpy's the required values into that array
449         4. generate a call to that routine
450  */
451
452 void
453 c_preview(void)
454 {       C_Added *r;
455
456         hastrack = 0;
457         if (c_tracked)
458                 hastrack = 1;
459         else
460         for (r = c_added; r; r = r->nxt)
461                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
462                 &&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
463                 &&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
464                 {       hastrack = 1;   /* c_state variant now obsolete */
465                         break;
466                 }
467 }
468
469 int
470 c_add_sv(FILE *fd)      /* 1+2 -- called in pangen1.c */
471 {       C_Added *r;
472         int cnt = 0;
473
474         if (!c_added && !c_tracked) return 0;
475
476         for (r = c_added; r; r = r->nxt)        /* pickup global decls */
477                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
478                         fprintf(fd, "   %s;\n", r->s->name);
479
480         for (r = c_added; r; r = r->nxt)
481                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
482                 &&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
483                 &&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
484                 {       cnt++;  /* obsolete use */
485                 }
486
487         for (r = c_tracked; r; r = r->nxt)
488                 cnt++;          /* preferred use */
489
490         if (cnt == 0) return 0;
491
492         cnt = 0;
493         fprintf(fd, "   uchar c_state[");
494         for (r = c_added; r; r = r->nxt)
495                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
496                 &&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
497                 &&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
498                 {       fprintf(fd, "%ssizeof(%s)",
499                                 (cnt==0)?"":"+", r->t->name);
500                         cnt++;
501                 }
502
503         for (r = c_tracked; r; r = r->nxt)
504         {       if (r->ival != ZS) continue;
505
506                 fprintf(fd, "%s%s",
507                         (cnt==0)?"":"+", r->t->name);
508                 cnt++;
509         }
510
511         if (cnt == 0) fprintf(fd, "4"); /* now redundant */
512         fprintf(fd, "];\n");
513         return 1;
514 }
515
516 void
517 c_add_stack(FILE *fd)
518 {       C_Added *r;
519         int cnt = 0;
520
521         if ((!c_added && !c_tracked) || !has_stack) return;
522
523
524         for (r = c_tracked; r; r = r->nxt)
525                 if (r->ival != ZS)
526                         cnt++;
527
528         if (cnt == 0) return;
529
530         fprintf(fd, "   uchar c_stack[");
531
532         cnt = 0;
533         for (r = c_tracked; r; r = r->nxt)
534         {       if (r->ival == ZS) continue;
535
536                 fprintf(fd, "%s%s",
537                         (cnt==0)?"":"+", r->t->name);
538                 cnt++;
539         }
540
541         if (cnt == 0) fprintf(fd, "WS"); /* can't happen */
542         fprintf(fd, "];\n");
543 }
544
545 void
546 c_add_hidden(FILE *fd)
547 {       C_Added *r;
548
549         for (r = c_added; r; r = r->nxt)        /* pickup hidden decls */
550                 if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0)
551                 {       r->s->name[strlen(r->s->name)-1] = ' ';
552                         fprintf(fd, "%s;        /* Hidden */\n", &r->s->name[1]);
553                         r->s->name[strlen(r->s->name)-1] = '"';
554                 }
555         /* called before c_add_def - quotes are still there */
556 }
557
558 void
559 c_add_loc(FILE *fd, char *s)    /* state vector entries for proctype s */
560 {       C_Added *r;
561         static char buf[1024];
562         char *p;
563
564         if (!c_added) return;
565
566         strcpy(buf, s);
567         strcat(buf, " ");
568         for (r = c_added; r; r = r->nxt)        /* pickup local decls */
569                 if (strncmp(r->t->name, " Local", strlen(" Local")) == 0)
570                 {       p = r->t->name + strlen(" Local");
571                         while (*p == ' ' || *p == '\t')
572                                 p++;
573                         if (strcmp(p, buf) == 0)
574                                 fprintf(fd, "   %s;\n", r->s->name);
575                 }
576 }
577 void
578 c_add_def(FILE *fd)     /* 3 - called in plunk_c_fcts() */
579 {       C_Added *r;
580
581         fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n");
582         for (r = c_added; r; r = r->nxt)
583         {       r->s->name[strlen(r->s->name)-1] = ' ';
584                 r->s->name[0] = ' '; /* remove the "s */
585
586                 r->t->name[strlen(r->t->name)-1] = ' ';
587                 r->t->name[0] = ' ';
588
589                 if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
590                 ||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
591                 ||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
592                         continue;
593
594                 if (strchr(r->s->name, '&'))
595                         fatal("dereferencing state object: %s", r->s->name);
596
597                 fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name);
598         }
599         for (r = c_tracked; r; r = r->nxt)
600         {       r->s->name[strlen(r->s->name)-1] = ' ';
601                 r->s->name[0] = ' '; /* remove " */
602
603                 r->t->name[strlen(r->t->name)-1] = ' ';
604                 r->t->name[0] = ' ';
605         }
606
607         if (separate == 2)
608         {       fprintf(fd, "#endif\n");
609                 return;
610         }
611
612         if (has_stack)
613         {       fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n");
614                 fprintf(fd, "#ifdef VERBOSE\n");
615                 fprintf(fd, "   printf(\"c_stack %%u\\n\", p_t_r);\n");
616                 fprintf(fd, "#endif\n");
617                 for (r = c_tracked; r; r = r->nxt)
618                 {       if (r->ival == ZS) continue;
619         
620                         fprintf(fd, "\tif(%s)\n", r->s->name);
621                         fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
622                                 r->s->name, r->t->name);
623                         fprintf(fd, "\telse\n");
624                         fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
625                                 r->t->name);
626                         fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
627                 }
628                 fprintf(fd, "}\n\n");
629         }
630
631         fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n");
632         fprintf(fd, "#ifdef VERBOSE\n");
633         fprintf(fd, "   printf(\"c_update %%u\\n\", p_t_r);\n");
634         fprintf(fd, "#endif\n");
635         for (r = c_added; r; r = r->nxt)
636         {       if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
637                 ||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
638                 ||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
639                         continue;
640
641                 fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n",
642                         r->s->name, r->t->name);
643                 fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
644         }
645
646         for (r = c_tracked; r; r = r->nxt)
647         {       if (r->ival) continue;
648
649                 fprintf(fd, "\tif(%s)\n", r->s->name);
650                 fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
651                         r->s->name, r->t->name);
652                 fprintf(fd, "\telse\n");
653                 fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
654                         r->t->name);
655                 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
656         }
657
658         fprintf(fd, "}\n");
659
660         if (has_stack)
661         {       fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n");
662                 fprintf(fd, "#ifdef VERBOSE\n");
663                 fprintf(fd, "   printf(\"c_unstack %%u\\n\", p_t_r);\n");
664                 fprintf(fd, "#endif\n");
665                 for (r = c_tracked; r; r = r->nxt)
666                 {       if (r->ival == ZS) continue;
667
668                         fprintf(fd, "\tif(%s)\n", r->s->name);
669                         fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
670                                 r->s->name, r->t->name);
671                         fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
672                 }
673                 fprintf(fd, "}\n");
674         }
675
676         fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n");
677         fprintf(fd, "#ifdef VERBOSE\n");
678         fprintf(fd, "   printf(\"c_revert %%u\\n\", p_t_r);\n");
679         fprintf(fd, "#endif\n");
680         for (r = c_added; r; r = r->nxt)
681         {       if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
682                 ||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
683                 ||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
684                         continue;
685
686                 fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n",
687                         r->s->name, r->t->name);
688                 fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
689         }
690         for (r = c_tracked; r; r = r->nxt)
691         {       if (r->ival != ZS) continue;
692
693                 fprintf(fd, "\tif(%s)\n", r->s->name);
694                 fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
695                         r->s->name, r->t->name);
696                 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
697         }
698
699         fprintf(fd, "}\n");
700         fprintf(fd, "#endif\n");
701 }
702
703 void
704 plunk_reverse(FILE *fd, IType *p, int matchthis)
705 {       char *y, *z;
706
707         if (!p) return;
708         plunk_reverse(fd, p->nxt, matchthis);
709
710         if (!p->nm->context
711         &&   p->nm->type == matchthis)
712         {       fprintf(fd, "\n/* start of %s */\n", p->nm->name);
713                 z = (char *) p->cn;
714                 while (*z == '\n' || *z == '\r' || *z == '\\')
715                         z++;
716                 /* e.g.: \#include "..." */
717
718                 y = z;
719                 while ((y = strstr(y, "\\#")) != NULL)
720                 {       *y = '\n'; y++;
721                 }
722
723                 fprintf(fd, "%s\n", z);
724                 fprintf(fd, "\n/* end of %s */\n", p->nm->name);
725         }
726 }
727
728 void
729 plunk_c_decls(FILE *fd)
730 {
731         plunk_reverse(fd, seqnames, CODE_DECL);
732 }
733
734 void
735 plunk_c_fcts(FILE *fd)
736 {
737         if (separate == 2 && hastrack)
738         {       c_add_def(fd);
739                 return;
740         }
741
742         c_add_hidden(fd);
743         plunk_reverse(fd, seqnames, CODE_FRAG);
744
745         if (c_added || c_tracked)       /* enables calls to c_revert and c_update */
746                 fprintf(fd, "#define C_States   1\n");
747         else
748                 fprintf(fd, "#undef C_States\n");
749
750         if (hastrack)
751                 c_add_def(fd);
752
753         c_add_globinit(fd);
754         do_locinits(fd);
755 }
756
757 static void
758 check_inline(IType *tmp)
759 {       char buf[128];
760         ProcList *p;
761
762         if (!X) return;
763
764         for (p = rdy; p; p = p->nxt)
765         {       if (strcmp(p->n->name, X->n->name) == 0)
766                         continue;
767                 sprintf(buf, "P%s->", p->n->name);
768                 if (strstr((char *)tmp->cn, buf))
769                 {       printf("spin: in proctype %s, ref to object in proctype %s\n",
770                                 X->n->name, p->n->name);
771                         fatal("invalid variable ref in '%s'", tmp->nm->name);
772         }       }
773 }
774
775 void
776 plunk_expr(FILE *fd, char *s)
777 {       IType *tmp;
778
779         tmp = find_inline(s);
780         check_inline(tmp);
781
782         fprintf(fd, "%s", (char *) tmp->cn);
783 }
784
785 void
786 preruse(FILE *fd, Lextok *n)    /* check a condition for c_expr with preconditions */
787 {       IType *tmp;
788
789         if (!n) return;
790         if (n->ntyp == C_EXPR)
791         {       tmp = find_inline(n->sym->name);
792                 if (tmp->prec)
793                 {       fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
794                         fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
795                         fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
796                         fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
797                         fprintf(fd, "_m = 3; goto P999; } } \n\t\t");
798                 }
799         } else
800         {       preruse(fd, n->rgt);
801                 preruse(fd, n->lft);
802         }
803 }
804
805 int
806 glob_inline(char *s)
807 {       IType *tmp;
808         char *bdy;
809
810         tmp = find_inline(s);
811         bdy = (char *) tmp->cn;
812         return (strstr(bdy, "now.")             /* global ref or   */
813         ||      strchr(bdy, '(') > bdy);        /* possible C-function call */
814 }
815
816 void
817 plunk_inline(FILE *fd, char *s, int how)        /* c_code with precondition */
818 {       IType *tmp;
819
820         tmp = find_inline(s);
821         check_inline(tmp);
822
823         fprintf(fd, "{ ");
824         if (how && tmp->prec)
825         {       fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
826                 fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
827                 fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
828                 fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
829                 fprintf(fd, "_m = 3; goto P999; } } ");
830         }
831         fprintf(fd, "%s", (char *) tmp->cn);
832         fprintf(fd, " }\n");
833 }
834
835 void
836 no_side_effects(char *s)
837 {       IType *tmp;
838         char *t;
839
840         /* could still defeat this check via hidden
841          * side effects in function calls,
842          * but this will catch at least some cases
843          */
844
845         tmp = find_inline(s);
846         t = (char *) tmp->cn;
847
848         if (strchr(t, ';')
849         ||  strstr(t, "++")
850         ||  strstr(t, "--"))
851         {
852 bad:            lineno = tmp->dln;
853                 Fname = tmp->dfn;
854                 non_fatal("c_expr %s has side-effects", s);
855                 return;
856         }
857         while ((t = strchr(t, '=')) != NULL)
858         {       if (*(t-1) == '!'
859                 ||  *(t-1) == '>'
860                 ||  *(t-1) == '<')
861                 {       t++;
862                         continue;
863                 }
864                 t++;
865                 if (*t != '=')
866                         goto bad;
867                 t++;
868         }
869 }
870
871 void
872 pickup_inline(Symbol *t, Lextok *apars)
873 {       IType *tmp; Lextok *p, *q; int j;
874
875         tmp = find_inline(t->name);
876
877         if (++Inlining >= MAXINL)
878                 fatal("inline fcts too deeply nested", 0);
879
880         tmp->cln = lineno;      /* remember calling point */
881         tmp->cfn = Fname;       /* and filename */
882
883         for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
884                 j++; /* count them */
885         if (p || q)
886                 fatal("wrong nr of params on call of '%s'", t->name);
887
888         tmp->anms  = (char **) emalloc(j * sizeof(char *));
889         for (p = apars, j = 0; p; p = p->rgt, j++)
890         {       tmp->anms[j] = (char *) emalloc((int) strlen(IArg_cont[j])+1);
891                 strcpy(tmp->anms[j], IArg_cont[j]);
892         }
893
894         lineno = tmp->dln;      /* linenr of def */
895         Fname = tmp->dfn;       /* filename of same */
896         Inliner[Inlining] = (char *)tmp->cn;
897         Inline_stub[Inlining] = tmp;
898 #if 0
899         if (verbose&32)
900         printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n",
901                 tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name);
902 #endif
903         for (j = 0; j < Inlining; j++)
904                 if (Inline_stub[j] == Inline_stub[Inlining])
905                 fatal("cyclic inline attempt on: %s", t->name);
906 }
907
908 static void
909 do_directive(int first)
910 {       int c = first;  /* handles lines starting with pound */
911
912         getword(c, isalpha_);
913
914         if (strcmp(yytext, "#ident") == 0)
915                 goto done;
916
917         if ((c = Getchar()) != ' ')
918                 fatal("malformed preprocessor directive - # .", 0);
919
920         if (!isdigit_(c = Getchar()))
921                 fatal("malformed preprocessor directive - # .lineno", 0);
922
923         getword(c, isdigit_);
924         lineno = atoi(yytext);  /* pickup the line number */
925
926         if ((c = Getchar()) == '\n')
927                 return; /* no filename */
928
929         if (c != ' ')
930                 fatal("malformed preprocessor directive - .fname", 0);
931
932         if ((c = Getchar()) != '\"')
933                 fatal("malformed preprocessor directive - .fname", 0);
934
935         getword(c, notquote);
936         if (Getchar() != '\"')
937                 fatal("malformed preprocessor directive - fname.", 0);
938
939         strcat(yytext, "\"");
940         Fname = lookup(yytext);
941 done:
942         while (Getchar() != '\n')
943                 ;
944 }
945
946 void
947 precondition(char *q)
948 {       int c, nest = 1;
949
950         for (;;)
951         {       c = Getchar();
952                 *q++ = c;
953                 switch (c) {
954                 case '\n':
955                         lineno++;
956                         break;
957                 case '[':
958                         nest++;
959                         break;
960                 case ']':
961                         if (--nest <= 0)
962                         {       *--q = '\0';
963                                 return;
964                         }
965                         break;
966                 }
967         }
968         fatal("cannot happen", (char *) 0);                     
969 }
970
971 Symbol *
972 prep_inline(Symbol *s, Lextok *nms)
973 {       int c, nest = 1, dln, firstchar, cnr;
974         char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL];
975         Lextok *t;
976         static int c_code = 1;
977
978         for (t = nms; t; t = t->rgt)
979                 if (t->lft)
980                 {       if (t->lft->ntyp != NAME)
981                         fatal("bad param to inline %s", s->name);
982                         t->lft->sym->hidden |= 32;
983                 }
984
985         if (!s) /* C_Code fragment */
986         {       s = (Symbol *) emalloc(sizeof(Symbol));
987                 s->name = (char *) emalloc((int) strlen("c_code")+26);
988                 sprintf(s->name, "c_code%d", c_code++);
989                 s->context = context;
990                 s->type = CODE_FRAG;
991         } else
992                 s->type = PREDEF;
993
994         p = &buf[0];
995         buf2[0] = '\0';
996         for (;;)
997         {       c = Getchar();
998                 switch (c) {
999                 case '[':
1000                         if (s->type != CODE_FRAG)
1001                                 goto bad;
1002                         precondition(&buf2[0]); /* e.g., c_code [p] { r = p-r; } */
1003                         continue;
1004                 case '{':
1005                         break;
1006                 case '\n':
1007                         lineno++;
1008                         /* fall through */
1009                 case ' ': case '\t': case '\f': case '\r':
1010                         continue;
1011                 default :
1012                          printf("spin: saw char '%c'\n", c);
1013 bad:                     fatal("bad inline: %s", s->name);
1014                 }
1015                 break;
1016         }
1017         dln = lineno;
1018         if (s->type == CODE_FRAG)
1019         {       if (verbose&32)
1020                         sprintf(buf, "\t/* line %d %s */\n\t\t",
1021                                 lineno, Fname->name);
1022                 else
1023                         strcpy(buf, "");
1024         } else
1025                 sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name);
1026         p += strlen(buf);
1027         firstchar = 1;
1028
1029         cnr = 1; /* not zero */
1030 more:
1031         *p++ = c = Getchar();
1032         if (p - buf >= SOMETHINGBIG)
1033                 fatal("inline text too long", 0);
1034         switch (c) {
1035         case '\n':
1036                 lineno++;
1037                 cnr = 0;
1038                 break;
1039         case '{':
1040                 cnr++;
1041                 nest++;
1042                 break;
1043         case '}':
1044                 cnr++;
1045                 if (--nest <= 0)
1046                 {       *p = '\0';
1047                         if (s->type == CODE_FRAG)
1048                                 *--p = '\0';    /* remove trailing '}' */       
1049                         def_inline(s, dln, &buf[0], &buf2[0], nms);
1050                         if (firstchar && s)
1051                                 printf("%3d: %s, warning: empty inline definition (%s)\n",
1052                                         dln, Fname->name, s->name);
1053                         return s;       /* normal return */
1054                 }
1055                 break;
1056         case '#':
1057                 if (cnr == 0)
1058                 {       p--;
1059                         do_directive(c); /* reads to newline */
1060                         break;
1061                 } /* else fall through */
1062         default:
1063                 firstchar = 0;
1064         case '\t':
1065         case ' ':
1066         case '\f':
1067                 cnr++;
1068                 break;
1069         }
1070         goto more;
1071 }
1072
1073 static int
1074 lex(void)
1075 {       int c;
1076
1077 again:
1078         c = Getchar();
1079         yytext[0] = (char) c;
1080         yytext[1] = '\0';
1081         switch (c) {
1082         case '\n':              /* newline */
1083                 lineno++;
1084         case '\r':              /* carriage return */
1085                 goto again;
1086
1087         case  ' ': case '\t': case '\f':        /* white space */
1088                 goto again;
1089
1090         case '#':               /* preprocessor directive */
1091                 if (in_comment) goto again;
1092                 do_directive(c);
1093                 goto again;
1094
1095         case '\"':
1096                 getword(c, notquote);
1097                 if (Getchar() != '\"')
1098                         fatal("string not terminated", yytext);
1099                 strcat(yytext, "\"");
1100                 SymToken(lookup(yytext), STRING)
1101
1102         case '\'':      /* new 3.0.9 */
1103                 c = Getchar();
1104                 if (c == '\\')
1105                 {       c = Getchar();
1106                         if (c == 'n') c = '\n';
1107                         else if (c == 'r') c = '\r';
1108                         else if (c == 't') c = '\t';
1109                         else if (c == 'f') c = '\f';
1110                 }
1111                 if (Getchar() != '\'' && !in_comment)
1112                         fatal("character quote missing: %s", yytext);
1113                 ValToken(c, CONST)
1114
1115         default:
1116                 break;
1117         }
1118
1119         if (isdigit_(c))
1120         {       getword(c, isdigit_);
1121                 ValToken(atoi(yytext), CONST)
1122         }
1123
1124         if (isalpha_(c) || c == '_')
1125         {       getword(c, isalnum_);
1126                 if (!in_comment)
1127                 {       c = check_name(yytext);
1128                         if (c) return c;
1129                         /* else fall through */
1130                 }
1131                 goto again;
1132         }
1133
1134         switch (c) {
1135         case '/': c = follow('*', 0, '/');
1136                   if (!c) { in_comment = 1; goto again; }
1137                   break;
1138         case '*': c = follow('/', 0, '*');
1139                   if (!c) { in_comment = 0; goto again; }
1140                   break;
1141         case ':': c = follow(':', SEP, ':'); break;
1142         case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break;
1143         case '+': c = follow('+', INCR, '+'); break;
1144         case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
1145         case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
1146         case '=': c = follow('=', EQ, ASGN); break;
1147         case '!': c = follow('=', NE, follow('!', O_SND, SND)); break;
1148         case '?': c = follow('?', R_RCV, RCV); break;
1149         case '&': c = follow('&', AND, '&'); break;
1150         case '|': c = follow('|', OR, '|'); break;
1151         case ';': c = SEMI; break;
1152         default : break;
1153         }
1154         Token(c)
1155 }
1156
1157 static struct {
1158         char *s;        int tok;        int val;        char *sym;
1159 } Names[] = {
1160         {"active",      ACTIVE,         0,              0},
1161         {"assert",      ASSERT,         0,              0},
1162         {"atomic",      ATOMIC,         0,              0},
1163         {"bit",         TYPE,           BIT,            0},
1164         {"bool",        TYPE,           BIT,            0},
1165         {"break",       BREAK,          0,              0},
1166         {"byte",        TYPE,           BYTE,           0},
1167         {"c_code",      C_CODE,         0,              0},
1168         {"c_decl",      C_DECL,         0,              0},
1169         {"c_expr",      C_EXPR,         0,              0},
1170         {"c_state",     C_STATE,        0,              0},
1171         {"c_track",     C_TRACK,        0,              0},
1172         {"D_proctype",  D_PROCTYPE,     0,              0},
1173         {"do",          DO,             0,              0},
1174         {"chan",        TYPE,           CHAN,           0},
1175         {"else",        ELSE,           0,              0},
1176         {"empty",       EMPTY,          0,              0},
1177         {"enabled",     ENABLED,        0,              0},
1178         {"eval",        EVAL,           0,              0},
1179         {"false",       CONST,          0,              0},
1180         {"fi",          FI,             0,              0},
1181         {"full",        FULL,           0,              0},
1182         {"goto",        GOTO,           0,              0},
1183         {"hidden",      HIDDEN,         0,              ":hide:"},
1184         {"if",          IF,             0,              0},
1185         {"init",        INIT,           0,              ":init:"},
1186         {"int",         TYPE,           INT,            0},
1187         {"len",         LEN,            0,              0},
1188         {"local",       ISLOCAL,        0,              ":local:"},
1189         {"mtype",       TYPE,           MTYPE,          0},
1190         {"nempty",      NEMPTY,         0,              0},
1191         {"never",       CLAIM,          0,              ":never:"},
1192         {"nfull",       NFULL,          0,              0},
1193         {"notrace",     TRACE,          0,              ":notrace:"},
1194         {"np_",         NONPROGRESS,    0,              0},
1195         {"od",          OD,             0,              0},
1196         {"of",          OF,             0,              0},
1197         {"pc_value",    PC_VAL,         0,              0},
1198         {"pid",         TYPE,           BYTE,           0},
1199         {"printf",      PRINT,          0,              0},
1200         {"printm",      PRINTM,         0,              0},
1201         {"priority",    PRIORITY,       0,              0},
1202         {"proctype",    PROCTYPE,       0,              0},
1203         {"provided",    PROVIDED,       0,              0},
1204         {"run",         RUN,            0,              0},
1205         {"d_step",      D_STEP,         0,              0},
1206         {"inline",      INLINE,         0,              0},
1207         {"short",       TYPE,           SHORT,          0},
1208         {"skip",        CONST,          1,              0},
1209         {"timeout",     TIMEOUT,        0,              0},
1210         {"trace",       TRACE,          0,              ":trace:"},
1211         {"true",        CONST,          1,              0},
1212         {"show",        SHOW,           0,              ":show:"},
1213         {"typedef",     TYPEDEF,        0,              0},
1214         {"unless",      UNLESS,         0,              0},
1215         {"unsigned",    TYPE,           UNSIGNED,       0},
1216         {"xr",          XU,             XR,             0},
1217         {"xs",          XU,             XS,             0},
1218         {0,             0,              0,              0},
1219 };
1220
1221 static int
1222 check_name(char *s)
1223 {       int i;
1224
1225         yylval = nn(ZN, 0, ZN, ZN);
1226         for (i = 0; Names[i].s; i++)
1227                 if (strcmp(s, Names[i].s) == 0)
1228                 {       yylval->val = Names[i].val;
1229                         if (Names[i].sym)
1230                                 yylval->sym = lookup(Names[i].sym);
1231                         return Names[i].tok;
1232                 }
1233
1234         if ((yylval->val = ismtype(s)) != 0)
1235         {       yylval->ismtyp = 1;
1236                 return CONST;
1237         }
1238
1239         if (strcmp(s, "_last") == 0)
1240                 has_last++;
1241
1242         if (Inlining >= 0 && !ReDiRect)
1243         {       Lextok *tt, *t = Inline_stub[Inlining]->params;
1244
1245                 for (i = 0; t; t = t->rgt, i++)                         /* formal pars */
1246                  if (!strcmp(s, t->lft->sym->name)                      /* varname matches formal */
1247                  &&   strcmp(s, Inline_stub[Inlining]->anms[i]) != 0)   /* actual pars */
1248                  {
1249 #if 0
1250                         if (verbose&32)
1251                         printf("\tline %d, replace %s in call of '%s' with %s\n",
1252                                 lineno, s,
1253                                 Inline_stub[Inlining]->nm->name,
1254                                 Inline_stub[Inlining]->anms[i]);
1255 #endif
1256                         
1257                         for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt)
1258                                 if (!strcmp(Inline_stub[Inlining]->anms[i],
1259                                         tt->lft->sym->name))
1260                                 {       /* would be cyclic if not caught */
1261                                         printf("spin: line %d replacement value: %s\n",
1262                                                 lineno, tt->lft->sym->name);
1263                                         fatal("formal par of %s matches replacement value",
1264                                                 Inline_stub[Inlining]->nm->name);
1265                                         yylval->ntyp = tt->lft->ntyp;
1266                                         yylval->sym = lookup(tt->lft->sym->name);
1267                                         return NAME;
1268                                 }
1269                         ReDiRect = Inline_stub[Inlining]->anms[i];
1270                         return 0;
1271         }        }
1272
1273         yylval->sym = lookup(s);        /* symbol table */
1274         if (isutype(s))
1275                 return UNAME;
1276         if (isproctype(s))
1277                 return PNAME;
1278         if (iseqname(s))
1279                 return INAME;
1280
1281         return NAME;
1282 }
1283
1284 int
1285 yylex(void)
1286 {       static int last = 0;
1287         static int hold = 0;
1288         int c;
1289         /*
1290          * repair two common syntax mistakes with
1291          * semi-colons before or after a '}'
1292          */
1293         if (hold)
1294         {       c = hold;
1295                 hold = 0;
1296         } else
1297         {       c = lex();
1298                 if (last == ELSE
1299                 &&  c != SEMI
1300                 &&  c != FI)
1301                 {       hold = c;
1302                         last = 0;
1303                         return SEMI;
1304                 }
1305                 if (last == '}'
1306                 &&  c != PROCTYPE
1307                 &&  c != INIT
1308                 &&  c != CLAIM
1309                 &&  c != SEP
1310                 &&  c != FI
1311                 &&  c != OD
1312                 &&  c != '}'
1313                 &&  c != UNLESS
1314                 &&  c != SEMI
1315                 &&  c != EOF)
1316                 {       hold = c;
1317                         last = 0;
1318                         return SEMI;    /* insert ';' */
1319                 }
1320                 if (c == SEMI)
1321                 {       /* if context, we're not in a typedef
1322                          * because they're global.
1323                          * if owner, we're at the end of a ref
1324                          * to a struct field -- prevent that the
1325                          * lookahead is interpreted as a field of
1326                          * the same struct...
1327                          */
1328                         if (context) owner = ZS;
1329                         hold = lex();   /* look ahead */
1330                         if (hold == '}'
1331                         ||  hold == SEMI)
1332                         {       c = hold; /* omit ';' */
1333                                 hold = 0;
1334                         }
1335                 }
1336         }
1337         last = c;
1338
1339         if (IArgs)
1340         {       static int IArg_nst = 0;
1341
1342                 if (strcmp(yytext, ",") == 0)
1343                 {       IArg_cont[++IArgno][0] = '\0';
1344                 } else if (strcmp(yytext, "(") == 0)
1345                 {       if (IArg_nst++ == 0)
1346                         {       IArgno = 0;
1347                                 IArg_cont[0][0] = '\0';
1348                         } else
1349                                 strcat(IArg_cont[IArgno], yytext);
1350                 } else if (strcmp(yytext, ")") == 0)
1351                 {       if (--IArg_nst > 0)
1352                                 strcat(IArg_cont[IArgno], yytext);
1353                 } else if (c == CONST && yytext[0] == '\'')
1354                 {       sprintf(yytext, "'%c'", yylval->val);
1355                         strcat(IArg_cont[IArgno], yytext);
1356                 } else
1357                 {
1358                         switch (c) {
1359                         case SEP:       strcpy(yytext, "::"); break;
1360                         case SEMI:      strcpy(yytext, ";"); break;
1361                         case DECR:      strcpy(yytext, "--"); break;
1362                         case INCR:      strcpy(yytext, "++"); break;
1363                         case LSHIFT:    strcpy(yytext, "<<"); break;
1364                         case RSHIFT:    strcpy(yytext, ">>"); break;
1365                         case LE:        strcpy(yytext, "<="); break;
1366                         case LT:        strcpy(yytext, "<"); break;
1367                         case GE:        strcpy(yytext, ">="); break;
1368                         case GT:        strcpy(yytext, ">"); break;
1369                         case EQ:        strcpy(yytext, "=="); break;
1370                         case ASGN:      strcpy(yytext, "="); break;
1371                         case NE:        strcpy(yytext, "!="); break;
1372                         case R_RCV:     strcpy(yytext, "??"); break;
1373                         case RCV:       strcpy(yytext, "?"); break;
1374                         case O_SND:     strcpy(yytext, "!!"); break;
1375                         case SND:       strcpy(yytext, "!"); break;
1376                         case AND:       strcpy(yytext, "&&"); break;
1377                         case OR:        strcpy(yytext, "||"); break;
1378                         }
1379                         strcat(IArg_cont[IArgno], yytext);
1380                 }
1381         }
1382
1383         return c;
1384 }