xref: /original-bsd/old/yacc/y2.c (revision 50dd0bba)
1 #ifndef lint
2 static char sccsid[] = "@(#)y2.c	4.1	(Berkeley)	02/11/83";
3 #endif not lint
4 
5 # include "dextern"
6 # define IDENTIFIER 257
7 # define MARK 258
8 # define TERM 259
9 # define LEFT 260
10 # define RIGHT 261
11 # define BINARY 262
12 # define PREC 263
13 # define LCURLY 264
14 # define C_IDENTIFIER 265  /* name followed by colon */
15 # define NUMBER 266
16 # define START 267
17 # define TYPEDEF 268
18 # define TYPENAME 269
19 # define UNION 270
20 # define ENDFILE 0
21 
22 	/* communication variables between various I/O routines */
23 
24 char *infile;	/* input file name */
25 int numbval;	/* value of an input number */
26 char tokname[NAMESIZE];	/* input token name */
27 
28 	/* storage of names */
29 
30 char cnames[CNAMSZ];	/* place where token and nonterminal names are stored */
31 int cnamsz = CNAMSZ;	/* size of cnames */
32 char * cnamp = cnames;	/* place where next name is to be put in */
33 int ndefout = 3;  /* number of defined symbols output */
34 
35 	/* storage of types */
36 int ntypes;	/* number of types defined */
37 char * typeset[NTYPES];	/* pointers to type tags */
38 
39 	/* symbol tables for tokens and nonterminals */
40 
41 int ntokens = 0;
42 struct toksymb tokset[NTERMS];
43 int toklev[NTERMS];
44 int nnonter = -1;
45 struct ntsymb nontrst[NNONTERM];
46 int start;	/* start symbol */
47 
48 	/* assigned token type values */
49 int extval = 0;
50 
51 	/* input and output file descriptors */
52 
53 FILE * finput;		/* yacc input file */
54 FILE * faction;		/* file for saving actions */
55 FILE * fdefine;		/* file for # defines */
56 FILE * ftable;		/* y.tab.c file */
57 FILE * ftemp;		/* tempfile to pass 2 */
58 FILE * foutput;		/* y.output file */
59 
60 	/* storage for grammar rules */
61 
62 int mem0[MEMSIZE] ; /* production storage */
63 int *mem = mem0;
64 int nprod= 1;	/* number of productions */
65 int *prdptr[NPROD];	/* pointers to descriptions of productions */
66 int levprd[NPROD] ;	/* precedence levels for the productions */
67 
68 
69 setup(argc,argv) int argc; char *argv[];
70 {	int i,j,lev,t, ty;
71 	int c;
72 	int *p;
73 	char actname[8];
74 
75 	foutput = NULL;
76 	fdefine = NULL;
77 	i = 1;
78 	while( argc >= 2  && argv[1][0] == '-' ) {
79 		while( *++(argv[1]) ){
80 			switch( *argv[1] ){
81 			case 'v':
82 			case 'V':
83 				foutput = fopen(FILEU, "w" );
84 				if( foutput == NULL ) error( "cannot open y.output" );
85 				continue;
86 			case 'D':
87 			case 'd':
88 				fdefine = fopen( FILED, "w" );
89 				continue;
90 			case 'o':
91 			case 'O':
92 				fprintf( stderr, "`o' flag now default in yacc\n" );
93 				continue;
94 
95 			case 'r':
96 			case 'R':
97 				error( "Ratfor Yacc is dead: sorry...\n" );
98 
99 			default:
100 				error( "illegal option: %c", *argv[1]);
101 				}
102 			}
103 		argv++;
104 		argc--;
105 		}
106 
107 	ftable = fopen( OFILE, "w" );
108 	if( ftable == NULL ) error( "cannot open table file" );
109 
110 	ftemp = fopen( TEMPNAME, "w" );
111 	faction = fopen( ACTNAME, "w" );
112 	if( ftemp==NULL || faction==NULL ) error( "cannot open temp file" );
113 
114 	if( argc < 2 || ((finput=fopen( infile=argv[1], "r" )) == NULL ) ){
115 		error( "cannot open input file" );
116 		}
117 
118 	cnamp = cnames;
119 	defin(0,"$end");
120 	extval = 0400;
121 	defin(0,"error");
122 	defin(1,"$accept");
123 	mem=mem0;
124 	lev = 0;
125 	ty = 0;
126 	i=0;
127 
128 	/* sorry -- no yacc parser here.....
129 		we must bootstrap somehow... */
130 
131 	for( t=gettok();  t!=MARK && t!= ENDFILE; ){
132 		switch( t ){
133 
134 		case ';':
135 			t = gettok();
136 			break;
137 
138 		case START:
139 			if( (t=gettok()) != IDENTIFIER ){
140 				error( "bad %%start construction" );
141 				}
142 			start = chfind(1,tokname);
143 			t = gettok();
144 			continue;
145 
146 		case TYPEDEF:
147 			if( (t=gettok()) != TYPENAME ) error( "bad syntax in %%type" );
148 			ty = numbval;
149 			for(;;){
150 				t = gettok();
151 				switch( t ){
152 
153 				case IDENTIFIER:
154 					if( (t=chfind( 1, tokname ) ) < NTBASE ) {
155 						j = TYPE( toklev[t] );
156 						if( j!= 0 && j != ty ){
157 							error( "type redeclaration of token %s",
158 								tokset[t].name );
159 							}
160 						else SETTYPE( toklev[t],ty);
161 						}
162 					else {
163 						j = nontrst[t-NTBASE].tvalue;
164 						if( j != 0 && j != ty ){
165 							error( "type redeclaration of nonterminal %s",
166 								nontrst[t-NTBASE].name );
167 							}
168 						else nontrst[t-NTBASE].tvalue = ty;
169 						}
170 				case ',':
171 					continue;
172 
173 				case ';':
174 					t = gettok();
175 					break;
176 				default:
177 					break;
178 					}
179 				break;
180 				}
181 			continue;
182 
183 		case UNION:
184 			/* copy the union declaration to the output */
185 			cpyunion();
186 			t = gettok();
187 			continue;
188 
189 		case LEFT:
190 		case BINARY:
191 		case RIGHT:
192 			++i;
193 		case TERM:
194 			lev = t-TERM;  /* nonzero means new prec. and assoc. */
195 			ty = 0;
196 
197 			/* get identifiers so defined */
198 
199 			t = gettok();
200 			if( t == TYPENAME ){ /* there is a type defined */
201 				ty = numbval;
202 				t = gettok();
203 				}
204 
205 			for(;;) {
206 				switch( t ){
207 
208 				case ',':
209 					t = gettok();
210 					continue;
211 
212 				case ';':
213 					break;
214 
215 				case IDENTIFIER:
216 					j = chfind(0,tokname);
217 					if( lev ){
218 						if( ASSOC(toklev[j]) ) error( "redeclaration of precedence of %s", tokname );
219 						SETASC(toklev[j],lev);
220 						SETPLEV(toklev[j],i);
221 						}
222 					if( ty ){
223 						if( TYPE(toklev[j]) ) error( "redeclaration of type of %s", tokname );
224 						SETTYPE(toklev[j],ty);
225 						}
226 					if( (t=gettok()) == NUMBER ){
227 						tokset[j].value = numbval;
228 						if( j < ndefout && j>2 ){
229 							error( "please define type number of %s earlier",
230 								tokset[j].name );
231 							}
232 						t=gettok();
233 						}
234 					continue;
235 
236 					}
237 
238 				break;
239 				}
240 
241 			continue;
242 
243 		case LCURLY:
244 			defout();
245 			cpycode();
246 			t = gettok();
247 			continue;
248 
249 		default:
250 			error( "syntax error" );
251 
252 			}
253 
254 		}
255 
256 	if( t == ENDFILE ){
257 		error( "unexpected EOF before %%" );
258 		}
259 
260 	/* t is MARK */
261 
262 	defout();
263 
264 		fprintf( ftable,  "#define yyclearin yychar = -1\n" );
265 		fprintf( ftable,  "#define yyerrok yyerrflag = 0\n" );
266 		fprintf( ftable,  "extern int yychar;\nextern short yyerrflag;\n" );
267 		fprintf( ftable,  "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" );
268 		if( !ntypes ) fprintf( ftable,  "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" );
269 		fprintf( ftable,  "YYSTYPE yylval, yyval;\n" );
270 
271 	prdptr[0]=mem;
272 	/* added production */
273 	*mem++ = NTBASE;
274 	*mem++ = start;  /* if start is 0, we will overwrite with the lhs of the first rule */
275 	*mem++ = 1;
276 	*mem++ = 0;
277 	prdptr[1]=mem;
278 
279 	while( (t=gettok()) == LCURLY ) cpycode();
280 
281 	if( t != C_IDENTIFIER ) error( "bad syntax on first rule" );
282 
283 	if( !start ) prdptr[0][1] = chfind(1,tokname);
284 
285 	/* read rules */
286 
287 	while( t!=MARK && t!=ENDFILE ){
288 
289 		/* process a rule */
290 
291 		if( t == '|' ){
292 			*mem++ = *prdptr[nprod-1];
293 			}
294 		else if( t == C_IDENTIFIER ){
295 			*mem = chfind(1,tokname);
296 			if( *mem < NTBASE ) error( "token illegal on LHS of grammar rule" );
297 			++mem;
298 			}
299 		else error( "illegal rule: missing semicolon or | ?" );
300 
301 		/* read rule body */
302 
303 
304 		t = gettok();
305 	more_rule:
306 		while( t == IDENTIFIER ) {
307 			*mem = chfind(1,tokname);
308 			if( *mem<NTBASE ) levprd[nprod] = toklev[*mem];
309 			++mem;
310 			t = gettok();
311 			}
312 
313 
314 		if( t == PREC ){
315 			if( gettok()!=IDENTIFIER) error( "illegal %%prec syntax" );
316 			j = chfind(2,tokname);
317 			if( j>=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name);
318 			levprd[nprod]=toklev[j];
319 			t = gettok();
320 			}
321 
322 		if( t == '=' ){
323 			levprd[nprod] |= ACTFLAG;
324 			fprintf( faction, "\ncase %d:", nprod );
325 			cpyact( mem-prdptr[nprod]-1 );
326 			fprintf( faction, " break;" );
327 			if( (t=gettok()) == IDENTIFIER ){
328 				/* action within rule... */
329 
330 				sprintf( actname, "$$%d", nprod );
331 				j = chfind(1,actname);  /* make it a nonterminal */
332 
333 				/* the current rule will become rule number nprod+1 */
334 				/* move the contents down, and make room for the null */
335 
336 				for( p=mem; p>=prdptr[nprod]; --p ) p[2] = *p;
337 				mem += 2;
338 
339 				/* enter null production for action */
340 
341 				p = prdptr[nprod];
342 
343 				*p++ = j;
344 				*p++ = -nprod;
345 
346 				/* update the production information */
347 
348 				levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
349 				levprd[nprod] = ACTFLAG;
350 
351 				if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
352 				prdptr[nprod] = p;
353 
354 				/* make the action appear in the original rule */
355 				*mem++ = j;
356 
357 				/* get some more of the rule */
358 
359 				goto more_rule;
360 				}
361 
362 			}
363 
364 		while( t == ';' ) t = gettok();
365 
366 		*mem++ = -nprod;
367 
368 		/* check that default action is reasonable */
369 
370 		if( ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].tvalue ){
371 			/* no explicit action, LHS has value */
372 			register tempty;
373 			tempty = prdptr[nprod][1];
374 			if( tempty < 0 ) error( "must return a value, since LHS has a type" );
375 			else if( tempty >= NTBASE ) tempty = nontrst[tempty-NTBASE].tvalue;
376 			else tempty = TYPE( toklev[tempty] );
377 			if( tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue ){
378 				error( "default action causes potential type clash" );
379 				}
380 			}
381 
382 		if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
383 		prdptr[nprod] = mem;
384 		levprd[nprod]=0;
385 
386 		}
387 
388 	/* end of all rules */
389 
390 	finact();
391 	if( t == MARK ){
392 		fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
393 		while( (c=getc(finput)) != EOF ) putc( c, ftable );
394 		}
395 	fclose( finput );
396 	}
397 
398 finact(){
399 	/* finish action routine */
400 
401 	fclose(faction);
402 
403 	fprintf( ftable, "# define YYERRCODE %d\n", tokset[2].value );
404 
405 	}
406 
407 defin( t, s ) register char  *s; {
408 /*	define s to be a terminal if t=0
409 	or a nonterminal if t=1		*/
410 
411 	register val;
412 
413 	if (t) {
414 		if( ++nnonter >= NNONTERM ) error("too many nonterminals, limit %d",NNONTERM);
415 		nontrst[nnonter].name = cstash(s);
416 		return( NTBASE + nnonter );
417 		}
418 	/* must be a token */
419 	if( ++ntokens >= NTERMS ) error("too many terminals, limit %d",NTERMS );
420 	tokset[ntokens].name = cstash(s);
421 
422 	/* establish value for token */
423 
424 	if( s[0]==' ' && s[2]=='\0' ) /* single character literal */
425 		val = s[1];
426 	else if ( s[0]==' ' && s[1]=='\\' ) { /* escape sequence */
427 		if( s[3] == '\0' ){ /* single character escape sequence */
428 			switch ( s[2] ){
429 					 /* character which is escaped */
430 			case 'n': val = '\n'; break;
431 			case 'r': val = '\r'; break;
432 			case 'b': val = '\b'; break;
433 			case 't': val = '\t'; break;
434 			case 'f': val = '\f'; break;
435 			case '\'': val = '\''; break;
436 			case '"': val = '"'; break;
437 			case '\\': val = '\\'; break;
438 			default: error( "invalid escape" );
439 				}
440 			}
441 		else if( s[2] <= '7' && s[2]>='0' ){ /* \nnn sequence */
442 			if( s[3]<'0' || s[3] > '7' || s[4]<'0' ||
443 				s[4]>'7' || s[5] != '\0' ) error("illegal \\nnn construction" );
444 			val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
445 			if( val == 0 ) error( "'\\000' is illegal" );
446 			}
447 		}
448 	else {
449 		val = extval++;
450 		}
451 	tokset[ntokens].value = val;
452 	toklev[ntokens] = 0;
453 	return( ntokens );
454 	}
455 
456 defout(){ /* write out the defines (at the end of the declaration section) */
457 
458 	register int i, c;
459 	register char *cp;
460 
461 	for( i=ndefout; i<=ntokens; ++i ){
462 
463 		cp = tokset[i].name;
464 		if( *cp == ' ' ) ++cp;  /* literals */
465 
466 		for( ; (c= *cp)!='\0'; ++cp ){
467 
468 			if( islower(c) || isupper(c) || isdigit(c) || c=='_' );  /* VOID */
469 			else goto nodef;
470 			}
471 
472 		fprintf( ftable, "# define %s %d\n", tokset[i].name, tokset[i].value );
473 		if( fdefine != NULL ) fprintf( fdefine, "# define %s %d\n", tokset[i].name, tokset[i].value );
474 
475 	nodef:	;
476 		}
477 
478 	ndefout = ntokens+1;
479 
480 	}
481 
482 char *
483 cstash( s ) register char *s; {
484 	char *temp;
485 
486 	temp = cnamp;
487 	do {
488 		if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" );
489 		else *cnamp++ = *s;
490 		}  while ( *s++ );
491 	return( temp );
492 	}
493 
494 gettok() {
495 	register i, base;
496 	static int peekline; /* number of '\n' seen in lookahead */
497 	register c, match, reserve;
498 
499 begin:
500 	reserve = 0;
501 	lineno += peekline;
502 	peekline = 0;
503 	c = getc(finput);
504 	while( c==' ' || c=='\n' || c=='\t' || c=='\f' ){
505 		if( c == '\n' ) ++lineno;
506 		c=getc(finput);
507 		}
508 	if( c == '/' ){ /* skip comment */
509 		lineno += skipcom();
510 		goto begin;
511 		}
512 
513 	switch(c){
514 
515 	case EOF:
516 		return(ENDFILE);
517 	case '{':
518 		ungetc( c, finput );
519 		return( '=' );  /* action ... */
520 	case '<':  /* get, and look up, a type name (union member name) */
521 		i = 0;
522 		while( (c=getc(finput)) != '>' && c>=0 && c!= '\n' ){
523 			tokname[i] = c;
524 			if( ++i >= NAMESIZE ) --i;
525 			}
526 		if( c != '>' ) error( "unterminated < ... > clause" );
527 		tokname[i] = '\0';
528 		for( i=1; i<=ntypes; ++i ){
529 			if( !strcmp( typeset[i], tokname ) ){
530 				numbval = i;
531 				return( TYPENAME );
532 				}
533 			}
534 		typeset[numbval = ++ntypes] = cstash( tokname );
535 		return( TYPENAME );
536 
537 	case '"':
538 	case '\'':
539 		match = c;
540 		tokname[0] = ' ';
541 		i = 1;
542 		for(;;){
543 			c = getc(finput);
544 			if( c == '\n' || c == EOF )
545 				error("illegal or missing ' or \"" );
546 			if( c == '\\' ){
547 				c = getc(finput);
548 				tokname[i] = '\\';
549 				if( ++i >= NAMESIZE ) --i;
550 				}
551 			else if( c == match ) break;
552 			tokname[i] = c;
553 			if( ++i >= NAMESIZE ) --i;
554 			}
555 		break;
556 
557 	case '%':
558 	case '\\':
559 
560 		switch(c=getc(finput)) {
561 
562 		case '0':	return(TERM);
563 		case '<':	return(LEFT);
564 		case '2':	return(BINARY);
565 		case '>':	return(RIGHT);
566 		case '%':
567 		case '\\':	return(MARK);
568 		case '=':	return(PREC);
569 		case '{':	return(LCURLY);
570 		default:	reserve = 1;
571 			}
572 
573 	default:
574 
575 		if( isdigit(c) ){ /* number */
576 			numbval = c-'0' ;
577 			base = (c=='0') ? 8 : 10 ;
578 			for( c=getc(finput); isdigit(c) ; c=getc(finput) ){
579 				numbval = numbval*base + c - '0';
580 				}
581 			ungetc( c, finput );
582 			return(NUMBER);
583 			}
584 		else if( islower(c) || isupper(c) || c=='_' || c=='.' || c=='$' ){
585 			i = 0;
586 			while( islower(c) || isupper(c) || isdigit(c) || c=='_' || c=='.' || c=='$' ){
587 				tokname[i] = c;
588 				if( reserve && isupper(c) ) tokname[i] += 'a'-'A';
589 				if( ++i >= NAMESIZE ) --i;
590 				c = getc(finput);
591 				}
592 			}
593 		else return(c);
594 
595 		ungetc( c, finput );
596 		}
597 
598 	tokname[i] = '\0';
599 
600 	if( reserve ){ /* find a reserved word */
601 		if( !strcmp(tokname,"term")) return( TERM );
602 		if( !strcmp(tokname,"token")) return( TERM );
603 		if( !strcmp(tokname,"left")) return( LEFT );
604 		if( !strcmp(tokname,"nonassoc")) return( BINARY );
605 		if( !strcmp(tokname,"binary")) return( BINARY );
606 		if( !strcmp(tokname,"right")) return( RIGHT );
607 		if( !strcmp(tokname,"prec")) return( PREC );
608 		if( !strcmp(tokname,"start")) return( START );
609 		if( !strcmp(tokname,"type")) return( TYPEDEF );
610 		if( !strcmp(tokname,"union")) return( UNION );
611 		error("invalid escape, or illegal reserved word: %s", tokname );
612 		}
613 
614 	/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
615 
616 	c = getc(finput);
617 	while( c==' ' || c=='\t'|| c=='\n' || c=='\f' || c== '/' ) {
618 		if( c == '\n' ) ++peekline;
619 		else if( c == '/' ){ /* look for comments */
620 			peekline += skipcom();
621 			}
622 		c = getc(finput);
623 		}
624 	if( c == ':' ) return( C_IDENTIFIER );
625 	ungetc( c, finput );
626 	return( IDENTIFIER );
627 }
628 
629 fdtype( t ){ /* determine the type of a symbol */
630 	register v;
631 	if( t >= NTBASE ) v = nontrst[t-NTBASE].tvalue;
632 	else v = TYPE( toklev[t] );
633 	if( v <= 0 ) error( "must specify type for %s", (t>=NTBASE)?nontrst[t-NTBASE].name:
634 			tokset[t].name );
635 	return( v );
636 	}
637 
638 chfind( t, s ) register char *s; {
639 	int i;
640 
641 	if (s[0]==' ')t=0;
642 	TLOOP(i){
643 		if(!strcmp(s,tokset[i].name)){
644 			return( i );
645 			}
646 		}
647 	NTLOOP(i){
648 		if(!strcmp(s,nontrst[i].name)) {
649 			return( i+NTBASE );
650 			}
651 		}
652 	/* cannot find name */
653 	if( t>1 )
654 		error( "%s should have been defined earlier", s );
655 	return( defin( t, s ) );
656 	}
657 
658 cpyunion(){
659 	/* copy the union declaration to the output, and the define file if present */
660 
661 	int level, c;
662 	fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
663 	fprintf( ftable, "typedef union " );
664 	if( fdefine ) fprintf( fdefine, "\ntypedef union " );
665 
666 	level = 0;
667 	for(;;){
668 		if( (c=getc(finput)) < 0 ) error( "EOF encountered while processing %%union" );
669 		putc( c, ftable );
670 		if( fdefine ) putc( c, fdefine );
671 
672 		switch( c ){
673 
674 		case '\n':
675 			++lineno;
676 			break;
677 
678 		case '{':
679 			++level;
680 			break;
681 
682 		case '}':
683 			--level;
684 			if( level == 0 ) { /* we are finished copying */
685 				fprintf( ftable, " YYSTYPE;\n" );
686 				if( fdefine ) fprintf( fdefine, " YYSTYPE;\nextern YYSTYPE yylval;\n" );
687 				return;
688 				}
689 			}
690 		}
691 	}
692 
693 cpycode(){ /* copies code between \{ and \} */
694 
695 	int c;
696 	c = getc(finput);
697 	if( c == '\n' ) {
698 		c = getc(finput);
699 		lineno++;
700 		}
701 	fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
702 	while( c>=0 ){
703 		if( c=='\\' )
704 			if( (c=getc(finput)) == '}' ) return;
705 			else putc('\\', ftable );
706 		if( c=='%' )
707 			if( (c=getc(finput)) == '}' ) return;
708 			else putc('%', ftable );
709 		putc( c , ftable );
710 		if( c == '\n' ) ++lineno;
711 		c = getc(finput);
712 		}
713 	error("eof before %%}" );
714 	}
715 
716 skipcom(){ /* skip over comments */
717 	register c, i=0;  /* i is the number of lines skipped */
718 
719 	/* skipcom is called after reading a / */
720 
721 	if( getc(finput) != '*' ) error( "illegal comment" );
722 	c = getc(finput);
723 	while( c != EOF ){
724 		while( c == '*' ){
725 			if( (c=getc(finput)) == '/' ) return( i );
726 			}
727 		if( c == '\n' ) ++i;
728 		c = getc(finput);
729 		}
730 	error( "EOF inside comment" );
731 	/* NOTREACHED */
732 	}
733 
734 cpyact(offset){ /* copy C action to the next ; or closing } */
735 	int brac, c, match, j, s, tok;
736 
737 	fprintf( faction, "\n# line %d \"%s\"\n", lineno, infile );
738 
739 	brac = 0;
740 
741 loop:
742 	c = getc(finput);
743 swt:
744 	switch( c ){
745 
746 case ';':
747 		if( brac == 0 ){
748 			putc( c , faction );
749 			return;
750 			}
751 		goto lcopy;
752 
753 case '{':
754 		brac++;
755 		goto lcopy;
756 
757 case '$':
758 		s = 1;
759 		tok = -1;
760 		c = getc(finput);
761 		if( c == '<' ){ /* type description */
762 			ungetc( c, finput );
763 			if( gettok() != TYPENAME ) error( "bad syntax on $<ident> clause" );
764 			tok = numbval;
765 			c = getc(finput);
766 			}
767 		if( c == '$' ){
768 			fprintf( faction, "yyval");
769 			if( ntypes ){ /* put out the proper tag... */
770 				if( tok < 0 ) tok = fdtype( *prdptr[nprod] );
771 				fprintf( faction, ".%s", typeset[tok] );
772 				}
773 			goto loop;
774 			}
775 		if( c == '-' ){
776 			s = -s;
777 			c = getc(finput);
778 			}
779 		if( isdigit(c) ){
780 			j=0;
781 			while( isdigit(c) ){
782 				j= j*10+c-'0';
783 				c = getc(finput);
784 				}
785 
786 			j = j*s - offset;
787 			if( j > 0 ){
788 				error( "Illegal use of $%d", j+offset );
789 				}
790 
791 			fprintf( faction, "yypvt[-%d]", -j );
792 			if( ntypes ){ /* put out the proper tag */
793 				if( j+offset <= 0 && tok < 0 ) error( "must specify type of $%d", j+offset );
794 				if( tok < 0 ) tok = fdtype( prdptr[nprod][j+offset] );
795 				fprintf( faction, ".%s", typeset[tok] );
796 				}
797 			goto swt;
798 			}
799 		putc( '$' , faction );
800 		if( s<0 ) putc('-', faction );
801 		goto swt;
802 
803 case '}':
804 		if( --brac ) goto lcopy;
805 		putc( c, faction );
806 		return;
807 
808 
809 case '/':	/* look for comments */
810 		putc( c , faction );
811 		c = getc(finput);
812 		if( c != '*' ) goto swt;
813 
814 		/* it really is a comment */
815 
816 		putc( c , faction );
817 		c = getc(finput);
818 		while( c != EOF ){
819 			while( c=='*' ){
820 				putc( c , faction );
821 				if( (c=getc(finput)) == '/' ) goto lcopy;
822 				}
823 			putc( c , faction );
824 			if( c == '\n' )++lineno;
825 			c = getc(finput);
826 			}
827 		error( "EOF inside comment" );
828 
829 case '\'':	/* character constant */
830 		match = '\'';
831 		goto string;
832 
833 case '"':	/* character string */
834 		match = '"';
835 
836 	string:
837 
838 		putc( c , faction );
839 		while( c=getc(finput) ){
840 
841 			if( c=='\\' ){
842 				putc( c , faction );
843 				c=getc(finput);
844 				if( c == '\n' ) ++lineno;
845 				}
846 			else if( c==match ) goto lcopy;
847 			else if( c=='\n' ) error( "newline in string or char. const." );
848 			putc( c , faction );
849 			}
850 		error( "EOF in string or character constant" );
851 
852 case EOF:
853 		error("action does not terminate" );
854 
855 case '\n':	++lineno;
856 		goto lcopy;
857 
858 		}
859 
860 lcopy:
861 	putc( c , faction );
862 	goto loop;
863 	}
864