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