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