xref: /inferno-os/limbo/lex.c (revision 0195c4e25fc394097552c7f5ebf3085ec2d201f5)
1 #define Extern
2 #include "limbo.h"
3 #include "y.tab.h"
4 
5 enum
6 {
7 	Leof		= -1,
8 	Linestart	= 0,
9 
10 	Mlower		= 1,
11 	Mupper		= 2,
12 	Munder		= 4,
13 	Malpha		= Mupper|Mlower|Munder,
14 	Mdigit		= 8,
15 	Msign		= 16,
16 	Mexp		= 32,
17 	Mhex		= 64,
18 	Mradix		= 128,
19 
20 	HashSize	= 1024,
21 	MaxPath		= 4096
22 };
23 
24 typedef	struct Keywd	Keywd;
25 struct	Keywd
26 {
27 	char	*name;
28 	int	token;
29 };
30 
31 	File	**files;			/* files making up the module, sorted by absolute line */
32 	int	nfiles;
33 static	int	lenfiles;
34 static	int	lastfile;			/* index of last file looked up */
35 
36 static	char	*incpath[MaxIncPath];
37 static	Sym	*symbols[HashSize];
38 static	Sym	*strings[HashSize];
39 static	char	map[256];
40 static	Biobuf	*bin;
41 static	Line	linestack[MaxInclude];
42 static	int	lineno;
43 static	int	linepos;
44 static	int	bstack;
45 static	int	ineof;
46 static	int	lasttok;
47 static	YYSTYPE	lastyylval;
48 static	char	srcdir[MaxPath];
49 
50 static	Keywd	keywords[] =
51 {
52 	"adt",		Ladt,
53 	"alt",		Lalt,
54 	"array",	Larray,
55 	"big",		Ltid,
56 	"break",	Lbreak,
57 	"byte",		Ltid,
58 	"case",		Lcase,
59 	"chan",		Lchan,
60 	"con",		Lcon,
61 	"continue",	Lcont,
62 	"cyclic",	Lcyclic,
63 	"do",		Ldo,
64 	"dynamic",	Ldynamic,
65 	"else",		Lelse,
66 	"exception",	Lexcept,
67 	"exit",		Lexit,
68 	"fixed",	Lfix,
69 	"fn",		Lfn,
70 	"for",		Lfor,
71 	"hd",		Lhd,
72 	"if",		Lif,
73 	"implement",	Limplement,
74 	"import",	Limport,
75 	"include",	Linclude,
76 	"int",		Ltid,
77 	"len",		Llen,
78 	"list",		Llist,
79 	"load",		Lload,
80 	"module",	Lmodule,
81 	"nil",		Lnil,
82 	"of",		Lof,
83 	"or",		Lor,
84 	"pick",		Lpick,
85 	"raise",	Lraise,
86 	"raises",	Lraises,
87 	"real",		Ltid,
88 	"ref",		Lref,
89 	"return",	Lreturn,
90 	"self",		Lself,
91 	"spawn",	Lspawn,
92 	"string",	Ltid,
93 	"tagof",	Ltagof,
94 	"tl",		Ltl,
95 	"to",		Lto,
96 	"type",		Ltype,
97 	"while",	Lwhile,
98 	0,
99 };
100 
101 static	Keywd	tokwords[] =
102 {
103 	"&=",	Landeq,
104 	"|=",	Loreq,
105 	"^=",	Lxoreq,
106 	"<<=",	Llsheq,
107 	">>=",	Lrsheq,
108 	"+=",	Laddeq,
109 	"-=",	Lsubeq,
110 	"*=",	Lmuleq,
111 	"/=",	Ldiveq,
112 	"%=",	Lmodeq,
113 	"**=", Lexpeq,
114 	":=",	Ldeclas,
115 	"||",	Loror,
116 	"&&",	Landand,
117 	"::",	Lcons,
118 	"==",	Leq,
119 	"!=",	Lneq,
120 	"<=",	Lleq,
121 	">=",	Lgeq,
122 	"<<",	Llsh,
123 	">>",	Lrsh,
124 	"<-",	Lcomm,
125 	"++", Linc,
126 	"--",	Ldec,
127 	"->", Lmdot,
128 	"=>", Llabs,
129 	"**", Lexp,
130 	"EOF",	Leof,
131 	"eof",	Beof,
132 	0,
133 };
134 
135 void
lexinit(void)136 lexinit(void)
137 {
138 	Keywd *k;
139 	int i;
140 
141 	for(i = 0; i < 256; i++){
142 		if(i == '_' || i > 0xa0)
143 			map[i] |= Munder;
144 		if(i >= 'A' && i <= 'Z')
145 			map[i] |= Mupper;
146 		if(i >= 'a' && i <= 'z')
147 			map[i] |= Mlower;
148 		if(i >= 'A' && i <= 'F' || i >= 'a' && i <= 'f')
149 			map[i] |= Mhex;
150 		if(i == 'e' || i == 'E')
151 			map[i] |= Mexp;
152 		if(i == 'r' || i == 'R')
153 			map[i] |= Mradix;
154 		if(i == '-' || i == '+')
155 			map[i] |= Msign;
156 		if(i >= '0' && i <= '9')
157 			map[i] |= Mdigit;
158 	}
159 
160 	memset(escmap, -1, sizeof(escmap));
161 	escmap['\''] = '\'';
162 	unescmap['\''] = '\'';
163 	escmap['"'] = '"';
164 	unescmap['"'] = '"';
165 	escmap['\\'] = '\\';
166 	unescmap['\\'] = '\\';
167 	escmap['a'] = '\a';
168 	unescmap['\a'] = 'a';
169 	escmap['b'] = '\b';
170 	unescmap['\b'] = 'b';
171 	escmap['f'] = '\f';
172 	unescmap['\f'] = 'f';
173 	escmap['n'] = '\n';
174 	unescmap['\n'] = 'n';
175 	escmap['r'] = '\r';
176 	unescmap['\r'] = 'r';
177 	escmap['t'] = '\t';
178 	unescmap['\t'] = 't';
179 	escmap['v'] = '\v';
180 	unescmap['\v'] = 'v';
181 	escmap['0'] = '\0';
182 	unescmap['\0'] = '0';
183 
184 	for(k = keywords; k->name != nil; k++)
185 		enter(k->name, k->token);
186 }
187 
188 int
cmap(int c)189 cmap(int c)
190 {
191 	if(c<0)
192 		return 0;
193 	if(c<256)
194 		return map[c];
195 	return Mlower;
196 }
197 
198 void
lexstart(char * in)199 lexstart(char *in)
200 {
201 	char *p;
202 
203 	ineof = 0;
204 	bstack = 0;
205 	nfiles = 0;
206 	lastfile = 0;
207 	addfile(mkfile(strdup(in), 1, 0, -1, nil, 0, -1));
208 	bin = bins[bstack];
209 	lineno = 1;
210 	linepos = Linestart;
211 
212 	secpy(srcdir, srcdir+MaxPath, in);
213 	p = strrchr(srcdir, '/');
214 	if(p == nil)
215 		srcdir[0] = '\0';
216 	else
217 		p[1] = '\0';
218 }
219 
220 static int
Getc(void)221 Getc(void)
222 {
223 	int c;
224 
225 	if(ineof)
226 		return Beof;
227 	c = BGETC(bin);
228 	if(c == Beof)
229 		ineof = 1;
230 	linepos++;
231 	return c;
232 }
233 
234 static void
unGetc(void)235 unGetc(void)
236 {
237 	if(ineof)
238 		return;
239 	Bungetc(bin);
240 	linepos--;
241 }
242 
243 static int
getrune(void)244 getrune(void)
245 {
246 	int c;
247 
248 	if(ineof)
249 		return Beof;
250 	c = Bgetrune(bin);
251 	if(c == Beof)
252 		ineof = 1;
253 	linepos++;
254 	return c;
255 }
256 
257 static void
ungetrune(void)258 ungetrune(void)
259 {
260 	if(ineof)
261 		return;
262 	Bungetrune(bin);
263 	linepos--;
264 }
265 
266 void
addinclude(char * s)267 addinclude(char *s)
268 {
269 	int i;
270 
271 	for(i = 0; i < MaxIncPath; i++){
272 		if(incpath[i] == 0){
273 			incpath[i] = s;
274 			return;
275 		}
276 	}
277 	fatal("out of include path space");
278 }
279 
280 File*
mkfile(char * name,int abs,int off,int in,char * act,int actoff,int sbl)281 mkfile(char *name, int abs, int off, int in, char *act, int actoff, int sbl)
282 {
283 	File *f;
284 
285 	f = allocmem(sizeof *f);
286 	f->name = name;
287 	f->abs = abs;
288 	f->off = off;
289 	f->in = in;
290 	f->act = act;
291 	f->actoff = actoff;
292 	f->sbl = sbl;
293 	return f;
294 }
295 
296 int
addfile(File * f)297 addfile(File *f)
298 {
299 	if(nfiles >= lenfiles){
300 		lenfiles = nfiles+32;
301 		files = reallocmem(files, lenfiles*sizeof(File*));
302 	}
303 	files[nfiles] = f;
304 	return nfiles++;
305 }
306 
307 void
includef(Sym * file)308 includef(Sym *file)
309 {
310 	Biobuf *b;
311 	char *p, buf[MaxPath];
312 	int i;
313 
314 	linestack[bstack].line = lineno;
315 	linestack[bstack].pos = linepos;
316 	bstack++;
317 	if(bstack >= MaxInclude)
318 		fatal("%L: include file depth too great", curline());
319 	p = "";
320 	if(file->name[0] != '/')
321 		p = srcdir;
322 	seprint(buf, buf+sizeof(buf), "%s%s", p, file->name);
323 	b = Bopen(buf, OREAD);
324 	for(i = 0; b == nil && i < MaxIncPath && incpath[i] != nil && file->name[0] != '/'; i++){
325 		seprint(buf, buf+sizeof(buf), "%s/%s", incpath[i], file->name);
326 		b = Bopen(buf, OREAD);
327 	}
328 	bins[bstack] = b;
329 	if(bins[bstack] == nil){
330 		yyerror("can't include %s: %r", file->name);
331 		bstack--;
332 	}else{
333 		addfile(mkfile(strdup(buf), lineno+1, -lineno, lineno, nil, 0, -1));
334 		lineno++;
335 		linepos = Linestart;
336 	}
337 	bin = bins[bstack];
338 }
339 
340 /*
341  * we hit eof in the current file
342  * revert to the file which included it.
343  */
344 static void
popinclude(void)345 popinclude(void)
346 {
347 	Fline fl;
348 	File *f;
349 	int oline, opos, ln;
350 
351 	ineof = 0;
352 	bstack--;
353 	bin = bins[bstack];
354 	oline = linestack[bstack].line;
355 	opos = linestack[bstack].pos;
356 	fl = fline(oline);
357 	f =  fl.file;
358 	ln = fl.line;
359 	lineno++;
360 	linepos = opos;
361 	addfile(mkfile(f->name, lineno, ln-lineno, f->in, f->act, f->actoff, -1));
362 }
363 
364 /*
365  * convert an absolute Line into a file and line within the file
366  */
367 Fline
fline(int absline)368 fline(int absline)
369 {
370 	Fline fl;
371 	int l, r, m, s;
372 
373 	if(absline < files[lastfile]->abs
374 	|| lastfile+1 < nfiles && absline >= files[lastfile+1]->abs){
375 		lastfile = 0;
376 		l = 0;
377 		r = nfiles - 1;
378 		while(l <= r){
379 			m = (r + l) / 2;
380 			s = files[m]->abs;
381 			if(s <= absline){
382 				l = m + 1;
383 				lastfile = m;
384 			}else
385 				r = m - 1;
386 		}
387 	}
388 
389 	fl.file = files[lastfile];
390 	fl.line = absline + files[lastfile]->off;
391 	return fl;
392 }
393 
394 /*
395  * read a comment
396  */
397 static int
lexcom(void)398 lexcom(void)
399 {
400 	File *f;
401 	char buf[StrSize], *s, *t, *act;
402 	int i, n, c, actline;
403 
404 	i = 0;
405 	while((c = Getc()) != '\n'){
406 		if(c == Beof)
407 			return -1;
408 		if(i < sizeof(buf)-1)
409 			buf[i++] = c;
410 	}
411 	buf[i] = 0;
412 
413 	lineno++;
414 	linepos = Linestart;
415 
416 	if(strncmp(buf, "line ", 5) != 0 && strncmp(buf, "line\t", 5) != 0)
417 		return 0;
418 	for(s = buf+5; *s == ' ' || *s == '\t'; s++)
419 		;
420 	if(!(cmap(*s) & Mdigit))
421 		return 0;
422 	n = 0;
423 	for(; cmap(c = *s) & Mdigit; s++)
424 		n = n * 10 + c - '0';
425 	for(; *s == ' ' || *s == '\t'; s++)
426 		;
427 	if(*s != '"')
428 		return 0;
429 	s++;
430 	t = strchr(s, '"');
431 	if(t == nil || t[1] != '\0')
432 		return 0;
433 	*t = '\0';
434 
435 	f = files[nfiles - 1];
436 	if(n == f->off+lineno && strcmp(s, f->name) == 0)
437 		return 1;
438 	act = f->name;
439 	actline = lineno + f->off;
440 	if(f->act != nil){
441 		actline += f->actoff;
442 		act = f->act;
443 	}
444 	addfile(mkfile(strdup(s), lineno, n-lineno, f->in, act, actline - n, -1));
445 
446 	return 1;
447 }
448 
449 Line
curline(void)450 curline(void)
451 {
452 	Line line;
453 
454 	line.line = lineno;
455 	line.pos = linepos;
456 	return line;
457 }
458 
459 int
lineconv(Fmt * f)460 lineconv(Fmt *f)
461 {
462 	Fline fl;
463 	File *file;
464 	Line inl, line;
465 	char buf[StrSize], *s;
466 
467 	line = va_arg(f->args, Line);
468 
469 	if(line.line < 0)
470 		return fmtstrcpy(f, "<noline>");
471 	fl = fline(line.line);
472 	file = fl.file;
473 
474 	s = seprint(buf, buf+sizeof(buf), "%s:%d", file->name, fl.line);
475 	if(file->act != nil)
476 		s = seprint(s, buf+sizeof(buf), " [ %s:%d ]", file->act, file->actoff+fl.line);
477 	if(file->in >= 0){
478 		inl.line = file->in;
479 		inl.pos = 0;
480 		seprint(s, buf+sizeof(buf), ": %L", inl);
481 	}
482 	return fmtstrcpy(f, buf);
483 }
484 
485 static char*
posconv(char * s,char * e,Line line)486 posconv(char *s, char *e, Line line)
487 {
488 	Fline fl;
489 
490 	if(line.line < 0)
491 		return secpy(s, e, "nopos");
492 
493 	fl = fline(line.line);
494 	return seprint(s, e, "%s:%d.%d", fl.file->name, fl.line, line.pos);
495 }
496 
497 int
srcconv(Fmt * f)498 srcconv(Fmt *f)
499 {
500 	Src src;
501 	char buf[StrSize], *s;
502 
503 	src = va_arg(f->args, Src);
504 	s = posconv(buf, buf+sizeof(buf), src.start);
505 	s = secpy(s, buf+sizeof(buf), ",");
506 	posconv(s, buf+sizeof(buf), src.stop);
507 
508 	return fmtstrcpy(f, buf);
509 }
510 
511 int
lexid(int c)512 lexid(int c)
513 {
514 	Sym *sym;
515 	char id[StrSize*UTFmax+1], *p;
516 	Rune r;
517 	int i, t;
518 
519 	p = id;
520 	i = 0;
521 	for(;;){
522 		if(i < StrSize){
523 			if(c < Runeself)
524 				*p++ = c;
525 			else{
526 				r = c;
527 				p += runetochar(p, &r);
528 			}
529 			i++;
530 		}
531 		c = getrune();
532 		if(c == Beof
533 		|| !(cmap(c) & (Malpha|Mdigit))){
534 			ungetrune();
535 			break;
536 		}
537 	}
538 	*p = '\0';
539 	sym = enter(id, Lid);
540 	t = sym->token;
541 	if(t == Lid || t == Ltid)
542 		yylval.tok.v.idval = sym;
543 	return t;
544 }
545 
546 Long
strtoi(char * t,int base)547 strtoi(char *t, int base)
548 {
549 	char *s;
550 	Long v;
551 	int c, neg, ck;
552 
553 	neg = 0;
554 	if(t[0] == '-'){
555 		neg = 1;
556 		t++;
557 	}else if(t[0] == '+')
558 		t++;
559 	v = 0;
560 	for(s = t; c = *s; s++){
561 		ck = cmap(c);
562 		if(ck & Mdigit)
563 			c -= '0';
564 		else if(ck & Mlower)
565 			c = c - 'a' + 10;
566 		else if(ck & Mupper)
567 			c = c - 'A' + 10;
568 		if(c >= base){
569 			yyerror("digit '%c' not radix %d", *s, base);
570 			return -1;
571 		}
572 		v = v * base + c;
573 	}
574 	if(neg)
575 		return -v;
576 	return v;
577 }
578 
579 static int
digit(int c,int base)580 digit(int c, int base)
581 {
582 	int cc, ck;
583 
584 	cc = c;
585 	ck = cmap(c);
586 	if(ck & Mdigit)
587 		c -= '0';
588 	else if(ck & Mlower)
589 		c = c - 'a' + 10;
590 	else if(ck & Mupper)
591 		c = c - 'A' + 10;
592 	else if(ck & Munder)
593 		{}
594 	else
595 		return -1;
596 	if(c >= base)
597 		yyerror("digit '%c' not radix %d", cc, base);
598 	return c;
599 }
600 
601 double
strtodb(char * t,int base)602 strtodb(char *t, int base)
603 {
604 	double num, dem;
605 	int neg, eneg, dig, exp, c, d;
606 
607 	num = 0;
608 	neg = 0;
609 	dig = 0;
610 	exp = 0;
611 	eneg = 0;
612 
613 	c = *t++;
614 	if(c == '-' || c == '+'){
615 		if(c == '-')
616 			neg = 1;
617 		c = *t++;
618 	}
619 	while((d = digit(c, base)) >= 0){
620 		num = num*base + d;
621 		c = *t++;
622 	}
623 	if(c == '.')
624 		c = *t++;
625 	while((d = digit(c, base)) >= 0){
626 		num = num*base + d;
627 		dig++;
628 		c = *t++;
629 	}
630 	if(c == 'e' || c == 'E'){
631 		c = *t++;
632 		if(c == '-' || c == '+'){
633 			if(c == '-'){
634 				dig = -dig;
635 				eneg = 1;
636 			}
637 			c = *t++;
638 		}
639 		while((d = digit(c, base)) >= 0){
640 			exp = exp*base + d;
641 			c = *t++;
642 		}
643 	}
644 	exp -= dig;
645 	if(exp < 0){
646 		exp = -exp;
647 		eneg = !eneg;
648 	}
649 	dem = rpow(base, exp);
650 	if(eneg)
651 		num /= dem;
652 	else
653 		num *= dem;
654 	if(neg)
655 		return -num;
656 	return num;
657 }
658 
659 /*
660  * parse a numeric identifier
661  * format [0-9]+(r[0-9A-Za-z]+)?
662  * or ([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?
663  */
664 int
lexnum(int c)665 lexnum(int c)
666 {
667 	char buf[StrSize], *base;
668 	enum { Int, Radix, RadixSeen, Frac, ExpSeen, ExpSignSeen, Exp, FracB } state;
669 	double d;
670 	Long v;
671 	int i, ck;
672 
673 	i = 0;
674 	buf[i++]  = c;
675 	state = Int;
676 	if(c == '.')
677 		state = Frac;
678 	base = nil;
679 	for(;;){
680 		c = Getc();
681 		if(c == Beof){
682 			yyerror("end of file in numeric constant");
683 			return Leof;
684 		}
685 
686 		ck = cmap(c);
687 		switch(state){
688 		case Int:
689 			if(ck & Mdigit)
690 				break;
691 			if(ck & Mexp){
692 				state = ExpSeen;
693 				break;
694 			}
695 			if(ck & Mradix){
696 				base = &buf[i];
697 				state = RadixSeen;
698 				break;
699 			}
700 			if(c == '.'){
701 				state = Frac;
702 				break;
703 			}
704 			goto done;
705 		case RadixSeen:
706 		case Radix:
707 			if(ck & (Mdigit|Malpha)){
708 				state = Radix;
709 				break;
710 			}
711 			if(c == '.'){
712 				state = FracB;
713 				break;
714 			}
715 			goto done;
716 		case Frac:
717 			if(ck & Mdigit)
718 				break;
719 			if(ck & Mexp)
720 				state = ExpSeen;
721 			else
722 				goto done;
723 			break;
724 		case FracB:
725 			if(ck & (Mdigit|Malpha))
726 				break;
727 			goto done;
728 		case ExpSeen:
729 			if(ck & Msign){
730 				state = ExpSignSeen;
731 				break;
732 			}
733 			/* fall through */
734 		case ExpSignSeen:
735 		case Exp:
736 			if(ck & Mdigit){
737 				state = Exp;
738 				break;
739 			}
740 			goto done;
741 		}
742 		if(i < StrSize-1)
743 			buf[i++] = c;
744 	}
745 done:
746 	buf[i] = 0;
747 	unGetc();
748 	switch(state){
749 	default:
750 		yyerror("malformed numerical constant '%s'", buf);
751 		yylval.tok.v.ival = 0;
752 		return Lconst;
753 	case Radix:
754 		*base++ = '\0';
755 		v = strtoi(buf, 10);
756 		if(v < 0)
757 			break;
758 		if(v < 2 || v > 36){
759 			yyerror("radix '%s' must be between 2 and 36", buf);
760 			break;
761 		}
762 		v = strtoi(base, v);
763 		break;
764 	case Int:
765 		v = strtoi(buf, 10);
766 		break;
767 	case Frac:
768 	case Exp:
769 		d = strtod(buf, nil);
770 		yylval.tok.v.rval = d;
771 		return Lrconst;
772 	case FracB:
773 		*base++ = '\0';
774 		v = strtoi(buf, 10);
775 		if(v < 0)
776 			break;
777 		if(v < 2 || v > 36){
778 			yyerror("radix '%s' must be between 2 and 36", buf);
779 			break;
780 		}
781 		d = strtodb(base, v);
782 		yylval.tok.v.rval = d;
783 		return Lrconst;
784 	}
785 	yylval.tok.v.ival = v;
786 	return Lconst;
787 }
788 
789 int
escchar(void)790 escchar(void)
791 {
792 	char buf[4+1];
793 	int c, i;
794 
795 	c = getrune();
796 	if(c == Beof)
797 		return Beof;
798 	if(c == 'u'){
799 		for(i = 0; i < 4; i++){
800 			c = getrune();
801 			if(c == Beof || !(cmap(c) & (Mdigit|Mhex))){
802 				yyerror("malformed \\u escape sequence");
803 				ungetrune();
804 				break;
805 			}
806 			buf[i] = c;
807 		}
808 		buf[i] = 0;
809 		return strtoul(buf, 0, 16);
810 	}
811 	if(c < 256 && (i = escmap[c]) >= 0)
812 		return i;
813 	yyerror("unrecognized escape \\%C", c);
814 	return c;
815 }
816 
817 void
lexstring(int israw)818 lexstring(int israw)
819 {
820 	char *str;
821 	int c, t, startlno;
822 	Rune r;
823 	int len, alloc;
824 
825 	alloc = 32;
826 	len = 0;
827 	str = allocmem(alloc * sizeof(str));
828 	startlno = lineno;
829 	for(;;){
830 		c = getrune();
831 		if(israw){
832 			switch(c){
833 			case '`':
834 				yylval.tok.v.idval = enterstring(str, len);
835 				return;
836 			case '\n':
837 				lineno++;
838 				linepos = Linestart;
839 				break;
840 			case Beof:
841 				t = lineno;
842 				lineno = startlno;
843 				yyerror("end of file in raw string constant");
844 				lineno = t;
845 				yylval.tok.v.idval = enterstring(str, len);
846 				return;
847 			}
848 		}else{
849 			switch(c){
850 			case '\\':
851 				c = escchar();
852 				if(c != Beof)
853 					break;
854 				/* fall through */
855 			case Beof:
856 				yyerror("end of file in string constant");
857 				yylval.tok.v.idval = enterstring(str, len);
858 				return;
859 			case '\n':
860 				yyerror("newline in string constant");
861 				lineno++;
862 				linepos = Linestart;
863 				yylval.tok.v.idval = enterstring(str, len);
864 				return;
865 			case '"':
866 				yylval.tok.v.idval = enterstring(str, len);
867 				return;
868 			}
869 		}
870 		while(len+UTFmax+1 >= alloc){
871 			alloc += 32;
872 			str = reallocmem(str, alloc * sizeof(str));
873 		}
874 		r = c;
875 		len += runetochar(&str[len], &r);
876 		str[len] = '\0';
877 	}
878 }
879 
880 static int
lex(void)881 lex(void)
882 {
883 	int c;
884 
885 loop:
886 	yylval.tok.src.start.line = lineno;
887 	yylval.tok.src.start.pos = linepos;
888 	c = getrune(); /* ehg: outside switch() to avoid bug in VisualC++5.0 */
889 	switch(c){
890 	case Beof:
891 		Bterm(bin);
892 		if(bstack == 0)
893 			return Leof;
894 		popinclude();
895 		break;
896 	case '#':
897 		if(lexcom() < 0){
898 			Bterm(bin);
899 			if(bstack == 0)
900 				return Leof;
901 			popinclude();
902 		}
903 		break;
904 
905 	case '\n':
906 		lineno++;
907 		linepos = Linestart;
908 		goto loop;
909 	case ' ':
910 	case '\t':
911 	case '\r':
912 	case '\v':
913 	case '\f':
914 		goto loop;
915 	case '"':
916 		lexstring(0);
917 		return Lsconst;
918 	case '`':
919 		lexstring(1);
920 		return Lsconst;
921 	case '\'':
922 		c = getrune();
923 		if(c == '\\')
924 			c = escchar();
925 		if(c == Beof){
926 			yyerror("end of file in character constant");
927 			return Beof;
928 		}else
929 			yylval.tok.v.ival = c;
930 		c = Getc();
931 		if(c != '\'') {
932 			yyerror("missing closing '");
933 			unGetc();
934 		}
935 		return Lconst;
936 	case '(':
937 	case ')':
938 	case '[':
939 	case ']':
940 	case '{':
941 	case '}':
942 	case ',':
943 	case ';':
944 	case '~':
945 		return c;
946 
947 	case ':':
948 		c = Getc();
949 		if(c == ':')
950 			return Lcons;
951 		if(c == '=')
952 			return Ldeclas;
953 		unGetc();
954 		return ':';
955 
956 	case '.':
957 		c = Getc();
958 		unGetc();
959 		if(c != Beof && (cmap(c) & Mdigit))
960 			return lexnum('.');
961 		return '.';
962 
963 	case '|':
964 		c = Getc();
965 		if(c == '=')
966 			return Loreq;
967 		if(c == '|')
968 			return Loror;
969 		unGetc();
970 		return '|';
971 
972 	case '&':
973 		c = Getc();
974 		if(c == '=')
975 			return Landeq;
976 		if(c == '&')
977 			return Landand;
978 		unGetc();
979 		return '&';
980 
981 	case '^':
982 		c = Getc();
983 		if(c == '=')
984 			return Lxoreq;
985 		unGetc();
986 		return '^';
987 
988 	case '*':
989 		c = Getc();
990 		if(c == '=')
991 			return Lmuleq;
992 		if(c == '*'){
993 			c = Getc();
994 			if(c == '=')
995 				return Lexpeq;
996 			unGetc();
997 			return Lexp;
998 		}
999 		unGetc();
1000 		return '*';
1001 	case '/':
1002 		c = Getc();
1003 		if(c == '=')
1004 			return Ldiveq;
1005 		unGetc();
1006 		return '/';
1007 	case '%':
1008 		c = Getc();
1009 		if(c == '=')
1010 			return Lmodeq;
1011 		unGetc();
1012 		return '%';
1013 	case '=':
1014 		c = Getc();
1015 		if(c == '=')
1016 			return Leq;
1017 		if(c == '>')
1018 			return Llabs;
1019 		unGetc();
1020 		return '=';
1021 	case '!':
1022 		c = Getc();
1023 		if(c == '=')
1024 			return Lneq;
1025 		unGetc();
1026 		return '!';
1027 	case '>':
1028 		c = Getc();
1029 		if(c == '=')
1030 			return Lgeq;
1031 		if(c == '>'){
1032 			c = Getc();
1033 			if(c == '=')
1034 				return Lrsheq;
1035 			unGetc();
1036 			return Lrsh;
1037 		}
1038 		unGetc();
1039 		return '>';
1040 
1041 	case '<':
1042 		c = Getc();
1043 		if(c == '=')
1044 			return Lleq;
1045 		if(c == '-')
1046 			return Lcomm;
1047 		if(c == '<'){
1048 			c = Getc();
1049 			if(c == '=')
1050 				return Llsheq;
1051 			unGetc();
1052 			return Llsh;
1053 		}
1054 		unGetc();
1055 		return '<';
1056 
1057 	case '+':
1058 		c = Getc();
1059 		if(c == '=')
1060 			return Laddeq;
1061 		if(c == '+')
1062 			return Linc;
1063 		unGetc();
1064 		return '+';
1065 
1066 	case '-':
1067 		c = Getc();
1068 		if(c == '=')
1069 			return Lsubeq;
1070 		if(c == '-')
1071 			return Ldec;
1072 		if(c == '>')
1073 			return Lmdot;
1074 		unGetc();
1075 		return '-';
1076 
1077 	case '1': case '2': case '3': case '4': case '5':
1078 	case '0': case '6': case '7': case '8': case '9':
1079 		return lexnum(c);
1080 
1081 	default:
1082 		if(cmap(c) & Malpha)
1083 			return lexid(c);
1084 		yyerror("unknown character %c", c);
1085 		break;
1086 	}
1087 	goto loop;
1088 }
1089 
1090 int
yylex(void)1091 yylex(void)
1092 {
1093 	int t;
1094 
1095 	t = lex();
1096 	yylval.tok.src.stop.line = lineno;
1097 	yylval.tok.src.stop.pos = linepos;
1098 	lasttok = t;
1099 	lastyylval = yylval;
1100 	return t;
1101 }
1102 
1103 static char*
toksp(int t)1104 toksp(int t)
1105 {
1106 	Keywd *k;
1107 	static char buf[256];
1108 
1109 	switch(t){
1110 		case Lconst:
1111 			snprint(buf, sizeof(buf), "%lld", lastyylval.tok.v.ival);
1112 			return buf;
1113 		case Lrconst:
1114 			snprint(buf, sizeof(buf), "%f", lastyylval.tok.v.rval);
1115 			return buf;
1116 		case Lsconst:
1117 			snprint(buf, sizeof(buf), "\"%s\"", lastyylval.tok.v.idval->name);
1118 			return buf;
1119 		case Ltid:
1120 		case Lid:
1121 			return lastyylval.tok.v.idval->name;
1122 	}
1123 	for(k = keywords; k->name != nil; k++)
1124 		if(t == k->token)
1125 			return k->name;
1126 	for(k = tokwords; k->name != nil; k++)
1127 		if(t == k->token)
1128 			return k->name;
1129 	if(t < 0 || t > 255)
1130 		fatal("bad token %d in toksp()", t);
1131 	buf[0] = t;
1132 	buf[1] = '\0';
1133 	return buf;
1134 }
1135 
1136 Sym*
enterstring(char * str,int n)1137 enterstring(char *str, int n)
1138 {
1139 	Sym *s;
1140 	char *p, *e;
1141 	ulong h;
1142 	int c, c0;
1143 
1144 	e = str + n;
1145 	h = 0;
1146 	for(p = str; p < e; p++){
1147 		c = *p;
1148 		c ^= c << 6;
1149 		h += (c << 11) ^ (c >> 1);
1150 		c = *p;
1151 		h ^= (c << 14) + (c << 7) + (c << 4) + c;
1152 	}
1153 
1154 	c0 = str[0];
1155 	h %= HashSize;
1156 	for(s = strings[h]; s != nil; s = s->next){
1157 		if(s->name[0] == c0 && s->len == n && memcmp(s->name, str, n) == 0){
1158 			free(str);
1159 			return s;
1160 		}
1161 	}
1162 
1163 	if(n == 0)
1164 		return enter("", 0);
1165 
1166 	s = allocmem(sizeof(Sym));
1167 	memset(s, 0, sizeof(Sym));
1168 	s->name = str;
1169 	s->len = n;
1170 	s->next = strings[h];
1171 	strings[h] = s;
1172 	return s;
1173 }
1174 
1175 int
symcmp(Sym * s,Sym * t)1176 symcmp(Sym *s, Sym *t)
1177 {
1178 	int n, c;
1179 
1180 	n = s->len;
1181 	if(n > t->len)
1182 		n = t->len;
1183 	c = memcmp(s->name, t->name, n);
1184 	if(c == 0)
1185 		return s->len - t->len;
1186 	return c;
1187 }
1188 
1189 Sym*
stringcat(Sym * s,Sym * t)1190 stringcat(Sym *s, Sym *t)
1191 {
1192 	char *str;
1193 	int n;
1194 
1195 	n = s->len + t->len;
1196 	str = allocmem(n+1);
1197 	memmove(str, s->name, s->len);
1198 	memmove(str+s->len, t->name, t->len);
1199 	str[n] = '\0';
1200 	return enterstring(str, n);
1201 }
1202 
1203 Sym*
enter(char * name,int token)1204 enter(char *name, int token)
1205 {
1206 	Sym *s;
1207 	char *p;
1208 	ulong h;
1209 	int c0, c, n;
1210 
1211 	c0 = name[0];
1212 	h = 0;
1213 	for(p = name; c = *p; p++){
1214 		c ^= c << 6;
1215 		h += (c << 11) ^ (c >> 1);
1216 		c = *p;
1217 		h ^= (c << 14) + (c << 7) + (c << 4) + c;
1218 	}
1219 	n = p - name;
1220 
1221 	h %= HashSize;
1222 	for(s = symbols[h]; s != nil; s = s->next)
1223 		if(s->name[0] == c0 && strcmp(s->name, name) == 0)
1224 			return s;
1225 
1226 	s = allocmem(sizeof(Sym));
1227 	memset(s, 0, sizeof(Sym));
1228 	s->hash = h;
1229 	s->name = allocmem(n+1);
1230 	memmove(s->name, name, n+1);
1231 	if(token == 0)
1232 		token = Lid;
1233 	s->token = token;
1234 	s->next = symbols[h];
1235 	s->len = n;
1236 	symbols[h] = s;
1237 	return s;
1238 }
1239 
1240 char*
stringpr(char * buf,char * end,Sym * sym)1241 stringpr(char *buf, char *end, Sym *sym)
1242 {
1243 	char sb[30], *s, *p;
1244 	int i, c, n;
1245 
1246 	s = sym->name;
1247 	n = sym->len;
1248 	if(n > 10)
1249 		n = 10;
1250 	p = sb;
1251 	*p++ = '"';
1252 	for(i = 0; i < n; i++){
1253 		c = s[i];
1254 		switch(c){
1255 		case '\\':
1256 		case '"':
1257 		case '\n':
1258 		case '\r':
1259 		case '\t':
1260 		case '\b':
1261 		case '\a':
1262 		case '\v':
1263 		case '\0':
1264 			*p++ = '\\';
1265 			*p++ = unescmap[c];
1266 			break;
1267 		default:
1268 			*p++ = c;
1269 			break;
1270 		}
1271 	}
1272 	if(n != sym->len){
1273 		*p++ = '.';
1274 		*p++ = '.';
1275 		*p++ = '.';
1276 	}
1277 	*p++ = '"';
1278 	*p = 0;
1279 	return secpy(buf, end, sb);
1280 }
1281 
1282 void
warn(Line line,char * fmt,...)1283 warn(Line line, char *fmt, ...)
1284 {
1285 	char buf[4096];
1286 	va_list arg;
1287 
1288 	if(errors || !dowarn)
1289 		return;
1290 	va_start(arg, fmt);
1291 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1292 	va_end(arg);
1293 	fprint(2, "%L: warning: %s\n", line, buf);
1294 }
1295 
1296 void
nwarn(Node * n,char * fmt,...)1297 nwarn(Node *n, char *fmt, ...)
1298 {
1299 	char buf[4096];
1300 	va_list arg;
1301 
1302 	if(errors || !dowarn)
1303 		return;
1304 	va_start(arg, fmt);
1305 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1306 	va_end(arg);
1307 	fprint(2, "%L: warning: %s\n", n->src.start, buf);
1308 }
1309 
1310 void
error(Line line,char * fmt,...)1311 error(Line line, char *fmt, ...)
1312 {
1313 	char buf[4096];
1314 	va_list arg;
1315 
1316 	errors++;
1317 	if(errors >= maxerr){
1318 		if(errors == maxerr)
1319 			fprint(2, "too many errors, stopping\n");
1320 		return;
1321 	}
1322 	va_start(arg, fmt);
1323 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1324 	va_end(arg);
1325 	fprint(2, "%L: %s\n", line, buf);
1326 }
1327 
1328 void
nerror(Node * n,char * fmt,...)1329 nerror(Node *n, char *fmt, ...)
1330 {
1331 	char buf[4096];
1332 	va_list arg;
1333 
1334 	errors++;
1335 	if(errors >= maxerr){
1336 		if(errors == maxerr)
1337 			fprint(2, "too many errors, stopping\n");
1338 		return;
1339 	}
1340 	va_start(arg, fmt);
1341 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1342 	va_end(arg);
1343 	fprint(2, "%L: %s\n", n->src.start, buf);
1344 }
1345 
1346 void
yyerror(char * fmt,...)1347 yyerror(char *fmt, ...)
1348 {
1349 	char buf[4096];
1350 	va_list arg;
1351 
1352 	errors++;
1353 	if(errors >= maxerr){
1354 		if(errors == maxerr)
1355 			fprint(2, "too many errors, stopping\n");
1356 		return;
1357 	}
1358 	va_start(arg, fmt);
1359 	vseprint(buf, buf+sizeof(buf), fmt, arg);
1360 	va_end(arg);
1361 	if(lasttok != 0)
1362 		fprint(2, "%L: near ` %s ` : %s\n", curline(), toksp(lasttok), buf);
1363 	else
1364 		fprint(2, "%L: %s\n", curline(), buf);
1365 }
1366 
1367 void
fatal(char * fmt,...)1368 fatal(char *fmt, ...)
1369 {
1370 	char buf[4096];
1371 	va_list arg;
1372 
1373 	if(errors == 0 || isfatal){
1374 		va_start(arg, fmt);
1375 		vseprint(buf, buf+sizeof(buf), fmt, arg);
1376 		va_end(arg);
1377 		fprint(2, "fatal limbo compiler error: %s\n", buf);
1378 	}
1379 	if(bout != nil)
1380 		remove(outfile);
1381 	if(bsym != nil)
1382 		remove(symfile);
1383 	if(isfatal)
1384 		abort();
1385 	exits(buf);
1386 }
1387 
1388 int
gfltconv(Fmt * f)1389 gfltconv(Fmt *f)
1390 {
1391 	double d;
1392 	char buf[32];
1393 
1394 	d = va_arg(f->args, double);
1395 	g_fmt(buf, d, 'e');
1396 	return fmtstrcpy(f, buf);
1397 }
1398 
1399 char*
secpy(char * p,char * e,char * s)1400 secpy(char *p, char *e, char *s)
1401 {
1402 	int c;
1403 
1404 	if(p == e){
1405 		p[-1] = '\0';
1406 		return p;
1407 	}
1408 	for(; c = *s; s++){
1409 		*p++ = c;
1410 		if(p == e){
1411 			p[-1] = '\0';
1412 			return p;
1413 		}
1414 	}
1415 	*p = '\0';
1416 	return p;
1417 }
1418 
1419 char*
seprint(char * buf,char * end,char * fmt,...)1420 seprint(char *buf, char *end, char *fmt, ...)
1421 {
1422 	va_list arg;
1423 
1424 	if(buf == end)
1425 		return buf;
1426 	va_start(arg, fmt);
1427 	buf = vseprint(buf, end, fmt, arg);
1428 	va_end(arg);
1429 	return buf;
1430 }
1431 
1432 void*
allocmem(ulong n)1433 allocmem(ulong n)
1434 {
1435 	void *p;
1436 
1437 	p = malloc(n != 0? n: 1);
1438 	if(p == nil)
1439 		fatal("out of memory");
1440 	return p;
1441 }
1442 
1443 void*
reallocmem(void * p,ulong n)1444 reallocmem(void *p, ulong n)
1445 {
1446 	if(p == nil)
1447 		p = malloc(n);
1448 	else
1449 		p = realloc(p, n);
1450 	if(p == nil)
1451 		fatal("out of memory");
1452 	return p;
1453 }
1454