xref: /csrg-svn/old/pcc/mip/scan.c (revision 32837)
1 #ifndef lint
2 static char *sccsid ="@(#)scan.c	2.13 (Berkeley) 12/10/87";
3 #endif lint
4 
5 # include "pass1.h"
6 # include <a.out.h>
7 # include <stab.h>
8 # include <ctype.h>
9 # include <signal.h>
10 
11 	/* temporarily */
12 
13 int asm_esc = 0; /* asm escaped used in file */
14 	/* lexical actions */
15 
16 # define A_ERR 0		/* illegal character */
17 # define A_LET 1		/* saw a letter */
18 # define A_DIG 2		/* saw a digit */
19 # define A_1C 3			/* return a single character */
20 # define A_STR 4		/* string */
21 # define A_CC 5			/* character constant */
22 # define A_BCD 6		/* GCOS BCD constant */
23 # define A_SL 7			/* saw a / */
24 # define A_DOT 8		/* saw a . */
25 # define A_PL 9		/* + */
26 # define A_MI 10		/* - */
27 # define A_EQ 11		/* = */
28 # define A_NOT 12		/* ! */
29 # define A_LT 13		/* < */
30 # define A_GT 14		/* > */
31 # define A_AND 16		/* & */
32 # define A_OR 17		/* | */
33 # define A_WS 18		/* whitespace (not \n) */
34 # define A_NL 19		/* \n */
35 
36 	/* character classes */
37 
38 # define LEXLET 01
39 # define LEXDIG 02
40 # define LEXOCT 04
41 # define LEXHEX 010
42 # define LEXWS 020
43 # define LEXDOT 040
44 
45 	/* reserved word actions */
46 
47 # define AR_TY 0		/* type word */
48 # define AR_RW 1		/* simple reserved word */
49 # define AR_CL 2		/* storage class word */
50 # define AR_S 3		/* struct */
51 # define AR_U 4		/* union */
52 # define AR_E 5		/* enum */
53 # define AR_A 6		/* asm */
54 
55 	/* text buffer */
56 #ifndef FLEXNAMES
57 # define LXTSZ 100
58 #else
59 #define	LXTSZ	BUFSIZ
60 #endif
61 char yytext[LXTSZ];
62 char * lxgcp;
63 
64 extern int proflg;
65 extern int gdebug;
66 extern int fpe();
67 struct sigvec fpe_sigvec;
68 int oldway;		/* allocate storage so lint will compile as well */
69 #ifndef LINT
70 extern int lastloc;
71 #endif
72 
73 unsigned caloff();
74 	/* ARGSUSED */
75 mainp1( argc, argv ) int argc; char *argv[]; {  /* control multiple files */
76 
77 	register i;
78 	register char *cp;
79 	extern int idebug, bdebug, tdebug, edebug;
80 	extern int ddebug, xdebug, gdebug, adebug;
81 	extern unsigned int offsz;
82 	int fdef = 0;
83 	extern char *release;
84 
85 	offsz = caloff();
86 	for( i=1; i<argc; ++i ){
87 		if( *(cp=argv[i]) == '-' && *++cp == 'X' ){
88 			while( *++cp ){
89 				switch( *cp ){
90 
91 				case 'r':
92 					fprintf( stderr, "Release: %s\n",
93 						release );
94 					break;
95 
96 				case 'd':
97 					++ddebug;
98 					break;
99 				case 'i':
100 					++idebug;
101 					break;
102 				case 'b':
103 					++bdebug;
104 					break;
105 				case 't':
106 					++tdebug;
107 					break;
108 				case 'e':
109 					++edebug;
110 					break;
111 				case 'x':
112 					++xdebug;
113 					break;
114 				case 'P':	/* profiling */
115 					++proflg;
116 					break;
117 				case 'g':
118 					++gdebug;
119 					break;
120 				case 'a':
121 					++adebug;
122 					break;
123 				case 'G':
124 					++gdebug;
125 					oldway = 1;
126 					break;
127 					}
128 				}
129 			}
130 			else {
131 			if( *(argv[i]) != '-' ) switch( fdef++ ) {
132 				case 0:
133 				case 1:
134 					if( freopen(argv[i], fdef==1 ? "r" : "w", fdef==1 ? stdin : stdout) == NULL) {
135 						fprintf(stderr, "ccom:can't open %s\n", argv[i]);
136 						exit(1);
137 					}
138 					break;
139 
140 				default:
141 					;
142 				}
143 			}
144 		}
145 
146 # ifdef ONEPASS
147 	(void) p2init( argc, argv );
148 # endif
149 
150 	for( i=0; i<SYMTSZ; ++i ) stab[i].stype = TNULL;
151 
152 	lineno = 1;
153 
154 	lxinit();
155 	tinit();
156 	mkdope();
157 
158 	/* dimension table initialization */
159 
160 	dimtab[NULL] = 0;
161 	dimtab[CHAR] = SZCHAR;
162 	dimtab[INT] = SZINT;
163 	dimtab[FLOAT] = SZFLOAT;
164 	dimtab[DOUBLE] = SZDOUBLE;
165 	dimtab[LONG] = SZLONG;
166 	dimtab[SHORT] = SZSHORT;
167 	dimtab[UCHAR] = SZCHAR;
168 	dimtab[USHORT] = SZSHORT;
169 	dimtab[UNSIGNED] = SZINT;
170 	dimtab[ULONG] = SZLONG;
171 	/* starts past any of the above */
172 	curdim = 16;
173 	reached = 1;
174 
175 	fpe_sigvec.sv_handler = fpe;
176 	(void) sigvec(SIGFPE, &fpe_sigvec, (struct sigvec *) NULL);
177 
178 	(void) yyparse();
179 	yyaccpt();
180 
181 	ejobcode( nerrors ? 1 : 0 );
182 	return(nerrors?1:0);
183 
184 	}
185 
186 # ifdef ibm
187 
188 # define CSMASK 0377
189 # define CSSZ 256
190 
191 # else
192 
193 # define CSMASK 0177
194 # define CSSZ 128
195 
196 # endif
197 
198 short lxmask[CSSZ+1];
199 
200 lxenter( s, m ) register char *s; register short m; {
201 	/* enter a mask into lxmask */
202 	register c;
203 
204 	while( c= *s++ ) lxmask[c+1] |= m;
205 
206 	}
207 
208 
209 # define lxget(c,m) (lxgcp=yytext,lxmore(c,m))
210 
211 lxmore( c, m )  register c, m; {
212 	register char *cp;
213 
214 	*(cp = lxgcp) = c;
215 	while( c=getchar(), lxmask[c+1]&m ){
216 		if( cp < &yytext[LXTSZ-1] ){
217 			*++cp = c;
218 			}
219 		}
220 	ungetc(c,stdin);
221 	*(lxgcp = cp+1) = '\0';
222 	}
223 
224 struct lxdope {
225 	short lxch;	/* the character */
226 	short lxact;	/* the action to be performed */
227 	short lxtok;	/* the token number to be returned */
228 	short lxval;	/* the value to be returned */
229 	} lxdope[] = {
230 
231 	'@',	A_ERR,	0,	0,	/* illegal characters go here... */
232 	'_',	A_LET,	0,	0,	/* letters point here */
233 	'0',	A_DIG,	0,	0,	/* digits point here */
234 	' ',	A_WS,	0,	0,	/* whitespace goes here */
235 	'\n',	A_NL,	0,	0,
236 	'"',	A_STR,	0,	0,	/* character string */
237 	'\'',	A_CC,	0,	0,	/* character constant */
238 	'`',	A_BCD,	0,	0,	/* GCOS BCD constant */
239 	'(',	A_1C,	LP,	0,
240 	')',	A_1C,	RP,	0,
241 	'{',	A_1C,	LC,	0,
242 	'}',	A_1C,	RC,	0,
243 	'[',	A_1C,	LB,	0,
244 	']',	A_1C,	RB,	0,
245 	'*',	A_1C,	MUL,	MUL,
246 	'?',	A_1C,	QUEST,	0,
247 	':',	A_1C,	COLON,	0,
248 	'+',	A_PL,	PLUS,	PLUS,
249 	'-',	A_MI,	MINUS,	MINUS,
250 	'/',	A_SL,	DIVOP,	DIV,
251 	'%',	A_1C,	DIVOP,	MOD,
252 	'&',	A_AND,	AND,	AND,
253 	'|',	A_OR,	OR,	OR,
254 	'^',	A_1C,	ER,	ER,
255 	'!',	A_NOT,	UNOP,	NOT,
256 	'~',	A_1C,	UNOP,	COMPL,
257 	',',	A_1C,	CM,	CM,
258 	';',	A_1C,	SM,	0,
259 	'.',	A_DOT,	STROP,	DOT,
260 	'<',	A_LT,	RELOP,	LT,
261 	'>',	A_GT,	RELOP,	GT,
262 	'=',	A_EQ,	ASSIGN,	ASSIGN,
263 	-1,	A_1C,	0,	0,
264 	};
265 
266 struct lxdope *lxcp[CSSZ+1];
267 
268 lxinit(){
269 	register struct lxdope *p;
270 	register i;
271 	register char *cp;
272 	/* set up character classes */
273 
274 	lxenter( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$", LEXLET );
275 	lxenter( "0123456789", LEXDIG );
276 	lxenter( "0123456789abcdefABCDEF", LEXHEX );
277 		/* \013 should become \v someday; \013 is OK for ASCII and EBCDIC */
278 	lxenter( " \t\r\b\f\013", LEXWS );
279 	lxenter( "01234567", LEXOCT );
280 	lxmask['.'+1] |= LEXDOT;
281 
282 	/* make lxcp point to appropriate lxdope entry for each character */
283 
284 	/* initialize error entries */
285 
286 	for( i= 0; i<=CSSZ; ++i ) lxcp[i] = lxdope;
287 
288 	/* make unique entries */
289 
290 	for( p=lxdope; ; ++p ) {
291 		lxcp[p->lxch+1] = p;
292 		if( p->lxch < 0 ) break;
293 		}
294 
295 	/* handle letters, digits, and whitespace */
296 	/* by convention, first, second, and third places */
297 
298 	cp = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$";
299 	while( *cp ) lxcp[*cp++ + 1] = &lxdope[1];
300 	cp = "123456789";
301 	while( *cp ) lxcp[*cp++ + 1] = &lxdope[2];
302 	cp = "\t\b\r\f\013";
303 	while( *cp ) lxcp[*cp++ + 1] = &lxdope[3];
304 
305 	/* first line might have title */
306 	lxtitle();
307 
308 	}
309 
310 int lxmatch = 0;  /* character to be matched in char or string constant */
311 
312 lxstr(ct){
313 	/* match a string or character constant, up to lxmatch */
314 
315 	register c;
316 	register val;
317 	register i;
318 
319 	i=0;
320 	while( (c=getchar()) != lxmatch ){
321 		switch( c ) {
322 
323 		case EOF:
324 			uerror( "unexpected EOF" );
325 			break;
326 
327 		case '\n':
328 			uerror( "newline in string or char constant" );
329 			++lineno;
330 			break;
331 
332 		case '\\':
333 			switch( c = getchar() ){
334 
335 			case '\n':
336 				++lineno;
337 				continue;
338 
339 			default:
340 				val = c;
341 				goto mkcc;
342 
343 			case 'n':
344 				val = '\n';
345 				goto mkcc;
346 
347 			case 'r':
348 				val = '\r';
349 				goto mkcc;
350 
351 			case 'b':
352 				val = '\b';
353 				goto mkcc;
354 
355 			case 't':
356 				val = '\t';
357 				goto mkcc;
358 
359 			case 'f':
360 				val = '\f';
361 				goto mkcc;
362 
363 			case 'v':
364 				val = '\013';
365 				goto mkcc;
366 
367 			case '0':
368 			case '1':
369 			case '2':
370 			case '3':
371 			case '4':
372 			case '5':
373 			case '6':
374 			case '7':
375 				val = c-'0';
376 				c=getchar();  /* try for 2 */
377 				if( lxmask[c+1] & LEXOCT ){
378 					val = (val<<3) | (c-'0');
379 					c = getchar();  /* try for 3 */
380 					if( lxmask[c+1] & LEXOCT ){
381 						val = (val<<3) | (c-'0');
382 						}
383 					else ungetc( c ,stdin);
384 					}
385 				else ungetc( c ,stdin);
386 
387 				goto mkcc1;
388 
389 				}
390 		default:
391 			val =c;
392 		mkcc:
393 			val = CCTRANS(val);
394 		mkcc1:
395 			if( lxmatch == '\'' ){
396 				val = CHARCAST(val);  /* it is, after all, a "character" constant */
397 				makecc( val, i );
398 				}
399 			else { /* stash the byte into the string */
400 				if( strflg ) {
401 					if( ct==0 || i<ct ) putbyte( val );
402 					else if( i == ct ) werror( "non-null byte ignored in string initializer" );
403 					}
404 				else bycode( val, i );
405 				}
406 			++i;
407 			continue;
408 			}
409 		break;
410 		}
411 	/* end of string or  char constant */
412 
413 	if( lxmatch == '"' ){
414 		if( strflg ){ /* end the string */
415 			if( ct==0 || i<ct ) putbyte( 0 );  /* the null at the end */
416 			}
417 		else {  /* the initializer gets a null byte */
418 			bycode( 0, i++ );
419 			bycode( -1, i );
420 			dimtab[curdim] = i;  /* in case of later sizeof ... */
421 			}
422 		}
423 	else { /* end the character constant */
424 		if( i == 0 ) uerror( "empty character constant" );
425 		if( i>(SZINT/SZCHAR) || ( (pflag||hflag)&&i>1) )
426 			uerror( "too many characters in character constant" );
427 		}
428 	lxmatch = 0;	/* handshake with yylex() */
429 	}
430 
431 lxcom(){
432 	register c;
433 	/* saw a /*: process a comment */
434 
435 	for(;;){
436 
437 		switch( c = getchar() ){
438 
439 		case EOF:
440 			uerror( "unexpected EOF" );
441 			return;
442 
443 		case '\n':
444 			++lineno;
445 
446 		default:
447 			continue;
448 
449 		case '*':
450 			if( (c = getchar()) == '/' ) return;
451 			else ungetc( c ,stdin);
452 			continue;
453 
454 # ifdef LINT
455 		case 'V':
456 			lxget( c, LEXLET|LEXDIG );
457 			{
458 				extern int vaflag;
459 				int i;
460 				i = yytext[7]?yytext[7]-'0':0;
461 				yytext[7] = '\0';
462 				if( strcmp( yytext, "VARARGS" ) ) continue;
463 				vaflag = i;
464 				continue;
465 				}
466 		case 'L':
467 			lxget( c, LEXLET );
468 			if( strcmp( yytext, "LINTLIBRARY" ) ) continue;
469 			{
470 				extern int libflag;
471 				libflag = 1;
472 				}
473 			continue;
474 
475 		case 'A':
476 			lxget( c, LEXLET );
477 			if( strcmp( yytext, "ARGSUSED" ) ) continue;
478 			{
479 				extern int argflag, vflag;
480 				argflag = 1;
481 				vflag = 0;
482 				}
483 			continue;
484 
485 		case 'N':
486 			lxget( c, LEXLET );
487 			if( strcmp( yytext, "NOTREACHED" ) ) continue;
488 			reached = 0;
489 			continue;
490 # endif
491 			}
492 		}
493 	}
494 
495 yylex(){
496 	if (lxmatch != 0) {
497 		/* recover from a syntax error that consumes a STRING token */
498 		strflg = 1;
499 		lxstr(0);
500 	}
501 	for(;;){
502 
503 		register lxchar;
504 		register struct lxdope *p;
505 		register struct symtab *sp;
506 		int id;
507 		char *s;
508 		static char sc[5];
509 
510 		switch( (p=lxcp[(lxchar=getchar())+1])->lxact ){
511 
512 		onechar:
513 			ungetc( lxchar ,stdin);
514 
515 		case A_1C:
516 			/* eat up a single character, and return an opcode */
517 
518 			yylval.intval = p->lxval;
519 			return( p->lxtok );
520 
521 		case A_ERR:
522 			switch( lxchar ){
523 			case '\\':	s = "\\\\"; break;
524 			case '\0':	s = "\\0"; break;
525 			default:
526 				if( isgraph( lxchar ) ){
527 					sc[0] = lxchar;
528 					sc[1] = '\0';
529 					}
530 				else
531 					sprintf( sc, "\\%03.3o", (unsigned char) lxchar );
532 				s = sc;
533 				break;
534 				}
535 			uerror( "illegal character: '%s'", s );
536 			break;
537 
538 		case A_LET:
539 			/* collect an identifier, check for reserved word, and return */
540 			lxget( lxchar, LEXLET|LEXDIG );
541 			if( (lxchar=lxres()) > 0 ) return( lxchar ); /* reserved word */
542 			if( lxchar== 0 ) continue;
543 #ifdef FLEXNAMES
544 			id = lookup( hash(yytext),
545 #else
546 			id = lookup( yytext,
547 #endif
548 				/* tag name for struct/union/enum */
549 				(stwart&TAGNAME)? STAG:
550 				/* member name for struct/union */
551 				(stwart&(INSTRUCT|INUNION|FUNNYNAME))?SMOS:0 );
552 			sp = &stab[id];
553 			if( sp->sclass == TYPEDEF && !stwart ){
554 				stwart = instruct;
555 				yylval.nodep = mkty( sp->stype, sp->dimoff, sp->sizoff );
556 				return( TYPE );
557 				}
558 			stwart = (stwart&SEENAME) ? instruct : 0;
559 			yylval.intval = id;
560 			return( NAME );
561 
562 		case A_DIG:
563 			/* collect a digit string, then look at last one... */
564 			lastcon = 0;
565 			lxget( lxchar, LEXDIG );
566 			switch( lxchar=getchar() ){
567 
568 			case 'x':
569 			case 'X':
570 				if( yytext[0] != '0' && !yytext[1] ) uerror( "illegal hex constant" );
571 				lxmore( lxchar, LEXHEX );
572 				/* convert the value */
573 				{
574 					register char *cp;
575 					for( cp = yytext+2; *cp; ++cp ){
576 						/* this code won't work for all wild character sets,
577 						   but seems ok for ascii and ebcdic */
578 						lastcon <<= 4;
579 						if( isdigit( *cp ) ) lastcon += *cp-'0';
580 						else if( isupper( *cp ) ) lastcon += *cp - 'A'+ 10;
581 						else lastcon += *cp - 'a'+ 10;
582 						}
583 					}
584 
585 			hexlong:
586 				/* criterion for longness for hex and octal constants is that it
587 				   fit within 0177777 */
588 				if( lastcon & ~0177777L ) yylval.intval = 1;
589 				else yylval.intval = 0;
590 
591 				goto islong;
592 
593 			case '.':
594 				lxmore( lxchar, LEXDIG );
595 
596 			getfp:
597 				if( (lxchar=getchar()) == 'e' || lxchar == 'E' ){ /* exponent */
598 
599 			case 'e':
600 			case 'E':
601 					if( (lxchar=getchar()) == '+' || lxchar == '-' ){
602 						*lxgcp++ = 'e';
603 						}
604 					else {
605 						ungetc(lxchar,stdin);
606 						lxchar = 'e';
607 						}
608 					lxmore( lxchar, LEXDIG );
609 					/* now have the whole thing... */
610 					}
611 				else {  /* no exponent */
612 					ungetc( lxchar ,stdin);
613 					}
614 				return( isitfloat( yytext ) );
615 
616 			default:
617 				ungetc( lxchar ,stdin);
618 				if( yytext[0] == '0' ){
619 					/* convert in octal */
620 					register char *cp;
621 					for( cp = yytext+1; *cp; ++cp ){
622 						lastcon <<= 3;
623 						lastcon += *cp - '0';
624 						}
625 					goto hexlong;
626 					}
627 				else {
628 					/* convert in decimal */
629 					register char *cp;
630 					for( cp = yytext; *cp; ++cp ){
631 						lastcon = lastcon * 10 + *cp - '0';
632 						}
633 					}
634 
635 				/* decide if it is long or not (decimal case) */
636 
637 				/* if it is positive and fits in 15 bits, or negative and
638 				   and fits in 15 bits plus an extended sign, it is int; otherwise long */
639 				/* if there is an l or L following, all bets are off... */
640 
641 				{	CONSZ v;
642 					v = lastcon & ~077777L;
643 					if( v == 0 || v == ~077777L ) yylval.intval = 0;
644 					else yylval.intval = 1;
645 					}
646 
647 			islong:
648 				/* finally, look for trailing L or l */
649 				if( (lxchar = getchar()) == 'L' || lxchar == 'l' ) yylval.intval = 1;
650 				else ungetc( lxchar ,stdin);
651 				return( ICON );
652 				}
653 
654 		case A_DOT:
655 			/* look for a dot: if followed by a digit, floating point */
656 			lxchar = getchar();
657 			if( lxmask[lxchar+1] & LEXDIG ){
658 				ungetc(lxchar,stdin);
659 				lxget( '.', LEXDIG );
660 				goto getfp;
661 				}
662 			stwart = FUNNYNAME;
663 			goto onechar;
664 
665 		case A_STR:
666 			/* string constant */
667 			lxmatch = '"';
668 			return( STRING );
669 
670 		case A_CC:
671 			/* character constant */
672 			lxmatch = '\'';
673 			lastcon = 0;
674 			lxstr(0);
675 			yylval.intval = 0;
676 			return( ICON );
677 
678 		case A_BCD:
679 			{
680 				register i;
681 				int j;
682 				for( i=0; i<LXTSZ; ++i ){
683 					if( ( j = getchar() ) == '`' ) break;
684 					if( j == '\n' ){
685 						uerror( "newline in BCD constant" );
686 						break;
687 						}
688 					yytext[i] = j;
689 					}
690 				yytext[i] = '\0';
691 				if( i>6 ) uerror( "BCD constant exceeds 6 characters" );
692 # ifdef gcos
693 				else strtob( yytext, &lastcon, i );
694 				lastcon >>= 6*(6-i);
695 # else
696 				uerror( "gcos BCD constant illegal" );
697 # endif
698 				yylval.intval = 0;  /* not long */
699 				return( ICON );
700 				}
701 
702 		case A_SL:
703 			/* / */
704 			if( (lxchar=getchar()) != '*' ) goto onechar;
705 			lxcom();
706 		case A_WS:
707 			continue;
708 
709 		case A_NL:
710 			++lineno;
711 			lxtitle();
712 			continue;
713 
714 		case A_NOT:
715 			/* ! */
716 			if( (lxchar=getchar()) != '=' ) goto onechar;
717 			yylval.intval = NE;
718 			return( EQUOP );
719 
720 		case A_MI:
721 			/* - */
722 			if( (lxchar=getchar()) == '-' ){
723 				yylval.intval = DECR;
724 				return( INCOP );
725 				}
726 			if( lxchar != '>' ) goto onechar;
727 			stwart = FUNNYNAME;
728 			yylval.intval=STREF;
729 			return( STROP );
730 
731 		case A_PL:
732 			/* + */
733 			if( (lxchar=getchar()) != '+' ) goto onechar;
734 			yylval.intval = INCR;
735 			return( INCOP );
736 
737 		case A_AND:
738 			/* & */
739 			if( (lxchar=getchar()) != '&' ) goto onechar;
740 			return( yylval.intval = ANDAND );
741 
742 		case A_OR:
743 			/* | */
744 			if( (lxchar=getchar()) != '|' ) goto onechar;
745 			return( yylval.intval = OROR );
746 
747 		case A_LT:
748 			/* < */
749 			if( (lxchar=getchar()) == '<' ){
750 				yylval.intval = LS;
751 				return( SHIFTOP );
752 				}
753 			if( lxchar != '=' ) goto onechar;
754 			yylval.intval = LE;
755 			return( RELOP );
756 
757 		case A_GT:
758 			/* > */
759 			if( (lxchar=getchar()) == '>' ){
760 				yylval.intval = RS;
761 				return(SHIFTOP );
762 				}
763 			if( lxchar != '=' ) goto onechar;
764 			yylval.intval = GE;
765 			return( RELOP );
766 
767 		case A_EQ:
768 			/* = */
769 			switch( lxchar = getchar() ){
770 
771 			case '=':
772 				yylval.intval = EQ;
773 				return( EQUOP );
774 
775 #ifdef old_assignment_ops
776 			case '+':
777 				yylval.intval = ASG PLUS;
778 				break;
779 
780 			case '-':
781 				yylval.intval = ASG MINUS;
782 
783 			warn:
784 				if( lxmask[ (lxchar=getchar())+1] & (LEXLET|LEXDIG|LEXDOT) ){
785 					werror( "ambiguous assignment: assignment op taken" );
786 					}
787 				ungetc( lxchar ,stdin);
788 				break;
789 
790 			case '*':
791 				yylval.intval = ASG MUL;
792 				goto warn;
793 
794 			case '/':
795 				yylval.intval = ASG DIV;
796 				break;
797 
798 			case '%':
799 				yylval.intval = ASG MOD;
800 				break;
801 
802 			case '&':
803 				yylval.intval = ASG AND;
804 				break;
805 
806 			case '|':
807 				yylval.intval = ASG OR;
808 				break;
809 
810 			case '^':
811 				yylval.intval = ASG ER;
812 				break;
813 
814 			case '<':
815 				if( (lxchar=getchar()) != '<' ){
816 					uerror( "=<%c illegal", lxchar );
817 					}
818 				yylval.intval = ASG LS;
819 				break;
820 
821 			case '>':
822 				if( (lxchar=getchar()) != '>' ){
823 					uerror( "=>%c illegal", lxchar );
824 					}
825 				yylval.intval = ASG RS;
826 				break;
827 #endif old_assignment_ops
828 
829 			default:
830 				goto onechar;
831 
832 				}
833 
834 #ifdef old_assignment_ops	/* defeat 'unreachable code' warning */
835 			return( ASOP );
836 #endif old_assignment_ops
837 
838 		default:
839 			cerror( "yylex error, character %03o (octal)", lxchar );
840 
841 			}
842 
843 		/* ordinarily, repeat here... */
844 		cerror( "out of switch in yylex" );
845 
846 		}
847 
848 	}
849 
850 struct lxrdope {
851 	/* dope for reserved, in alphabetical order */
852 
853 	char *lxrch;	/* name of reserved word */
854 	short lxract;	/* reserved word action */
855 	short lxrval;	/* value to be returned */
856 	} lxrdope[] = {
857 
858 	"asm",		AR_A,	0,
859 	"auto",		AR_CL,	AUTO,
860 	"break",	AR_RW,	BREAK,
861 	"char",		AR_TY,	CHAR,
862 	"case",		AR_RW,	CASE,
863 	"continue",	AR_RW,	CONTINUE,
864 	"double",	AR_TY,	DOUBLE,
865 	"default",	AR_RW,	DEFAULT,
866 	"do",		AR_RW,	DO,
867 	"extern",	AR_CL,	EXTERN,
868 	"else",		AR_RW,	ELSE,
869 	"enum",		AR_E,	ENUM,
870 	"for",		AR_RW,	FOR,
871 	"float",	AR_TY,	FLOAT,
872 	"fortran",	AR_CL,	FORTRAN,
873 	"goto",		AR_RW,	GOTO,
874 	"if",		AR_RW,	IF,
875 	"int",		AR_TY,	INT,
876 	"long",		AR_TY,	LONG,
877 	"return",	AR_RW,	RETURN,
878 	"register",	AR_CL,	REGISTER,
879 	"switch",	AR_RW,	SWITCH,
880 	"struct",	AR_S,	0,
881 	"sizeof",	AR_RW,	SIZEOF,
882 	"short",	AR_TY,	SHORT,
883 	"static",	AR_CL,	STATIC,
884 	"typedef",	AR_CL,	TYPEDEF,
885 	"unsigned",	AR_TY,	UNSIGNED,
886 	"union",	AR_U,	0,
887 	"void",		AR_TY,	UNDEF, /* tymerge adds FTN */
888 	"while",	AR_RW,	WHILE,
889 	"",		0,	0,	/* to stop the search */
890 	};
891 
892 lxres() {
893 	/* check to see of yytext is reserved; if so,
894 	/* do the appropriate action and return */
895 	/* otherwise, return -1 */
896 
897 	register c, ch;
898 	register struct lxrdope *p;
899 
900 	ch = yytext[0];
901 
902 	if( !islower(ch) ) return( -1 );
903 
904 	switch( ch ){
905 
906 	case 'a':
907 		c=0; break;
908 	case 'b':
909 		c=2; break;
910 	case 'c':
911 		c=3; break;
912 	case 'd':
913 		c=6; break;
914 	case 'e':
915 		c=9; break;
916 	case 'f':
917 		c=12; break;
918 	case 'g':
919 		c=15; break;
920 	case 'i':
921 		c=16; break;
922 	case 'l':
923 		c=18; break;
924 	case 'r':
925 		c=19; break;
926 	case 's':
927 		c=21; break;
928 	case 't':
929 		c=26; break;
930 	case 'u':
931 		c=27; break;
932 	case 'v':
933 		c=29; break;
934 	case 'w':
935 		c=30; break;
936 
937 	default:
938 		return( -1 );
939 		}
940 
941 	for( p= lxrdope+c; p->lxrch[0] == ch; ++p ){
942 		if( !strcmp( yytext, p->lxrch ) ){ /* match */
943 			switch( p->lxract ){
944 
945 			case AR_TY:
946 				/* type word */
947 				stwart = instruct;
948 				yylval.nodep = mkty( (TWORD)p->lxrval, 0, p->lxrval );
949 				return( TYPE );
950 
951 			case AR_RW:
952 				/* ordinary reserved word */
953 				return( yylval.intval = p->lxrval );
954 
955 			case AR_CL:
956 				/* class word */
957 				yylval.intval = p->lxrval;
958 				return( CLASS );
959 
960 			case AR_S:
961 				/* struct */
962 				stwart = INSTRUCT|SEENAME|TAGNAME;
963 				yylval.intval = INSTRUCT;
964 				return( STRUCT );
965 
966 			case AR_U:
967 				/* union */
968 				stwart = INUNION|SEENAME|TAGNAME;
969 				yylval.intval = INUNION;
970 				return( STRUCT );
971 
972 			case AR_E:
973 				/* enums */
974 				stwart = SEENAME|TAGNAME;
975 				return( yylval.intval = ENUM );
976 
977 			case AR_A:
978 				/* asm */
979 				asm_esc = 1; /* warn the world! */
980 				lxget( ' ', LEXWS );
981 				if( getchar() != '(' ) goto badasm;
982 				lxget( ' ', LEXWS );
983 				if( getchar() != '"' ) goto badasm;
984 # ifndef ONEPASS
985 # ifndef LINT
986 				putchar(')');
987 # endif
988 # endif
989 				while( (c=getchar()) != '"' ){
990 					if( c=='\n' || c==EOF ) goto badasm;
991 # ifndef LINT
992 					putchar(c);
993 # endif
994 					}
995 				lxget( ' ', LEXWS );
996 				if( getchar() != ')' ) goto badasm;
997 # ifndef LINT
998 				putchar('\n');
999 # endif
1000 				return( 0 );
1001 
1002 			badasm:
1003 				uerror( "bad asm construction" );
1004 				return( 0 );
1005 
1006 			default:
1007 				cerror( "bad AR_?? action" );
1008 				}
1009 			}
1010 		}
1011 	return( -1 );
1012 	}
1013 
1014 extern int	labelno;
1015 
1016 lxtitle(){
1017 	/* called after a newline; set linenumber and file name */
1018 
1019 	register c, val;
1020 	register char *cp, *cq;
1021 
1022 	for(;;){  /* might be several such lines in a row */
1023 		if( (c=getchar()) != '#' ){
1024 			if( c != EOF ) ungetc(c,stdin);
1025 #ifndef LINT
1026 			if ( lastloc != PROG) return;
1027 			cp = ftitle;
1028 			cq = ititle;
1029 			while ( *cp ) if (*cp++ != *cq++) return;
1030 			if ( *cq ) return;
1031 			if( nerrors == 0 ) psline();
1032 #endif
1033 			return;
1034 			}
1035 
1036 		lxget( ' ', LEXWS );
1037 		c = getchar();
1038 		if( c == 'i' ){
1039 			/* #ident -- currently a no-op */
1040 			lxget( c, LEXLET );
1041 			if( strcmp( yytext, "ident" ) )
1042 				werror( "%s: undefined control", yytext );
1043 			while( (c = getchar()) != '\n' && c != EOF )
1044 				;
1045 			continue;
1046 			}
1047 		if( c == 'p' ){
1048 			/* #pragma -- special instructions */
1049 			lxget( c, LEXLET );
1050 			if( strcmp( yytext, "pragma" ) ) {
1051 				werror( "%s: undefined control", yytext );
1052 				while( (c = getchar()) != '\n' && c != EOF )
1053 					;
1054 				continue;
1055 				}
1056 			lxget( ' ' , LEXWS );
1057 			switch( c = getchar() ){
1058 # ifdef LINT
1059 			case 'V':
1060 				lxget( c, LEXLET|LEXDIG );
1061 				{
1062 					extern int vaflag;
1063 					int i;
1064 					i = yytext[7]?yytext[7]-'0':0;
1065 					yytext[7] = '\0';
1066 					if( strcmp( yytext, "VARARGS" ) ) break;
1067 					vaflag = i;
1068 					break;
1069 					}
1070 			case 'L':
1071 				lxget( c, LEXLET );
1072 				if( strcmp( yytext, "LINTLIBRARY" ) ) break;
1073 				{
1074 					extern int libflag;
1075 					libflag = 1;
1076 					}
1077 				break;
1078 
1079 			case 'A':
1080 				lxget( c, LEXLET );
1081 				if( strcmp( yytext, "ARGSUSED" ) ) break;
1082 				{
1083 					extern int argflag, vflag;
1084 					argflag = 1;
1085 					vflag = 0;
1086 					}
1087 				break;
1088 
1089 			case 'N':
1090 				lxget( c, LEXLET );
1091 				if( strcmp( yytext, "NOTREACHED" ) ) break;
1092 				reached = 0;
1093 				break;
1094 #endif
1095 
1096 			case '\n':
1097 			case EOF:
1098 				continue;
1099 				}
1100 			while( (c = getchar()) != '\n' && c != EOF )
1101 				;
1102 			continue;
1103 			}
1104 		if( c == 'l' ){
1105 			/* #line -- just like # */
1106 			lxget( c, LEXLET );
1107 			if( strcmp( yytext, "line" ) ){
1108 				werror( "%s: undefined control", yytext );
1109 				while( (c = getchar()) != '\n' && c != EOF )
1110 					;
1111 				continue;
1112 				}
1113 			lxget( ' ', LEXWS );
1114 			c = getchar();
1115 			}
1116 		if( !isdigit(c) ){
1117 			if( isalpha(c) ){
1118 				lxget( c, LEXLET );
1119 				werror( "%s: undefined control", yytext );
1120 				}
1121 			while( c != '\n' && c != EOF )
1122 				c = getchar();
1123 			continue;
1124 			}
1125 
1126 		val = 0;
1127 		do {
1128 			val = val*10+ c - '0';
1129 			}
1130 		while( isdigit( c = getchar() ) );
1131 
1132 		if( c == EOF )
1133 			continue;
1134 		ungetc( c, stdin );
1135 		lineno = val;
1136 		lxget( ' ', LEXWS );
1137 		if( (c=getchar()) != '\n' && c != EOF ){
1138 			for( cp=ftitle; c!=EOF && c!='\n'; c=getchar(),++cp ){
1139 				*cp = c;
1140 				}
1141 			*cp = '\0';
1142 #ifndef LINT
1143 			if (ititle[0] == '\0') {
1144 				cp = ftitle;
1145 				cq = ititle;
1146 				while ( *cp )
1147 					*cq++ = *cp++;
1148 				*cq = '\0';
1149 				*--cq = '\0';
1150 #ifndef FLEXNAMES
1151 				for ( cp = ititle+1; *(cp-1); cp += 8 ) {
1152 					pstab(cp, N_SO);
1153 					if (gdebug) printf("0,0,LL%d\n", labelno);
1154 					}
1155 #else
1156 				pstab(ititle+1, N_SO);
1157 				if (gdebug) printf("0,0,LL%d\n", labelno);
1158 #endif
1159 
1160 				*cq = '"';
1161 				printf("LL%d:\n", labelno++);
1162 				}
1163 #endif
1164 			}
1165 		}
1166 	}
1167 
1168 #ifdef FLEXNAMES
1169 #define	NSAVETAB	4096
1170 char	*savetab;
1171 unsigned saveleft;
1172 char	*malloc();
1173 char	*calloc();
1174 char	*strncpy();
1175 
1176 char *
1177 savestr(cp)
1178 	register char *cp;
1179 {
1180 	register int len;
1181 
1182 	len = strlen(cp) + 1;
1183 	if (len > saveleft) {
1184 		saveleft = NSAVETAB;
1185 		if (len > saveleft)
1186 			saveleft = len;
1187 		savetab = malloc(saveleft);
1188 		if (savetab == 0)
1189 			cerror("Ran out of memory (savestr)");
1190 	}
1191 	(void) strncpy(savetab, cp, len);
1192 	cp = savetab;
1193 	savetab += len;
1194 	saveleft -= len;
1195 	return (cp);
1196 }
1197 
1198 /*
1199  * The definition for the segmented hash tables.
1200  */
1201 #define	MAXHASH	20
1202 #define	HASHINC	1013
1203 struct ht {
1204 	char	**ht_low;
1205 	char	**ht_high;
1206 	int	ht_used;
1207 } htab[MAXHASH];
1208 
1209 char *
1210 hash(s)
1211 	char *s;
1212 {
1213 	register char **h;
1214 	register i;
1215 	register char *cp;
1216 	struct ht *htp;
1217 	int sh;
1218 
1219 	/*
1220 	 * The hash function is a modular hash of
1221 	 * the sum of the characters with the sum
1222 	 * doubled before each successive character
1223 	 * is added.
1224 	 */
1225 	cp = s;
1226 	i = 0;
1227 	while (*cp)
1228 		i = i*2 + *cp++;
1229 	sh = (i&077777) % HASHINC;
1230 	cp = s;
1231 	/*
1232 	 * There are as many as MAXHASH active
1233 	 * hash tables at any given point in time.
1234 	 * The search starts with the first table
1235 	 * and continues through the active tables
1236 	 * as necessary.
1237 	 */
1238 	for (htp = htab; htp < &htab[MAXHASH]; htp++) {
1239 		if (htp->ht_low == 0) {
1240 			register char **hp =
1241 			    (char **) calloc(sizeof (char **), HASHINC);
1242 			if (hp == 0)
1243 				cerror("ran out of memory (hash)");
1244 			htp->ht_low = hp;
1245 			htp->ht_high = htp->ht_low + HASHINC;
1246 		}
1247 		h = htp->ht_low + sh;
1248 		/*
1249 		 * quadratic rehash increment
1250 		 * starts at 1 and incremented
1251 		 * by two each rehash.
1252 		 */
1253 		i = 1;
1254 		do {
1255 			if (*h == 0) {
1256 				if (htp->ht_used > (HASHINC * 3)/4)
1257 					break;
1258 				htp->ht_used++;
1259 				*h = savestr(cp);
1260 				return (*h);
1261 			}
1262 			if (**h == *cp && strcmp(*h, cp) == 0)
1263 				return (*h);
1264 			h += i;
1265 			i += 2;
1266 			if (h >= htp->ht_high)
1267 				h -= HASHINC;
1268 		} while (i < HASHINC);
1269 	}
1270 	cerror("ran out of hash tables");
1271 	/*NOTREACHED*/
1272 }
1273 #endif
1274