Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <mach.h>
6 #define Extern extern
7 #include "acid.h"
8 #include "y.tab.h"
10 struct keywd
11 {
12 char *name;
13 int terminal;
14 }
15 keywds[] =
16 {
17 "do", Tdo,
18 "if", Tif,
19 "then", Tthen,
20 "else", Telse,
21 "while", Twhile,
22 "loop", Tloop,
23 "head", Thead,
24 "tail", Ttail,
25 "append", Tappend,
26 "defn", Tfn,
27 "return", Tret,
28 "local", Tlocal,
29 "aggr", Tcomplex,
30 "union", Tcomplex,
31 "adt", Tcomplex,
32 "complex", Tcomplex,
33 "delete", Tdelete,
34 "whatis", Twhat,
35 "eval", Teval,
36 "builtin", Tbuiltin,
37 0, 0
38 };
40 char cmap[256];
42 void
43 initcmap(void)
44 {
45 cmap['0']= '\0'+1;
46 cmap['n']= '\n'+1;
47 cmap['r']= '\r'+1;
48 cmap['t']= '\t'+1;
49 cmap['b']= '\b'+1;
50 cmap['f']= '\f'+1;
51 cmap['a']= '\a'+1;
52 cmap['v']= '\v'+1;
53 cmap['\\']= '\\'+1;
54 cmap['"']= '"'+1;
55 }
57 void
58 kinit(void)
59 {
60 int i;
62 initcmap();
64 for(i = 0; keywds[i].name; i++)
65 enter(keywds[i].name, keywds[i].terminal);
66 }
68 typedef struct IOstack IOstack;
69 struct IOstack
70 {
71 char *name;
72 int line;
73 char *text;
74 char *ip;
75 Biobuf *fin;
76 IOstack *prev;
77 };
78 IOstack *lexio;
79 uint nlexio;
81 void
82 setacidfile(void)
83 {
84 char *name;
85 Lsym *l;
87 if(lexio)
88 name = lexio->name;
89 else
90 name = "";
91 l = mkvar("acidfile");
92 l->v->set = 1;
93 l->v->store.fmt = 's';
94 l->v->type = TSTRING;
95 l->v->store.u.string = strnode(name);
96 }
98 void
99 pushfile(char *file)
101 Biobuf *b;
102 IOstack *io;
104 if(nlexio > 64)
105 error("too many includes");
107 if(file)
108 b = Bopen(file, OREAD);
109 else{
110 b = Bopen(unsharp("#d/0"), OREAD);
111 file = "<stdin>";
114 if(b == 0)
115 error("pushfile: %s: %r", file);
117 io = malloc(sizeof(IOstack));
118 if(io == 0)
119 fatal("no memory");
120 io->name = strdup(file);
121 if(io->name == 0)
122 fatal("no memory");
123 io->line = line;
124 line = 1;
125 io->text = 0;
126 io->fin = b;
127 io->prev = lexio;
128 lexio = io;
129 nlexio++;
130 setacidfile();
133 void
134 pushfd(int fd)
136 pushfile("/dev/null");
137 close(lexio->fin->fid);
138 free(lexio->name);
139 lexio->name = smprint("<fd#d>", fd);
140 lexio->fin->fid = fd;
143 void
144 pushstr(Node *s)
146 IOstack *io;
148 io = malloc(sizeof(IOstack));
149 if(io == 0)
150 fatal("no memory");
151 io->line = line;
152 line = 1;
153 io->name = strdup("<string>");
154 if(io->name == 0)
155 fatal("no memory");
156 io->line = line;
157 line = 1;
158 io->text = strdup(s->store.u.string->string);
159 if(io->text == 0)
160 fatal("no memory");
161 io->ip = io->text;
162 io->fin = 0;
163 io->prev = lexio;
164 nlexio++;
165 lexio = io;
166 setacidfile();
169 void
170 restartio(void)
172 Bflush(lexio->fin);
173 Binit(lexio->fin, 0, OREAD);
176 int
177 popio(void)
179 IOstack *s;
181 if(lexio == 0)
182 return 0;
184 if(lexio->prev == 0){
185 if(lexio->fin)
186 restartio();
187 return 0;
190 if(lexio->fin)
191 Bterm(lexio->fin);
192 else
193 free(lexio->text);
194 free(lexio->name);
195 line = lexio->line;
196 s = lexio;
197 lexio = s->prev;
198 free(s);
199 nlexio--;
200 setacidfile();
201 return 1;
204 int
205 Zfmt(Fmt *f)
207 char buf[1024], *p;
208 IOstack *e;
210 e = lexio;
211 if(e) {
212 p = seprint(buf, buf+sizeof buf, "%s:%d", e->name, line);
213 while(e->prev) {
214 e = e->prev;
215 if(initialising && e->prev == 0)
216 break;
217 p = seprint(p, buf+sizeof buf, " [%s:%d]", e->name, e->line);
219 } else
220 sprint(buf, "no file:0");
221 fmtstrcpy(f, buf);
222 return 0;
225 void
226 unlexc(int s)
228 if(s == '\n')
229 line--;
231 if(lexio->fin)
232 Bungetc(lexio->fin);
233 else
234 lexio->ip--;
237 int
238 lexc(void)
240 int c;
242 if(lexio->fin) {
243 c = Bgetc(lexio->fin);
244 if(gotint)
245 error("interrupt");
246 return c;
249 c = *lexio->ip++;
250 if(c == 0)
251 return -1;
252 return c;
255 int
256 escchar(int c)
258 int n;
259 char buf[Strsize];
261 if(c >= '0' && c <= '9') {
262 n = 1;
263 buf[0] = c;
264 for(;;) {
265 c = lexc();
266 if(c == Eof)
267 error("%d: <eof> in escape sequence", line);
268 if(strchr("0123456789xX", c) == 0) {
269 unlexc(c);
270 break;
272 buf[n++] = c;
274 buf[n] = '\0';
275 return strtol(buf, 0, 0);
278 n = cmap[(unsigned char)c];
279 if(n == 0)
280 return c;
281 return n-1;
284 void
285 eatstring(void)
287 int esc, c, cnt;
288 char buf[Strsize];
290 esc = 0;
291 for(cnt = 0;;) {
292 c = lexc();
293 switch(c) {
294 case Eof:
295 error("%d: <eof> in string constant", line);
297 case '\n':
298 error("newline in string constant");
299 goto done;
301 case '\\':
302 if(esc)
303 goto Default;
304 esc = 1;
305 break;
307 case '"':
308 if(esc == 0)
309 goto done;
311 /* Fall through */
312 default:
313 Default:
314 if(esc) {
315 c = escchar(c);
316 esc = 0;
318 buf[cnt++] = c;
319 break;
321 if(cnt >= Strsize)
322 error("string token too long");
324 done:
325 buf[cnt] = '\0';
326 yylval.string = strnode(buf);
329 void
330 eatnl(void)
332 int c;
334 line++;
335 for(;;) {
336 c = lexc();
337 if(c == Eof)
338 error("eof in comment");
339 if(c == '\n')
340 return;
344 int
345 yylex(void)
347 int c;
348 extern char vfmt[];
350 loop:
351 Bflush(bout);
352 c = lexc();
353 switch(c) {
354 case Eof:
355 if(gotint) {
356 gotint = 0;
357 stacked = 0;
358 Bprint(bout, "\nacid; ");
359 goto loop;
361 return Eof;
363 case '"':
364 eatstring();
365 return Tstring;
367 case ' ':
368 case '\t':
369 goto loop;
371 case '\n':
372 line++;
373 if(interactive == 0)
374 goto loop;
375 if(stacked) {
376 print("\t");
377 goto loop;
379 nlcount++;
380 return ';';
382 case '.':
383 c = lexc();
384 unlexc(c);
385 if(isdigit(c))
386 return numsym('.');
388 return '.';
390 case '(':
391 case ')':
392 case '[':
393 case ']':
394 case ';':
395 case ':':
396 case ',':
397 case '~':
398 case '?':
399 case '*':
400 case '@':
401 case '^':
402 case '%':
403 return c;
404 case '{':
405 stacked++;
406 return c;
407 case '}':
408 stacked--;
409 return c;
411 case '\\':
412 c = lexc();
413 if(strchr(vfmt, c) == 0) {
414 unlexc(c);
415 return '\\';
417 yylval.ival = c;
418 return Tfmt;
420 case '!':
421 c = lexc();
422 if(c == '=')
423 return Tneq;
424 unlexc(c);
425 return '!';
427 case '+':
428 c = lexc();
429 if(c == '+')
430 return Tinc;
431 unlexc(c);
432 return '+';
434 case '/':
435 c = lexc();
436 if(c == '/') {
437 eatnl();
438 goto loop;
440 unlexc(c);
441 return '/';
443 case '\'':
444 c = lexc();
445 if(c == '\\')
446 yylval.ival = escchar(lexc());
447 else
448 yylval.ival = c;
449 c = lexc();
450 if(c != '\'') {
451 error("missing '");
452 unlexc(c);
454 return Tconst;
456 case '&':
457 c = lexc();
458 if(c == '&')
459 return Tandand;
460 unlexc(c);
461 return '&';
463 case '=':
464 c = lexc();
465 if(c == '=')
466 return Teq;
467 unlexc(c);
468 return '=';
470 case '|':
471 c = lexc();
472 if(c == '|')
473 return Toror;
474 unlexc(c);
475 return '|';
477 case '<':
478 c = lexc();
479 if(c == '=')
480 return Tleq;
481 if(c == '<')
482 return Tlsh;
483 unlexc(c);
484 return '<';
486 case '>':
487 c = lexc();
488 if(c == '=')
489 return Tgeq;
490 if(c == '>')
491 return Trsh;
492 unlexc(c);
493 return '>';
495 case '-':
496 c = lexc();
498 if(c == '>')
499 return Tindir;
501 if(c == '-')
502 return Tdec;
503 unlexc(c);
504 return '-';
506 default:
507 return numsym(c);
511 int
512 numsym(char first)
514 int c, isbin, isfloat, ishex;
515 char *sel, *p;
516 Lsym *s;
518 symbol[0] = first;
519 p = symbol;
521 ishex = 0;
522 isbin = 0;
523 isfloat = 0;
524 if(first == '.')
525 isfloat = 1;
527 if(isdigit((uchar)*p++) || isfloat) {
528 for(;;) {
529 c = lexc();
530 if(c < 0)
531 error("%d: <eof> eating symbols", line);
533 if(c == '\n')
534 line++;
535 sel = "01234567890.xb";
536 if(ishex)
537 sel = "01234567890abcdefABCDEF";
538 else if(isbin)
539 sel = "01";
540 else if(isfloat)
541 sel = "01234567890eE-+";
543 if(strchr(sel, c) == 0) {
544 unlexc(c);
545 break;
547 if(c == '.')
548 isfloat = 1;
549 if(!isbin && c == 'x')
550 ishex = 1;
551 if(!ishex && c == 'b')
552 isbin = 1;
553 *p++ = c;
555 *p = '\0';
556 if(isfloat) {
557 yylval.fval = atof(symbol);
558 return Tfconst;
561 if(isbin)
562 yylval.ival = strtoul(symbol+2, 0, 2);
563 else
564 yylval.ival = strtoul(symbol, 0, 0);
565 return Tconst;
568 for(;;) {
569 c = lexc();
570 if(c < 0)
571 error("%d <eof> eating symbols", line);
572 if(c == '\n')
573 line++;
574 if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */
575 unlexc(c);
576 break;
578 *p++ = c;
581 *p = '\0';
583 s = look(symbol);
584 if(s == 0)
585 s = enter(symbol, Tid);
587 yylval.sym = s;
588 return s->lexval;
591 Lsym*
592 enter(char *name, int t)
594 Lsym *s;
595 ulong h;
596 char *p;
597 Value *v;
599 h = 0;
600 for(p = name; *p; p++)
601 h = h*3 + *p;
602 h %= Hashsize;
604 s = gmalloc(sizeof(Lsym));
605 memset(s, 0, sizeof(Lsym));
606 s->name = strdup(name);
608 s->hash = hash[h];
609 hash[h] = s;
610 s->lexval = t;
612 v = gmalloc(sizeof(Value));
613 s->v = v;
615 v->store.fmt = 'X';
616 v->type = TINT;
617 memset(v, 0, sizeof(Value));
619 return s;
622 void
623 delsym(Lsym *s)
625 char *q;
626 ulong h;
627 Lsym *p;
629 h = 0;
630 for(q = s->name; *q; q++)
631 h = h*3 + *q;
632 h %= Hashsize;
634 if(hash[h] == s)
635 hash[h] = s->hash;
636 else{
637 for(p=hash[h]; p && p->hash != s; p=p->hash)
639 if(p)
640 p->hash = s->hash;
642 s->hash = nil;
645 Lsym*
646 look(char *name)
648 Lsym *s;
649 ulong h;
650 char *p;
652 h = 0;
653 for(p = name; *p; p++)
654 h = h*3 + *p;
655 h %= Hashsize;
657 for(s = hash[h]; s; s = s->hash)
658 if(strcmp(name, s->name) == 0)
659 return s;
660 return 0;
663 Lsym*
664 mkvar(char *s)
666 Lsym *l;
668 l = look(s);
669 if(l == 0)
670 l = enter(s, Tid);
671 return l;