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