Blob
1 #include <u.h>2 #include <libc.h>3 #include <bio.h>4 #include <ctype.h>5 #include <mach.h>6 #define Extern extern7 #include "acid.h"8 #include "y.tab.h"10 struct keywd11 {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, 038 };40 char cmap[256];42 void43 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 void58 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 IOstack70 {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 void82 setacidfile(void)83 {84 char *name;85 Lsym *l;87 if(lexio)88 name = lexio->name;89 else90 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 void99 pushfile(char *file)100 {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>";112 }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();131 }133 void134 pushfd(int fd)135 {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;141 }143 void144 pushstr(Node *s)145 {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();167 }169 void170 restartio(void)171 {172 Bflush(lexio->fin);173 Binit(lexio->fin, 0, OREAD);174 }176 int177 popio(void)178 {179 IOstack *s;181 if(lexio == 0)182 return 0;184 if(lexio->prev == 0){185 if(lexio->fin)186 restartio();187 return 0;188 }190 if(lexio->fin)191 Bterm(lexio->fin);192 else193 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;202 }204 int205 Zfmt(Fmt *f)206 {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);218 }219 } else220 sprint(buf, "no file:0");221 fmtstrcpy(f, buf);222 return 0;223 }225 void226 unlexc(int s)227 {228 if(s == '\n')229 line--;231 if(lexio->fin)232 Bungetc(lexio->fin);233 else234 lexio->ip--;235 }237 int238 lexc(void)239 {240 int c;242 if(lexio->fin) {243 c = Bgetc(lexio->fin);244 if(gotint)245 error("interrupt");246 return c;247 }249 c = *lexio->ip++;250 if(c == 0)251 return -1;252 return c;253 }255 int256 escchar(char c)257 {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;271 }272 buf[n++] = c;273 }274 buf[n] = '\0';275 return strtol(buf, 0, 0);276 }278 n = cmap[(unsigned char)c];279 if(n == 0)280 return c;281 return n-1;282 }284 void285 eatstring(void)286 {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;317 }318 buf[cnt++] = c;319 break;320 }321 if(cnt >= Strsize)322 error("string token too long");323 }324 done:325 buf[cnt] = '\0';326 yylval.string = strnode(buf);327 }329 void330 eatnl(void)331 {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;341 }342 }344 int345 yylex(void)346 {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;360 }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;378 }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 '\\';416 }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;439 }440 unlexc(c);441 return '/';443 case '\'':444 c = lexc();445 if(c == '\\')446 yylval.ival = escchar(lexc());447 else448 yylval.ival = c;449 c = lexc();450 if(c != '\'') {451 error("missing '");452 unlexc(c);453 }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);508 }509 }511 int512 numsym(char first)513 {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(*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;546 }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;554 }555 *p = '\0';556 if(isfloat) {557 yylval.fval = atof(symbol);558 return Tfconst;559 }561 if(isbin)562 yylval.ival = strtoul(symbol+2, 0, 2);563 else564 yylval.ival = strtoul(symbol, 0, 0);565 return Tconst;566 }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;577 }578 *p++ = c;579 }581 *p = '\0';583 s = look(symbol);584 if(s == 0)585 s = enter(symbol, Tid);587 yylval.sym = s;588 return s->lexval;589 }591 Lsym*592 enter(char *name, int t)593 {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;620 }622 void623 delsym(Lsym *s)624 {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)638 ;639 if(p)640 p->hash = s->hash;641 }642 s->hash = nil;643 }645 Lsym*646 look(char *name)647 {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;661 }663 Lsym*664 mkvar(char *s)665 {666 Lsym *l;668 l = look(s);669 if(l == 0)670 l = enter(s, Tid);671 return l;672 }