]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/acid/exec.c
acid: don't get fooled by spaces in convflt()
[plan9front.git] / sys / src / cmd / acid / exec.c
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
9 void
10 error(char *fmt, ...)
11 {
12         int i;
13         char buf[2048];
14         va_list arg;
15
16         /* Unstack io channels */
17         if(iop != 0) {
18                 for(i = 1; i < iop; i++)
19                         Bterm(io[i]);
20                 bout = io[0];
21                 iop = 0;
22         }
23
24         ret = 0;
25         gotint = 0;
26         Bflush(bout);
27         if(silent)
28                 silent = 0;
29         else {
30                 va_start(arg, fmt);
31                 vseprint(buf, buf+sizeof(buf), fmt, arg);
32                 va_end(arg);
33                 fprint(2, "%L: (error) %s\n", buf);
34         }
35         while(popio())
36                 ;
37         interactive = 1;
38         longjmp(err, 1);
39 }
40
41 void
42 unwind(void)
43 {
44         int i;
45         Lsym *s;
46         Value *v;
47
48         for(i = 0; i < Hashsize; i++) {
49                 for(s = hash[i]; s; s = s->hash) {
50                         while(s->v->pop) {
51                                 v = s->v->pop;
52                                 free(s->v);
53                                 s->v = v;
54                         }
55                 }
56         }
57 }
58
59 void
60 execrec(Node *n)
61 {
62         Value *v;
63         Lsym *s;
64
65         /* make node a root so it isn't collected! */
66         s = mkvar("_thiscmd");
67
68         v = gmalloc(sizeof(Value));
69         memset(v, 0, sizeof(Value));
70         v->type = TCODE;
71         v->cc = n;
72         v->pop = s->v;
73
74         s->v = v;
75         s->proc = n;
76
77         gc();
78         execute(n);
79
80         s->proc = s->v->cc;
81         s->v = v->pop;
82         free(v);
83 }
84
85 void
86 execute(Node *n)
87 {
88         Value *v;
89         Lsym *sl;
90         Node *l, *r;
91         vlong i, s, e;
92         Node res, xx;
93         static int stmnt;
94
95         if(gotint)
96                 error("interrupted");
97
98         if(n == 0)
99                 return;
100
101         if(stmnt++ > 5000) {
102                 Bflush(bout);
103                 stmnt = 0;
104         }
105
106         l = n->left;
107         r = n->right;
108
109         switch(n->op) {
110         default:
111                 expr(n, &res);
112                 if(ret || (res.type == TLIST && res.l == 0 && n->op != OADD))
113                         break;
114                 prnt->right = &res;
115                 expr(prnt, &xx);
116                 break;
117         case OASGN:
118         case OCALL:
119                 expr(n, &res);
120                 break;
121         case OCOMPLEX:
122                 decl(n);
123                 break;
124         case OLOCAL:
125                 for(n = n->left; n; n = n->left) {
126                         if(ret == 0)
127                                 error("local not in function");
128                         sl = n->sym;
129                         if(sl->v->ret == ret)
130                                 error("%s declared twice", sl->name);
131                         v = gmalloc(sizeof(Value));
132                         v->ret = ret;
133                         v->pop = sl->v;
134                         sl->v = v;
135                         v->scope = 0;
136                         *(ret->tail) = sl;
137                         ret->tail = &v->scope;
138                         v->set = 0;
139                 }
140                 break;
141         case ORET:
142                 if(ret == 0)
143                         error("return not in function");
144                 expr(n->left, ret->val);
145                 longjmp(ret->rlab, 1);
146         case OLIST:
147                 execute(n->left);
148                 execute(n->right);
149                 break;
150         case OIF:
151                 expr(l, &res);
152                 if(r && r->op == OELSE) {
153                         if(bool(&res))
154                                 execute(r->left);
155                         else
156                                 execute(r->right);
157                 }
158                 else if(bool(&res))
159                         execute(r);
160                 break;
161         case OWHILE:
162                 for(;;) {
163                         expr(l, &res);
164                         if(!bool(&res))
165                                 break;
166                         execute(r);
167                 }
168                 break;
169         case ODO:
170                 expr(l->left, &res);
171                 if(res.type != TINT)
172                         error("loop must have integer start");
173                 s = res.ival;
174                 expr(l->right, &res);
175                 if(res.type != TINT)
176                         error("loop must have integer end");
177                 e = res.ival;
178                 for(i = s; i <= e; i++)
179                         execute(r);
180                 break;
181         }
182 }
183
184 int
185 bool(Node *n)
186 {
187         int true = 0;
188
189         if(n->op != OCONST)
190                 fatal("bool: not const");
191
192         switch(n->type) {
193         case TINT:
194                 if(n->ival != 0)
195                         true = 1;
196                 break;
197         case TFLOAT:
198                 if(n->fval != 0.0)
199                         true = 1;
200                 break;
201         case TSTRING:
202                 if(n->string->len)
203                         true = 1;
204                 break;
205         case TLIST:
206                 if(n->l)
207                         true = 1;
208                 break;
209         }
210         return true;
211 }
212
213 void
214 convflt(Node *r, char *flt)
215 {
216         char *s;
217
218         while(*flt == ' ')
219                 flt++;
220
221         s = flt;
222         if(*s == '-' || *s == '+')
223                 s++;
224         if(*s == '.')
225                 s++;
226
227         if(*s >= '0' && *s <= '9'){     
228                 r->type = TFLOAT;
229                 r->fval = atof(flt);
230         } else {
231                 r->type = TSTRING;
232                 r->fmt = 's';
233                 r->string = strnode(flt);
234         }
235 }
236
237 void
238 indir(Map *m, uvlong addr, char fmt, Node *r)
239 {
240         int i;
241         ulong lval;
242         uvlong uvval;
243         int ret;
244         uchar cval;
245         ushort sval;
246         char buf[512], reg[12];
247
248         r->op = OCONST;
249         r->fmt = fmt;
250         switch(fmt) {
251         default:
252                 error("bad pointer format '%c' for *", fmt);
253         case 'c':
254         case 'C':
255         case 'b':
256                 r->type = TINT;
257                 ret = get1(m, addr, &cval, 1);
258                 if (ret < 0)
259                         error("indir: %r");
260                 r->ival = cval;
261                 break;
262         case 'x':
263         case 'd':
264         case 'u':
265         case 'o':
266         case 'q':
267         case 'r':
268                 r->type = TINT;
269                 ret = get2(m, addr, &sval);
270                 if (ret < 0)
271                         error("indir: %r");
272                 r->ival = sval;
273                 break;
274         case 'a':
275         case 'A':
276         case 'W':
277                 r->type = TINT;
278                 ret = geta(m, addr, &uvval);
279                 if (ret < 0)
280                         error("indir: %r");
281                 r->ival = uvval;
282                 break;
283         case 'B':
284         case 'X':
285         case 'D':
286         case 'U':
287         case 'O':
288         case 'Q':
289                 r->type = TINT;
290                 ret = get4(m, addr, &lval);
291                 if (ret < 0)
292                         error("indir: %r");
293                 r->ival = lval;
294                 break;
295         case 'V':
296         case 'Y':
297         case 'Z':
298                 r->type = TINT;
299                 ret = get8(m, addr, &uvval);
300                 if (ret < 0)
301                         error("indir: %r");
302                 r->ival = uvval;
303                 break;
304         case 's':
305                 r->type = TSTRING;
306                 for(i = 0; i < sizeof(buf)-1; i++) {
307                         ret = get1(m, addr, (uchar*)&buf[i], 1);
308                         if (ret < 0)
309                                 error("indir: %r");
310                         addr++;
311                         if(buf[i] == '\0')
312                                 break;
313                 }
314                 buf[i] = 0;
315                 if(i == 0)
316                         strcpy(buf, "(null)");
317                 r->string = strnode(buf);
318                 break;
319         case 'R':
320                 r->type = TSTRING;
321                 for(i = 0; i < sizeof(buf)-2; i += 2) {
322                         ret = get1(m, addr, (uchar*)&buf[i], 2);
323                         if (ret < 0)
324                                 error("indir: %r");
325                         addr += 2;
326                         if(buf[i] == 0 && buf[i+1] == 0)
327                                 break;
328                 }
329                 buf[i++] = 0;
330                 buf[i] = 0;
331                 r->string = runenode((Rune*)buf);
332                 break;
333         case 'i':
334         case 'I':
335                 if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
336                         error("indir: %r");
337                 r->type = TSTRING;
338                 r->fmt = 's';
339                 r->string = strnode(buf);
340                 break;
341         case 'f':
342                 ret = get1(m, addr, (uchar*)buf, mach->szfloat);
343                 if (ret < 0)
344                         error("indir: %r");
345                 machdata->sftos(buf, sizeof(buf), (void*) buf);
346                 convflt(r, buf);
347                 break;
348         case 'g':
349                 ret = get1(m, addr, (uchar*)buf, mach->szfloat);
350                 if (ret < 0)
351                         error("indir: %r");
352                 machdata->sftos(buf, sizeof(buf), (void*) buf);
353                 r->type = TSTRING;
354                 r->string = strnode(buf);
355                 break;
356         case 'F':
357                 ret = get1(m, addr, (uchar*)buf, mach->szdouble);
358                 if (ret < 0)
359                         error("indir: %r");
360                 machdata->dftos(buf, sizeof(buf), (void*) buf);
361                 convflt(r, buf);
362                 break;
363         case '3':       /* little endian ieee 80 with hole in bytes 8&9 */
364                 ret = get1(m, addr, (uchar*)reg, 10);
365                 if (ret < 0)
366                         error("indir: %r");
367                 memmove(reg+10, reg+8, 2);      /* open hole */
368                 memset(reg+8, 0, 2);            /* fill it */
369                 leieee80ftos(buf, sizeof(buf), reg);
370                 convflt(r, buf);
371                 break;
372         case '8':       /* big-endian ieee 80 */
373                 ret = get1(m, addr, (uchar*)reg, 10);
374                 if (ret < 0)
375                         error("indir: %r");
376                 beieee80ftos(buf, sizeof(buf), reg);
377                 convflt(r, buf);
378                 break;
379         case 'G':
380                 ret = get1(m, addr, (uchar*)buf, mach->szdouble);
381                 if (ret < 0)
382                         error("indir: %r");
383                 machdata->dftos(buf, sizeof(buf), (void*) buf);
384                 r->type = TSTRING;
385                 r->string = strnode(buf);
386                 break;
387         }
388 }
389
390 void
391 windir(Map *m, Node *addr, Node *rval, Node *r)
392 {
393         uchar cval;
394         ushort sval;
395         long lval;
396         Node res, aes;
397         int ret;
398
399         if(m == 0)
400                 error("no map for */@=");
401
402         expr(rval, &res);
403         expr(addr, &aes);
404
405         if(aes.type != TINT)
406                 error("bad type lhs of @/*");
407
408         if(m != cormap && wtflag == 0)
409                 error("not in write mode");
410
411         r->type = res.type;
412         r->fmt = res.fmt;
413         r->Store = res.Store;
414
415         switch(res.fmt) {
416         default:
417                 error("bad pointer format '%c' for */@=", res.fmt);
418         case 'c':
419         case 'C':
420         case 'b':
421                 cval = res.ival;
422                 ret = put1(m, aes.ival, &cval, 1);
423                 break;
424         case 'r':
425         case 'x':
426         case 'd':
427         case 'u':
428         case 'o':
429                 sval = res.ival;
430                 ret = put2(m, aes.ival, sval);
431                 r->ival = sval;
432                 break;
433         case 'a':
434         case 'A':
435         case 'W':
436                 ret = puta(m, aes.ival, res.ival);
437                 break;
438         case 'B':
439         case 'X':
440         case 'D':
441         case 'U':
442         case 'O':
443                 lval = res.ival;
444                 ret = put4(m, aes.ival, lval);
445                 break;
446         case 'V':
447         case 'Y':
448         case 'Z':
449                 ret = put8(m, aes.ival, res.ival);
450                 break;
451         case 's':
452         case 'R':
453                 ret = put1(m, aes.ival, (uchar*)res.string->string, res.string->len);
454                 break;
455         }
456         if (ret < 0)
457                 error("windir: %r");
458 }
459
460 void
461 call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
462 {
463         int np, i;
464         Rplace rlab;
465         Node *n, res;
466         Value *v, *f;
467         Lsym *s, *next;
468         Node *avp[Maxarg], *ava[Maxarg];
469
470         rlab.local = 0;
471
472         na = 0;
473         flatten(avp, parameters);
474         np = na;
475         na = 0;
476         flatten(ava, local);
477         if(np != na) {
478                 if(np < na)
479                         error("%s: too few arguments", fn);
480                 error("%s: too many arguments", fn);
481         }
482
483         rlab.tail = &rlab.local;
484
485         ret = &rlab;
486         for(i = 0; i < np; i++) {
487                 n = ava[i];
488                 switch(n->op) {
489                 default:
490                         error("%s: %d formal not a name", fn, i);
491                 case ONAME:
492                         expr(avp[i], &res);
493                         s = n->sym;
494                         break;
495                 case OINDM:
496                         res.cc = avp[i];
497                         res.type = TCODE;
498                         res.comt = 0;
499                         if(n->left->op != ONAME)
500                                 error("%s: %d formal not a name", fn, i);
501                         s = n->left->sym;
502                         break;
503                 }
504                 if(s->v->ret == ret)
505                         error("%s already declared at this scope", s->name);
506
507                 v = gmalloc(sizeof(Value));
508                 v->ret = ret;
509                 v->pop = s->v;
510                 s->v = v;
511                 v->scope = 0;
512                 *(rlab.tail) = s;
513                 rlab.tail = &v->scope;
514
515                 v->Store = res.Store;
516                 v->type = res.type;
517                 v->set = 1;
518         }
519
520         ret->val = retexp;
521         if(setjmp(rlab.rlab) == 0)
522                 execute(body);
523
524         for(s = rlab.local; s; s = next) {
525                 f = s->v;
526                 next = f->scope;
527                 s->v = f->pop;
528                 free(f);
529         }
530 }