xref: /plan9/sys/src/cmd/cc/lex.c (revision 51e5a6e64864eca88b38d65bc2db7f84bcf218a0)
1 #include	"cc.h"
2 #include	"y.tab.h"
3 
4 #ifndef	CPP
5 #define	CPP	"/bin/cpp"
6 #endif
7 
8 /*
9  * known debug flags
10  *	-a		acid declaration output
11  *	-A		!B
12  *	-B		non ANSI
13  *	-d		print declarations
14  *	-D name		define
15  *	-F		format specification check
16  *	-i		print initialization
17  *	-I path		include
18  *	-l		generate little-endian code
19  *	-L		print every NAME symbol
20  *	-M		constant multiplication
21  *	-m		print add/sub/mul trees
22  *	-n		print acid to file (%.c=%.acid) (with -a or -aa)
23  *	-o file		output file
24  *	-p		use standard cpp ANSI preprocessor (not on windows)
25  *	-r		print registerization
26  *	-s		print structure offsets (with -a or -aa)
27  *	-S		print assembly
28  *	-t		print type trees
29  *	-V		enable void* conversion warnings
30  *	-v		verbose printing
31  *	-w		print warnings
32  *	-X		abort on error
33  */
34 
35 void
36 main(int argc, char *argv[])
37 {
38 	char *defs[50], *p;
39 	int nproc, nout, status, i, c, ndef;
40 
41 	memset(debug, 0, sizeof(debug));
42 	tinit();
43 	cinit();
44 	ginit();
45 	arginit();
46 
47 	profileflg = 1;	/* #pragma can turn it off */
48 	tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
49 	ndef = 0;
50 	outfile = 0;
51 	include[ninclude++] = ".";
52 	ARGBEGIN {
53 	default:
54 		c = ARGC();
55 		if(c >= 0 && c < sizeof(debug))
56 			debug[c]++;
57 		break;
58 
59 	case 'l':			/* for little-endian mips */
60 		if(thechar != 'v'){
61 			print("can only use -l with vc");
62 			errorexit();
63 		}
64 		thechar = '0';
65 		thestring = "spim";
66 		break;
67 
68 	case 'o':
69 		outfile = ARGF();
70 		break;
71 
72 	case 'D':
73 		p = ARGF();
74 		if(p) {
75 			defs[ndef++] = p;
76 			dodefine(p);
77 		}
78 		break;
79 
80 	case 'I':
81 		p = ARGF();
82 		setinclude(p);
83 		break;
84 	} ARGEND
85 	if(argc < 1 && outfile == 0) {
86 		print("usage: %cc [-options] files\n", thechar);
87 		errorexit();
88 	}
89 	if(argc > 1 && systemtype(Windows)){
90 		print("can't compile multiple files on windows\n");
91 		errorexit();
92 	}
93 	if(argc > 1 && !systemtype(Windows)) {
94 		nproc = 1;
95 		/*
96 		 * if we're writing acid to standard output, don't compile
97 		 * concurrently, to avoid interleaving output.
98 		 */
99 		if(((!debug['a'] && !debug['Z']) || debug['n']) &&
100 		    (p = getenv("NPROC")) != nil)
101 			nproc = atol(p);	/* */
102 		c = 0;
103 		nout = 0;
104 		for(;;) {
105 			while(nout < nproc && argc > 0) {
106 				i = myfork();
107 				if(i < 0) {
108 					i = mywait(&status);
109 					if(i < 0) {
110 						print("cannot create a process\n");
111 						errorexit();
112 					}
113 					if(status)
114 						c++;
115 					nout--;
116 					continue;
117 				}
118 				if(i == 0) {
119 					fprint(2, "%s:\n", *argv);
120 					if (compile(*argv, defs, ndef))
121 						errorexit();
122 					exits(0);
123 				}
124 				nout++;
125 				argc--;
126 				argv++;
127 			}
128 			i = mywait(&status);
129 			if(i < 0) {
130 				if(c)
131 					errorexit();
132 				exits(0);
133 			}
134 			if(status)
135 				c++;
136 			nout--;
137 		}
138 	}
139 
140 	if(argc == 0)
141 		c = compile("stdin", defs, ndef);
142 	else
143 		c = compile(argv[0], defs, ndef);
144 
145 	if(c)
146 		errorexit();
147 	exits(0);
148 }
149 
150 int
151 compile(char *file, char **defs, int ndef)
152 {
153 	char ofile[400], incfile[20];
154 	char *p, *av[100], opt[256];
155 	int i, c, fd[2];
156 	static int first = 1;
157 
158 	strcpy(ofile, file);
159 	p = utfrrune(ofile, pathchar());
160 	if(p) {
161 		*p++ = 0;
162 		if(!debug['.'])
163 			include[0] = strdup(ofile);
164 	} else
165 		p = ofile;
166 
167 	if(outfile == 0) {
168 		outfile = p;
169 		if(outfile) {
170 			if(p = utfrrune(outfile, '.'))
171 				if(p[1] == 'c' && p[2] == 0)
172 					p[0] = 0;
173 			p = utfrune(outfile, 0);
174 			if(debug['a'] && debug['n'])
175 				strcat(p, ".acid");
176 			else if(debug['Z'] && debug['n'])
177 				strcat(p, "_pickle.c");
178 			else {
179 				p[0] = '.';
180 				p[1] = thechar;
181 				p[2] = 0;
182 			}
183 		} else
184 			outfile = "/dev/null";
185 	}
186 
187 	if(p = getenv("INCLUDE")) {
188 		setinclude(p);
189 	} else {
190 		if(systemtype(Plan9)) {
191 			sprint(incfile, "/%s/include", thestring);
192 			setinclude(strdup(incfile));
193 			setinclude("/sys/include");
194 		}
195 	}
196 	if (first)
197 		Binit(&diagbuf, 1, OWRITE);
198 	/*
199 	 * if we're writing acid to standard output, don't keep scratching
200 	 * outbuf.
201 	 */
202 	if((debug['a'] || debug['Z']) && !debug['n']) {
203 		if (first) {
204 			outfile = 0;
205 			Binit(&outbuf, dup(1, -1), OWRITE);
206 			dup(2, 1);
207 		}
208 	} else {
209 		c = mycreat(outfile, 0664);
210 		if(c < 0) {
211 			diag(Z, "cannot open %s - %r", outfile);
212 			outfile = 0;
213 			errorexit();
214 		}
215 		Binit(&outbuf, c, OWRITE);
216 	}
217 	newio();
218 	first = 0;
219 
220 	/* Use an ANSI preprocessor */
221 	if(debug['p']) {
222 		if(systemtype(Windows)) {
223 			diag(Z, "-p option not supported on windows");
224 			errorexit();
225 		}
226 		if(myaccess(file) < 0) {
227 			diag(Z, "%s does not exist", file);
228 			errorexit();
229 		}
230 		if(mypipe(fd) < 0) {
231 			diag(Z, "pipe failed");
232 			errorexit();
233 		}
234 		switch(myfork()) {
235 		case -1:
236 			diag(Z, "fork failed");
237 			errorexit();
238 		case 0:
239 			close(fd[0]);
240 			mydup(fd[1], 1);
241 			close(fd[1]);
242 			av[0] = CPP;
243 			i = 1;
244 			if(debug['+']) {
245 				sprint(opt, "-+");
246 				av[i++] = strdup(opt);
247 			}
248 			for(c = 0; c < ndef; c++) {
249 				sprint(opt, "-D%s", defs[c]);
250 				av[i++] = strdup(opt);
251 			}
252 			for(c = 0; c < ninclude; c++) {
253 				sprint(opt, "-I%s", include[c]);
254 				av[i++] = strdup(opt);
255 			}
256 			if(strcmp(file, "stdin") != 0)
257 				av[i++] = file;
258 			av[i] = 0;
259 			if(debug['p'] > 1) {
260 				for(c = 0; c < i; c++)
261 					fprint(2, "%s ", av[c]);
262 				fprint(2, "\n");
263 			}
264 			myexec(av[0], av);
265 			fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
266 			errorexit();
267 		default:
268 			close(fd[1]);
269 			newfile(file, fd[0]);
270 			break;
271 		}
272 	} else {
273 		if(strcmp(file, "stdin") == 0)
274 			newfile(file, 0);
275 		else
276 			newfile(file, -1);
277 	}
278 	yyparse();
279 	if(!debug['a'] && !debug['Z'])
280 		gclean();
281 	return nerrors;
282 }
283 
284 void
285 errorexit(void)
286 {
287 	if(outfile)
288 		remove(outfile);
289 	exits("error");
290 }
291 
292 void
293 pushio(void)
294 {
295 	Io *i;
296 
297 	i = iostack;
298 	if(i == I) {
299 		yyerror("botch in pushio");
300 		errorexit();
301 	}
302 	i->p = fi.p;
303 	i->c = fi.c;
304 }
305 
306 void
307 newio(void)
308 {
309 	Io *i;
310 	static int pushdepth = 0;
311 
312 	i = iofree;
313 	if(i == I) {
314 		pushdepth++;
315 		if(pushdepth > 1000) {
316 			yyerror("macro/io expansion too deep");
317 			errorexit();
318 		}
319 		i = alloc(sizeof(*i));
320 	} else
321 		iofree = i->link;
322 	i->c = 0;
323 	i->f = -1;
324 	ionext = i;
325 }
326 
327 void
328 newfile(char *s, int f)
329 {
330 	Io *i;
331 
332 	if(debug['e'])
333 		print("%L: %s\n", lineno, s);
334 
335 	i = ionext;
336 	i->link = iostack;
337 	iostack = i;
338 	i->f = f;
339 	if(f < 0)
340 		i->f = open(s, 0);
341 	if(i->f < 0) {
342 		yyerror("%cc: %r: %s", thechar, s);
343 		errorexit();
344 	}
345 	fi.c = 0;
346 	linehist(s, 0);
347 }
348 
349 Sym*
350 slookup(char *s)
351 {
352 
353 	strcpy(symb, s);
354 	return lookup();
355 }
356 
357 Sym*
358 lookup(void)
359 {
360 	Sym *s;
361 	ulong h;
362 	char *p;
363 	int c, n;
364 
365 	h = 0;
366 	for(p=symb; *p;) {
367 		h = h * 3;
368 		h += *p++;
369 	}
370 	n = (p - symb) + 1;
371 	if((long)h < 0)
372 		h = ~h;
373 	h %= NHASH;
374 	c = symb[0];
375 	for(s = hash[h]; s != S; s = s->link) {
376 		if(s->name[0] != c)
377 			continue;
378 		if(strcmp(s->name, symb) == 0)
379 			return s;
380 	}
381 	s = alloc(sizeof(*s));
382 	s->name = alloc(n);
383 	memmove(s->name, symb, n);
384 
385 	strcpy(s->name, symb);
386 	s->link = hash[h];
387 	hash[h] = s;
388 	syminit(s);
389 
390 	return s;
391 }
392 
393 void
394 syminit(Sym *s)
395 {
396 	s->lexical = LNAME;
397 	s->block = 0;
398 	s->offset = 0;
399 	s->type = T;
400 	s->suetag = T;
401 	s->class = CXXX;
402 	s->aused = 0;
403 	s->sig = SIGNONE;
404 }
405 
406 #define	EOF	(-1)
407 #define	IGN	(-2)
408 #define	ESC	(1<<20)
409 #define	GETC()	((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
410 
411 enum
412 {
413 	Numdec		= 1<<0,
414 	Numlong		= 1<<1,
415 	Numuns		= 1<<2,
416 	Numvlong	= 1<<3,
417 	Numflt		= 1<<4,
418 };
419 
420 long
421 yylex(void)
422 {
423 	vlong vv;
424 	long c, c1, t;
425 	char *cp;
426 	Rune rune;
427 	Sym *s;
428 
429 	if(peekc != IGN) {
430 		c = peekc;
431 		peekc = IGN;
432 		goto l1;
433 	}
434 l0:
435 	c = GETC();
436 
437 l1:
438 	if(c >= Runeself) {
439 		/*
440 		 * extension --
441 		 *	all multibyte runes are alpha
442 		 */
443 		cp = symb;
444 		goto talph;
445 	}
446 	if(isspace(c)) {
447 		if(c == '\n')
448 			lineno++;
449 		goto l0;
450 	}
451 	if(isalpha(c)) {
452 		cp = symb;
453 		if(c != 'L')
454 			goto talph;
455 		*cp++ = c;
456 		c = GETC();
457 		if(c == '\'') {
458 			/* L'x' */
459 			c = escchar('\'', 1, 0);
460 			if(c == EOF)
461 				c = '\'';
462 			c1 = escchar('\'', 1, 0);
463 			if(c1 != EOF) {
464 				yyerror("missing '");
465 				peekc = c1;
466 			}
467 			yylval.vval = convvtox(c, TUSHORT);
468 			return LUCONST;
469 		}
470 		if(c == '"') {
471 			goto caselq;
472 		}
473 		goto talph;
474 	}
475 	if(isdigit(c))
476 		goto tnum;
477 	switch(c)
478 	{
479 
480 	case EOF:
481 		peekc = EOF;
482 		return -1;
483 
484 	case '_':
485 		cp = symb;
486 		goto talph;
487 
488 	case '#':
489 		domacro();
490 		goto l0;
491 
492 	case '.':
493 		c1 = GETC();
494 		if(isdigit(c1)) {
495 			cp = symb;
496 			*cp++ = c;
497 			c = c1;
498 			c1 = 0;
499 			goto casedot;
500 		}
501 		break;
502 
503 	case '"':
504 		strcpy(symb, "\"<string>\"");
505 		cp = alloc(0);
506 		c1 = 0;
507 
508 		/* "..." */
509 		for(;;) {
510 			c = escchar('"', 0, 1);
511 			if(c == EOF)
512 				break;
513 			if(c & ESC) {
514 				cp = allocn(cp, c1, 1);
515 				cp[c1++] = c;
516 			} else {
517 				rune = c;
518 				c = runelen(rune);
519 				cp = allocn(cp, c1, c);
520 				runetochar(cp+c1, &rune);
521 				c1 += c;
522 			}
523 		}
524 		yylval.sval.l = c1;
525 		do {
526 			cp = allocn(cp, c1, 1);
527 			cp[c1++] = 0;
528 		} while(c1 & MAXALIGN);
529 		yylval.sval.s = cp;
530 		return LSTRING;
531 
532 	caselq:
533 		/* L"..." */
534 		strcpy(symb, "\"L<string>\"");
535 		cp = alloc(0);
536 		c1 = 0;
537 		for(;;) {
538 			c = escchar('"', 1, 0);
539 			if(c == EOF)
540 				break;
541 			cp = allocn(cp, c1, sizeof(ushort));
542 			*(ushort*)(cp + c1) = c;
543 			c1 += sizeof(ushort);
544 		}
545 		yylval.sval.l = c1;
546 		do {
547 			cp = allocn(cp, c1, sizeof(ushort));
548 			*(ushort*)(cp + c1) = 0;
549 			c1 += sizeof(ushort);
550 		} while(c1 & MAXALIGN);
551 		yylval.sval.s = cp;
552 		return LLSTRING;
553 
554 	case '\'':
555 		/* '.' */
556 		c = escchar('\'', 0, 0);
557 		if(c == EOF)
558 			c = '\'';
559 		c1 = escchar('\'', 0, 0);
560 		if(c1 != EOF) {
561 			yyerror("missing '");
562 			peekc = c1;
563 		}
564 		vv = c;
565 		yylval.vval = convvtox(vv, TUCHAR);
566 		if(yylval.vval != vv)
567 			yyerror("overflow in character constant: 0x%lx", c);
568 		else
569 		if(c & 0x80){
570 			nearln = lineno;
571 			warn(Z, "sign-extended character constant");
572 		}
573 		yylval.vval = convvtox(vv, TCHAR);
574 		return LCONST;
575 
576 	case '/':
577 		c1 = GETC();
578 		if(c1 == '*') {
579 			for(;;) {
580 				c = getr();
581 				while(c == '*') {
582 					c = getr();
583 					if(c == '/')
584 						goto l0;
585 				}
586 				if(c == EOF) {
587 					yyerror("eof in comment");
588 					errorexit();
589 				}
590 			}
591 		}
592 		if(c1 == '/') {
593 			for(;;) {
594 				c = getr();
595 				if(c == '\n')
596 					goto l0;
597 				if(c == EOF) {
598 					yyerror("eof in comment");
599 					errorexit();
600 				}
601 			}
602 		}
603 		if(c1 == '=')
604 			return LDVE;
605 		break;
606 
607 	case '*':
608 		c1 = GETC();
609 		if(c1 == '=')
610 			return LMLE;
611 		break;
612 
613 	case '%':
614 		c1 = GETC();
615 		if(c1 == '=')
616 			return LMDE;
617 		break;
618 
619 	case '+':
620 		c1 = GETC();
621 		if(c1 == '+')
622 			return LPP;
623 		if(c1 == '=')
624 			return LPE;
625 		break;
626 
627 	case '-':
628 		c1 = GETC();
629 		if(c1 == '-')
630 			return LMM;
631 		if(c1 == '=')
632 			return LME;
633 		if(c1 == '>')
634 			return LMG;
635 		break;
636 
637 	case '>':
638 		c1 = GETC();
639 		if(c1 == '>') {
640 			c = LRSH;
641 			c1 = GETC();
642 			if(c1 == '=')
643 				return LRSHE;
644 			break;
645 		}
646 		if(c1 == '=')
647 			return LGE;
648 		break;
649 
650 	case '<':
651 		c1 = GETC();
652 		if(c1 == '<') {
653 			c = LLSH;
654 			c1 = GETC();
655 			if(c1 == '=')
656 				return LLSHE;
657 			break;
658 		}
659 		if(c1 == '=')
660 			return LLE;
661 		break;
662 
663 	case '=':
664 		c1 = GETC();
665 		if(c1 == '=')
666 			return LEQ;
667 		break;
668 
669 	case '!':
670 		c1 = GETC();
671 		if(c1 == '=')
672 			return LNE;
673 		break;
674 
675 	case '&':
676 		c1 = GETC();
677 		if(c1 == '&')
678 			return LANDAND;
679 		if(c1 == '=')
680 			return LANDE;
681 		break;
682 
683 	case '|':
684 		c1 = GETC();
685 		if(c1 == '|')
686 			return LOROR;
687 		if(c1 == '=')
688 			return LORE;
689 		break;
690 
691 	case '^':
692 		c1 = GETC();
693 		if(c1 == '=')
694 			return LXORE;
695 		break;
696 
697 	default:
698 		return c;
699 	}
700 	peekc = c1;
701 	return c;
702 
703 talph:
704 	/*
705 	 * cp is set to symb and some
706 	 * prefix has been stored
707 	 */
708 	for(;;) {
709 		if(c >= Runeself) {
710 			for(c1=0;;) {
711 				cp[c1++] = c;
712 				if(fullrune(cp, c1))
713 					break;
714 				c = GETC();
715 			}
716 			cp += c1;
717 			c = GETC();
718 			continue;
719 		}
720 		if(!isalnum(c) && c != '_')
721 			break;
722 		*cp++ = c;
723 		c = GETC();
724 	}
725 	*cp = 0;
726 	if(debug['L'])
727 		print("%L: %s\n", lineno, symb);
728 	peekc = c;
729 	s = lookup();
730 	if(s->macro) {
731 		newio();
732 		cp = ionext->b;
733 		macexpand(s, cp);
734 		pushio();
735 		ionext->link = iostack;
736 		iostack = ionext;
737 		fi.p = cp;
738 		fi.c = strlen(cp);
739 		if(peekc != IGN) {
740 			cp[fi.c++] = peekc;
741 			cp[fi.c] = 0;
742 			peekc = IGN;
743 		}
744 		goto l0;
745 	}
746 	yylval.sym = s;
747 	if(s->class == CTYPEDEF || s->class == CTYPESTR)
748 		return LTYPE;
749 	return s->lexical;
750 
751 tnum:
752 	c1 = 0;
753 	cp = symb;
754 	if(c != '0') {
755 		c1 |= Numdec;
756 		for(;;) {
757 			*cp++ = c;
758 			c = GETC();
759 			if(isdigit(c))
760 				continue;
761 			goto dc;
762 		}
763 	}
764 	*cp++ = c;
765 	c = GETC();
766 	if(c == 'x' || c == 'X')
767 		for(;;) {
768 			*cp++ = c;
769 			c = GETC();
770 			if(isdigit(c))
771 				continue;
772 			if(c >= 'a' && c <= 'f')
773 				continue;
774 			if(c >= 'A' && c <= 'F')
775 				continue;
776 			if(cp == symb+2)
777 				yyerror("malformed hex constant");
778 			goto ncu;
779 		}
780 	if(c < '0' || c > '7')
781 		goto dc;
782 	for(;;) {
783 		if(c >= '0' && c <= '7') {
784 			*cp++ = c;
785 			c = GETC();
786 			continue;
787 		}
788 		goto ncu;
789 	}
790 
791 dc:
792 	if(c == '.')
793 		goto casedot;
794 	if(c == 'e' || c == 'E')
795 		goto casee;
796 
797 ncu:
798 	if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
799 		c = GETC();
800 		c1 |= Numuns;
801 		goto ncu;
802 	}
803 	if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
804 		c = GETC();
805 		if(c1 & Numlong)
806 			c1 |= Numvlong;
807 		c1 |= Numlong;
808 		goto ncu;
809 	}
810 	*cp = 0;
811 	peekc = c;
812 	if(mpatov(symb, &yylval.vval))
813 		yyerror("overflow in constant");
814 
815 	vv = yylval.vval;
816 	if(c1 & Numvlong) {
817 		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
818 			c = LUVLCONST;
819 			t = TUVLONG;
820 			goto nret;
821 		}
822 		c = LVLCONST;
823 		t = TVLONG;
824 		goto nret;
825 	}
826 	if(c1 & Numlong) {
827 		if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
828 			c = LULCONST;
829 			t = TULONG;
830 			goto nret;
831 		}
832 		c = LLCONST;
833 		t = TLONG;
834 		goto nret;
835 	}
836 	if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
837 		c = LUCONST;
838 		t = TUINT;
839 		goto nret;
840 	}
841 	c = LCONST;
842 	t = TINT;
843 	goto nret;
844 
845 nret:
846 	yylval.vval = convvtox(vv, t);
847 	if(yylval.vval != vv){
848 		nearln = lineno;
849 		warn(Z, "truncated constant: %T %s", types[t], symb);
850 	}
851 	return c;
852 
853 casedot:
854 	for(;;) {
855 		*cp++ = c;
856 		c = GETC();
857 		if(!isdigit(c))
858 			break;
859 	}
860 	if(c != 'e' && c != 'E')
861 		goto caseout;
862 
863 casee:
864 	*cp++ = 'e';
865 	c = GETC();
866 	if(c == '+' || c == '-') {
867 		*cp++ = c;
868 		c = GETC();
869 	}
870 	if(!isdigit(c))
871 		yyerror("malformed fp constant exponent");
872 	while(isdigit(c)) {
873 		*cp++ = c;
874 		c = GETC();
875 	}
876 
877 caseout:
878 	if(c == 'L' || c == 'l') {
879 		c = GETC();
880 		c1 |= Numlong;
881 	} else
882 	if(c == 'F' || c == 'f') {
883 		c = GETC();
884 		c1 |= Numflt;
885 	}
886 	*cp = 0;
887 	peekc = c;
888 	yylval.dval = strtod(symb, nil);
889 	if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
890 		yyerror("overflow in float constant");
891 		yylval.dval = 0;
892 	}
893 	if(c1 & Numflt)
894 		return LFCONST;
895 	return LDCONST;
896 }
897 
898 /*
899  * convert a string, s, to vlong in *v
900  * return conversion overflow.
901  * required syntax is [0[x]]d*
902  */
903 int
904 mpatov(char *s, vlong *v)
905 {
906 	vlong n, nn;
907 	int c;
908 
909 	n = 0;
910 	c = *s;
911 	if(c == '0')
912 		goto oct;
913 	while(c = *s++) {
914 		if(c >= '0' && c <= '9')
915 			nn = n*10 + c-'0';
916 		else
917 			goto bad;
918 		if(n < 0 && nn >= 0)
919 			goto bad;
920 		n = nn;
921 	}
922 	goto out;
923 
924 oct:
925 	s++;
926 	c = *s;
927 	if(c == 'x' || c == 'X')
928 		goto hex;
929 	while(c = *s++) {
930 		if(c >= '0' || c <= '7')
931 			nn = n*8 + c-'0';
932 		else
933 			goto bad;
934 		if(n < 0 && nn >= 0)
935 			goto bad;
936 		n = nn;
937 	}
938 	goto out;
939 
940 hex:
941 	s++;
942 	while(c = *s++) {
943 		if(c >= '0' && c <= '9')
944 			c += 0-'0';
945 		else
946 		if(c >= 'a' && c <= 'f')
947 			c += 10-'a';
948 		else
949 		if(c >= 'A' && c <= 'F')
950 			c += 10-'A';
951 		else
952 			goto bad;
953 		nn = n*16 + c;
954 		if(n < 0 && nn >= 0)
955 			goto bad;
956 		n = nn;
957 	}
958 out:
959 	*v = n;
960 	return 0;
961 
962 bad:
963 	*v = ~0;
964 	return 1;
965 }
966 
967 int
968 getc(void)
969 {
970 	int c;
971 
972 	if(peekc != IGN) {
973 		c = peekc;
974 		peekc = IGN;
975 	} else
976 		c = GETC();
977 	if(c == '\n')
978 		lineno++;
979 	if(c == EOF) {
980 		yyerror("End of file");
981 		errorexit();
982 	}
983 	return c;
984 }
985 
986 long
987 getr(void)
988 {
989 	int c, i;
990 	char str[UTFmax+1];
991 	Rune rune;
992 
993 
994 	c = getc();
995 	if(c < Runeself)
996 		return c;
997 	i = 0;
998 	str[i++] = c;
999 
1000 loop:
1001 	c = getc();
1002 	str[i++] = c;
1003 	if(!fullrune(str, i))
1004 		goto loop;
1005 	c = chartorune(&rune, str);
1006 	if(rune == Runeerror && c == 1) {
1007 		nearln = lineno;
1008 		diag(Z, "illegal rune in string");
1009 		for(c=0; c<i; c++)
1010 			print(" %.2x", *(uchar*)(str+c));
1011 		print("\n");
1012 	}
1013 	return rune;
1014 }
1015 
1016 int
1017 getnsc(void)
1018 {
1019 	int c;
1020 
1021 	if(peekc != IGN) {
1022 		c = peekc;
1023 		peekc = IGN;
1024 	} else
1025 		c = GETC();
1026 	for(;;) {
1027 		if(!isspace(c))
1028 			return c;
1029 		if(c == '\n') {
1030 			lineno++;
1031 			return c;
1032 		}
1033 		c = GETC();
1034 	}
1035 }
1036 
1037 void
1038 unget(int c)
1039 {
1040 
1041 	peekc = c;
1042 	if(c == '\n')
1043 		lineno--;
1044 }
1045 
1046 long
1047 escchar(long e, int longflg, int escflg)
1048 {
1049 	long c, l;
1050 	int i;
1051 
1052 loop:
1053 	c = getr();
1054 	if(c == '\n') {
1055 		yyerror("newline in string");
1056 		return EOF;
1057 	}
1058 	if(c != '\\') {
1059 		if(c == e)
1060 			c = EOF;
1061 		return c;
1062 	}
1063 	c = getr();
1064 	if(c == 'x') {
1065 		/*
1066 		 * note this is not ansi,
1067 		 * supposed to only accept 2 hex
1068 		 */
1069 		i = 2;
1070 		if(longflg)
1071 			i = 4;
1072 		l = 0;
1073 		for(; i>0; i--) {
1074 			c = getc();
1075 			if(c >= '0' && c <= '9') {
1076 				l = l*16 + c-'0';
1077 				continue;
1078 			}
1079 			if(c >= 'a' && c <= 'f') {
1080 				l = l*16 + c-'a' + 10;
1081 				continue;
1082 			}
1083 			if(c >= 'A' && c <= 'F') {
1084 				l = l*16 + c-'A' + 10;
1085 				continue;
1086 			}
1087 			unget(c);
1088 			break;
1089 		}
1090 		if(escflg)
1091 			l |= ESC;
1092 		return l;
1093 	}
1094 	if(c >= '0' && c <= '7') {
1095 		/*
1096 		 * note this is not ansi,
1097 		 * supposed to only accept 3 oct
1098 		 */
1099 		i = 2;
1100 		if(longflg)
1101 			i = 5;
1102 		l = c - '0';
1103 		for(; i>0; i--) {
1104 			c = getc();
1105 			if(c >= '0' && c <= '7') {
1106 				l = l*8 + c-'0';
1107 				continue;
1108 			}
1109 			unget(c);
1110 		}
1111 		if(escflg)
1112 			l |= ESC;
1113 		return l;
1114 	}
1115 	switch(c)
1116 	{
1117 	case '\n':	goto loop;
1118 	case 'n':	return '\n';
1119 	case 't':	return '\t';
1120 	case 'b':	return '\b';
1121 	case 'r':	return '\r';
1122 	case 'f':	return '\f';
1123 	case 'a':	return '\a';
1124 	case 'v':	return '\v';
1125 	}
1126 	return c;
1127 }
1128 
1129 struct
1130 {
1131 	char	*name;
1132 	ushort	lexical;
1133 	ushort	type;
1134 } itab[] =
1135 {
1136 	"auto",		LAUTO,		0,
1137 	"break",	LBREAK,		0,
1138 	"case",		LCASE,		0,
1139 	"char",		LCHAR,		TCHAR,
1140 	"const",	LCONSTNT,	0,
1141 	"continue",	LCONTINUE,	0,
1142 	"default",	LDEFAULT,	0,
1143 	"do",		LDO,		0,
1144 	"double",	LDOUBLE,	TDOUBLE,
1145 	"else",		LELSE,		0,
1146 	"enum",		LENUM,		0,
1147 	"extern",	LEXTERN,	0,
1148 	"float",	LFLOAT,		TFLOAT,
1149 	"for",		LFOR,		0,
1150 	"goto",		LGOTO,		0,
1151 	"if",		LIF,		0,
1152 	"inline",	LINLINE,	0,
1153 	"int",		LINT,		TINT,
1154 	"long",		LLONG,		TLONG,
1155 	"register",	LREGISTER,	0,
1156 	"restrict",	LRESTRICT,	0,
1157 	"return",	LRETURN,	0,
1158 	"SET",		LSET,		0,
1159 	"short",	LSHORT,		TSHORT,
1160 	"signed",	LSIGNED,	0,
1161 	"signof",	LSIGNOF,	0,
1162 	"sizeof",	LSIZEOF,	0,
1163 	"static",	LSTATIC,	0,
1164 	"struct",	LSTRUCT,	0,
1165 	"switch",	LSWITCH,	0,
1166 	"typedef",	LTYPEDEF,	0,
1167 	"typestr",	LTYPESTR,	0,
1168 	"union",	LUNION,		0,
1169 	"unsigned",	LUNSIGNED,	0,
1170 	"USED",		LUSED,		0,
1171 	"void",		LVOID,		TVOID,
1172 	"volatile",	LVOLATILE,	0,
1173 	"while",	LWHILE,		0,
1174 	0
1175 };
1176 
1177 void
1178 cinit(void)
1179 {
1180 	Sym *s;
1181 	int i;
1182 	Type *t;
1183 
1184 	nerrors = 0;
1185 	lineno = 1;
1186 	iostack = I;
1187 	iofree = I;
1188 	peekc = IGN;
1189 	nhunk = 0;
1190 
1191 	types[TXXX] = T;
1192 	types[TCHAR] = typ(TCHAR, T);
1193 	types[TUCHAR] = typ(TUCHAR, T);
1194 	types[TSHORT] = typ(TSHORT, T);
1195 	types[TUSHORT] = typ(TUSHORT, T);
1196 	types[TINT] = typ(TINT, T);
1197 	types[TUINT] = typ(TUINT, T);
1198 	types[TLONG] = typ(TLONG, T);
1199 	types[TULONG] = typ(TULONG, T);
1200 	types[TVLONG] = typ(TVLONG, T);
1201 	types[TUVLONG] = typ(TUVLONG, T);
1202 	types[TFLOAT] = typ(TFLOAT, T);
1203 	types[TDOUBLE] = typ(TDOUBLE, T);
1204 	types[TVOID] = typ(TVOID, T);
1205 	types[TENUM] = typ(TENUM, T);
1206 	types[TFUNC] = typ(TFUNC, types[TINT]);
1207 	types[TIND] = typ(TIND, types[TVOID]);
1208 
1209 	for(i=0; i<NHASH; i++)
1210 		hash[i] = S;
1211 	for(i=0; itab[i].name; i++) {
1212 		s = slookup(itab[i].name);
1213 		s->lexical = itab[i].lexical;
1214 		if(itab[i].type != 0)
1215 			s->type = types[itab[i].type];
1216 	}
1217 	blockno = 0;
1218 	autobn = 0;
1219 	autoffset = 0;
1220 
1221 	t = typ(TARRAY, types[TCHAR]);
1222 	t->width = 0;
1223 	symstring = slookup(".string");
1224 	symstring->class = CSTATIC;
1225 	symstring->type = t;
1226 
1227 	t = typ(TARRAY, types[TCHAR]);
1228 	t->width = 0;
1229 
1230 	nodproto = new(OPROTO, Z, Z);
1231 	dclstack = D;
1232 
1233 	pathname = allocn(pathname, 0, 100);
1234 	if(mygetwd(pathname, 99) == 0) {
1235 		pathname = allocn(pathname, 100, 900);
1236 		if(mygetwd(pathname, 999) == 0)
1237 			strcpy(pathname, "/???");
1238 	}
1239 
1240 	fmtinstall('O', Oconv);
1241 	fmtinstall('T', Tconv);
1242 	fmtinstall('F', FNconv);
1243 	fmtinstall('L', Lconv);
1244 	fmtinstall('Q', Qconv);
1245 	fmtinstall('|', VBconv);
1246 }
1247 
1248 int
1249 filbuf(void)
1250 {
1251 	Io *i;
1252 
1253 loop:
1254 	i = iostack;
1255 	if(i == I)
1256 		return EOF;
1257 	if(i->f < 0)
1258 		goto pop;
1259 	fi.c = read(i->f, i->b, BUFSIZ) - 1;
1260 	if(fi.c < 0) {
1261 		close(i->f);
1262 		linehist(0, 0);
1263 		goto pop;
1264 	}
1265 	fi.p = i->b + 1;
1266 	return i->b[0] & 0xff;
1267 
1268 pop:
1269 	iostack = i->link;
1270 	i->link = iofree;
1271 	iofree = i;
1272 	i = iostack;
1273 	if(i == I)
1274 		return EOF;
1275 	fi.p = i->p;
1276 	fi.c = i->c;
1277 	if(--fi.c < 0)
1278 		goto loop;
1279 	return *fi.p++ & 0xff;
1280 }
1281 
1282 int
1283 Oconv(Fmt *fp)
1284 {
1285 	int a;
1286 
1287 	a = va_arg(fp->args, int);
1288 	if(a < OXXX || a > OEND)
1289 		return fmtprint(fp, "***badO %d***", a);
1290 
1291 	return fmtstrcpy(fp, onames[a]);
1292 }
1293 
1294 int
1295 Lconv(Fmt *fp)
1296 {
1297 	char str[STRINGSZ], s[STRINGSZ];
1298 	Hist *h;
1299 	struct
1300 	{
1301 		Hist*	incl;	/* start of this include file */
1302 		long	idel;	/* delta line number to apply to include */
1303 		Hist*	line;	/* start of this #line directive */
1304 		long	ldel;	/* delta line number to apply to #line */
1305 	} a[HISTSZ];
1306 	long l, d;
1307 	int i, n;
1308 
1309 	l = va_arg(fp->args, long);
1310 	n = 0;
1311 	for(h = hist; h != H; h = h->link) {
1312 		if(l < h->line)
1313 			break;
1314 		if(h->name) {
1315 			if(h->offset != 0) {		/* #line directive, not #pragma */
1316 				if(n > 0 && n < HISTSZ && h->offset >= 0) {
1317 					a[n-1].line = h;
1318 					a[n-1].ldel = h->line - h->offset + 1;
1319 				}
1320 			} else {
1321 				if(n < HISTSZ) {	/* beginning of file */
1322 					a[n].incl = h;
1323 					a[n].idel = h->line;
1324 					a[n].line = 0;
1325 				}
1326 				n++;
1327 			}
1328 			continue;
1329 		}
1330 		n--;
1331 		if(n > 0 && n < HISTSZ) {
1332 			d = h->line - a[n].incl->line;
1333 			a[n-1].ldel += d;
1334 			a[n-1].idel += d;
1335 		}
1336 	}
1337 	if(n > HISTSZ)
1338 		n = HISTSZ;
1339 	str[0] = 0;
1340 	for(i=n-1; i>=0; i--) {
1341 		if(i != n-1) {
1342 			if(fp->flags & ~(FmtWidth|FmtPrec))	/* BUG ROB - was f3 */
1343 				break;
1344 			strcat(str, " ");
1345 		}
1346 		if(a[i].line)
1347 			snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
1348 				a[i].line->name, l-a[i].ldel+1,
1349 				a[i].incl->name, l-a[i].idel+1);
1350 		else
1351 			snprint(s, STRINGSZ, "%s:%ld",
1352 				a[i].incl->name, l-a[i].idel+1);
1353 		if(strlen(s)+strlen(str) >= STRINGSZ-10)
1354 			break;
1355 		strcat(str, s);
1356 		l = a[i].incl->line - 1;	/* now print out start of this file */
1357 	}
1358 	if(n == 0)
1359 		strcat(str, "<eof>");
1360 	return fmtstrcpy(fp, str);
1361 }
1362 
1363 int
1364 Tconv(Fmt *fp)
1365 {
1366 	char str[STRINGSZ+20], s[STRINGSZ+20];
1367 	Type *t, *t1;
1368 	int et;
1369 	long n;
1370 
1371 	str[0] = 0;
1372 	for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
1373 		et = t->etype;
1374 		if(str[0])
1375 			strcat(str, " ");
1376 		if(t->garb&~GINCOMPLETE) {
1377 			sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
1378 			if(strlen(str) + strlen(s) < STRINGSZ)
1379 				strcat(str, s);
1380 		}
1381 		sprint(s, "%s", tnames[et]);
1382 		if(strlen(str) + strlen(s) < STRINGSZ)
1383 			strcat(str, s);
1384 		if(et == TFUNC && (t1 = t->down)) {
1385 			sprint(s, "(%T", t1);
1386 			if(strlen(str) + strlen(s) < STRINGSZ)
1387 				strcat(str, s);
1388 			while(t1 = t1->down) {
1389 				sprint(s, ", %T", t1);
1390 				if(strlen(str) + strlen(s) < STRINGSZ)
1391 					strcat(str, s);
1392 			}
1393 			if(strlen(str) + strlen(s) < STRINGSZ)
1394 				strcat(str, ")");
1395 		}
1396 		if(et == TARRAY) {
1397 			n = t->width;
1398 			if(t->link && t->link->width)
1399 				n /= t->link->width;
1400 			sprint(s, "[%ld]", n);
1401 			if(strlen(str) + strlen(s) < STRINGSZ)
1402 				strcat(str, s);
1403 		}
1404 		if(t->nbits) {
1405 			sprint(s, " %d:%d", t->shift, t->nbits);
1406 			if(strlen(str) + strlen(s) < STRINGSZ)
1407 				strcat(str, s);
1408 		}
1409 		if(typesu[et]) {
1410 			if(t->tag) {
1411 				strcat(str, " ");
1412 				if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
1413 					strcat(str, t->tag->name);
1414 			} else
1415 				strcat(str, " {}");
1416 			break;
1417 		}
1418 	}
1419 	return fmtstrcpy(fp, str);
1420 }
1421 
1422 int
1423 FNconv(Fmt *fp)
1424 {
1425 	char *str;
1426 	Node *n;
1427 
1428 	n = va_arg(fp->args, Node*);
1429 	str = "<indirect>";
1430 	if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
1431 		str = n->sym->name;
1432 	return fmtstrcpy(fp, str);
1433 }
1434 
1435 int
1436 Qconv(Fmt *fp)
1437 {
1438 	char str[STRINGSZ+20], *s;
1439 	long b;
1440 	int i;
1441 
1442 	str[0] = 0;
1443 	for(b = va_arg(fp->args, long); b;) {
1444 		i = bitno(b);
1445 		if(str[0])
1446 			strcat(str, " ");
1447 		s = qnames[i];
1448 		if(strlen(str) + strlen(s) >= STRINGSZ)
1449 			break;
1450 		strcat(str, s);
1451 		b &= ~(1L << i);
1452 	}
1453 	return fmtstrcpy(fp, str);
1454 }
1455 
1456 int
1457 VBconv(Fmt *fp)
1458 {
1459 	char str[STRINGSZ];
1460 	int i, n, t, pc;
1461 
1462 	n = va_arg(fp->args, int);
1463 	pc = 0;	/* BUG: was printcol */
1464 	i = 0;
1465 	while(pc < n) {
1466 		t = (pc+4) & ~3;
1467 		if(t <= n) {
1468 			str[i++] = '\t';
1469 			pc = t;
1470 			continue;
1471 		}
1472 		str[i++] = ' ';
1473 		pc++;
1474 	}
1475 	str[i] = 0;
1476 
1477 	return fmtstrcpy(fp, str);
1478 }
1479 
1480 /*
1481  * real allocs
1482  */
1483 void*
1484 alloc(long n)
1485 {
1486 	void *p;
1487 
1488 	while((uintptr)hunk & MAXALIGN) {
1489 		hunk++;
1490 		nhunk--;
1491 	}
1492 	while(nhunk < n)
1493 		gethunk();
1494 	p = hunk;
1495 	nhunk -= n;
1496 	hunk += n;
1497 	return p;
1498 }
1499 
1500 void*
1501 allocn(void *p, long on, long n)
1502 {
1503 	void *q;
1504 
1505 	q = (uchar*)p + on;
1506 	if(q != hunk || nhunk < n) {
1507 		while(nhunk < on+n)
1508 			gethunk();
1509 		memmove(hunk, p, on);
1510 		p = hunk;
1511 		hunk += on;
1512 		nhunk -= on;
1513 	}
1514 	hunk += n;
1515 	nhunk -= n;
1516 	return p;
1517 }
1518 
1519 void
1520 setinclude(char *p)
1521 {
1522 	int i;
1523 	char *e;
1524 
1525 	while(*p != 0) {
1526 		e = strchr(p, ' ');
1527 		if(e != 0)
1528 			*e = '\0';
1529 
1530 		for(i=1; i < ninclude; i++)
1531 			if(strcmp(p, include[i]) == 0)
1532 				break;
1533 
1534 		if(i >= ninclude)
1535 			include[ninclude++] = p;
1536 
1537 		if(ninclude > nelem(include)) {
1538 			diag(Z, "ninclude too small %d", nelem(include));
1539 			exits("ninclude");
1540 		}
1541 
1542 		if(e == 0)
1543 			break;
1544 		p = e+1;
1545 	}
1546 }
1547