Skip to content

Commit b413309

Browse files
authored
Merge pull request #79 from refi64/fixes
Various bug fixes / performance improvements & add '!?' to dump the stack
2 parents 1c4015f + 3a724da commit b413309

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

o.c

+48-25
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ P rlc(P p,L z){P r;if(!(r=realloc(p,z)))ex("memory");R r;} //realloc memory
4444
#define DL(x) free(x)
4545
#define STL 8192 //upper stack limit: 2^13
4646

47+
//freelist
48+
typedef struct{P*l;L s,e;}FL; //type:freelist,start index,end index
49+
V initfl(FL*f){f->l=alc(BZ*sizeof(P));f->s=f->e=0;}
50+
I rcy(FL*f,P p){R f->e-f->s<BZ?(f->l[f->e++%BZ]=p,1):0;} //"recycle" pointer
51+
P arp(FL*f){R f->s<f->e?f->l[f->s++%BZ]:0;} //acquire recycled pointer
52+
V dlfl(FL*f){while(f->s<f->e)DL(f->l[f->s++%BZ]);DL(f->l);f->l=0;}
53+
4754
U su(S s){U r=0;L z=0;while(*s){r=rlc(r,z+1);s+=chartorune(r+z,s);++z;}R r;} //byte str to unicode
4855

4956
S rdln(){L z;S r=alc(BZ);if(!fgets(r,BZ,stdin)){if(feof(stdin)){*r=0;R r;}else PXE;}z=strlen(r);if(r[z-1]=='\n')r[z-1]=0;if(z>1&&r[z-2]=='\r')r[z-2]=0;R r;} //read line(XXX:only allows BZ as max length!)
@@ -52,14 +59,15 @@ F rdlnd(){F r;S s=rdln();r=strtod(s,0);DL(s);R r;} //read number(should this err
5259

5360
//stack
5461
typedef struct{P*st;L p,l;}STB;typedef STB*ST; //type:stack,top,len
55-
ST newst(L z){ST s=alc(sizeof(STB));s->st=alc(z*sizeof(P));s->p=0;s->l=z;R s;} //new stack
62+
FL sfl={0},sifl={0}; //stack freelist,stack inner array freelist
63+
ST newst(){if(!sfl.l)initfl(&sfl);if(!sifl.l)initfl(&sifl);ST s=arp(&sfl);if(!s)s=alc(sizeof(STB));if(!(s->st=arp(&sifl)))s->st=alc(BZ*sizeof(P));s->p=0;s->l=BZ;R s;} //new stack
5664
V psh(ST s,P x){if(s->p+1>s->l)ex("overflow");s->st[s->p++]=x;} //push
5765
P pop(ST s){if(s->p==0)ex("underflow");R s->st[--s->p];} //pop
5866
P top(ST s){if(s->p==0)ex("underflow");R s->st[s->p-1];} //top
5967
V swp(ST s){P a,b;a=pop(s);b=pop(s);psh(s,a);psh(s,b);} //swap
6068
V rot(ST s){P a,b,c;a=pop(s);b=pop(s);c=pop(s);psh(s,b);psh(s,a);psh(s,c);} //rotate 3
6169
L len(ST s){R s->p;}
62-
V dls(ST s){DL(s->st);DL(s);} //delete
70+
V dls(ST s){if(!rcy(&sifl,s->st))DL(s->st);if(!rcy(&sfl,s))DL(s);} //delete
6371
V rev(ST s){P t;L i;for(i=0;i<s->p/2;++i){t=s->st[i];s->st[i]=s->st[s->p-i-1];s->st[s->p-i-1]=t;}} //reverse
6472

6573
ST rst=0; //root stack
@@ -79,7 +87,8 @@ S tos(O o){
7987
case TR:{L lv;S tv;t=tos(o->e.k);tv=tos(o->e.v);z=strlen(t);lv=strlen(tv);r=alc(z+lv+5);sprintf(r,"{%s: %s}",t,tv);DL(t);DL(tv);}BK;
8088
}R r;
8189
} //tostring (copies)
82-
O newo(){R alc(sizeof(OB));} //new object
90+
FL ofl={0}; //object freelist
91+
O newo(){if (!ofl.l)initfl(&ofl);O o=arp(&ofl);R o?o:alc(sizeof(OB));} //new object
8392
O newod(F d){O r=newo();r->t=TD;r->d=d;R r;} //new object decimal
8493
O newocb(S s,L z){O r=newo();r->t=TCB;r->s.s=alc(z+1);memcpy(r->s.s,s,z);r->s.s[z]=0;r->s.z=z;R r;} //new object code block (copies)
8594
O newocbk(S s,L z){O r=newo();r->t=TCB;r->s.s=s;r->s.z=z;R r;} //new object string (doesn't copy)
@@ -96,10 +105,10 @@ V dlo(O o){
96105
case TA:while(len(o->a))dlo(pop(o->a));dls(o->a);BK;
97106
case TD:BK;
98107
case TR:dlo(o->e.k);dlo(o->e.v);BK;
99-
}DL(o);
108+
}if(!rcy(&ofl,o))DL(o);
100109
} //delete object
101110
O toso(O o){S s=tos(o);O r=newosz(s);DL(s);R r;} //wrap tostring in object
102-
O dup(O);O dupa(O o){ST s=newst(BZ);L i=0;for(i=0;i<len(o->a);++i)psh(s,dup(o->a->st[i]));R newoa(s);} //dup array
111+
O dup(O);O dupa(O o){ST s=newst();L i=0;for(i=0;i<len(o->a);++i)psh(s,dup(o->a->st[i]));R newoa(s);} //dup array
103112
O dup(O o){
104113
L z;S s;switch(o->t){
105114
case TCB:R newocb(o->s.s,o->s.z);BK;
@@ -142,7 +151,7 @@ O adds(O a,O b,ST s){S rs=alc(a->s.z+b->s.z+1);memcpy(rs,a->s.s,a->s.z);memcpy(r
142151
O addd(O a,O b,ST s){R newod(a->d+b->d);} //add decimal
143152
OTF addf[TN]={addd,adds};
144153

145-
O subs(O a,O b,ST s){L i,z=a->s.z;S r,p;if(b->s.z==0)R dup(a);for(i=0;i<a->s.z;++i)if(memcmp(a->s.s+i,b->s.s,b->s.z)==0)z-=b->s.z;p=r=alc(z+1);for(i=0;i<a->s.z;++i)if(memcmp(a->s.s+i,b->s.s,b->s.z)==0)i+=b->s.z-1;else*p++=a->s.s[i];R newosk(r,z);} //sub strings
154+
O subs(O a,O b,ST s){L i,az,z=a->s.z;az=z;S r,p;if(b->s.z==0)R dup(a);if(b->s.z<az)az-=b->s.z-1;for(i=0;i<az;++i)if(memcmp(a->s.s+i,b->s.s,b->s.z)==0)z-=b->s.z;p=r=alc(z+1);for(i=0;i<az;++i)if(memcmp(a->s.s+i,b->s.s,b->s.z)==0)i+=b->s.z-1;else*p++=a->s.s[i];memcpy(p,a->s.s+i,a->s.z-i);R newosk(r,z);} //sub strings
146155
O subd(O a,O b,ST s){R newod(a->d-b->d);} //sub decimal
147156
OTF subf[TN]={subd,subs};
148157

@@ -157,7 +166,7 @@ OTF gtf[TN]={gtd,gts};
157166

158167
V gnop(ST s,OTF*ft,I e,I t,OTF cx){
159168
I c;O a,b,x,r;b=pop(s);if(b->t==TA){if(e){O ad,bd;a=pop(s);if(a->t!=TA)TE;ad=newod(len(a->a));bd=newod(len(b->a));r=ft[TD](ad,bd,s);if(r)psh(s,r);dlo(ad);dlo(bd);dlo(a);dlo(b);R;}else{psh(s,opa(b,ft,e,t));dlo(b);R;}}
160-
a=pop(s);if(a->t==TA){if(cx)r=cx(a,b,s);else{r=newoa(newst(BZ));while(len(a->a)){psh(s,pop(a->a));psh(s,dup(b));gnop(s,ft,e,t,0);psh(r->a,pop(s));}dlo(a);dlo(b);rev(r->a);}psh(s,r);R;}
169+
a=pop(s);if(a->t==TA){if(cx)r=cx(a,b,s);else{r=newoa(newst());while(len(a->a)){psh(s,pop(a->a));psh(s,dup(b));gnop(s,ft,e,t,0);psh(r->a,pop(s));}dlo(a);dlo(b);rev(r->a);}psh(s,r);R;}
161170
c=a->t==TCB||b->t==TCB;/*two different types added together==str*/if(a->t!=b->t&&t){O ao=a,bo=b;a=tosocb(ao);b=tosocb(bo);dlo(ao);dlo(bo);}r=ft[a->t==TCB?TS:a->t](a,b,s);if(r&&c&&r->t==TS){x=r;r=newocb(x->s.s,x->s.z);dlo(x);}
162171
if(r)psh(s,r);dlo(a);dlo(b);
163172
} //generic op
@@ -166,7 +175,7 @@ O muls(O a,O b,ST s){S r,p;I i,t=b->d/*truncate*/;L z=a->s.z*t;p=r=alc(z+1);for(
166175
O muld(O a,O b,ST s){R newod(a->d*b->d);} //mul decimal
167176
OTF mulf[TN]={muld,muls};
168177

169-
O moda(O a,O b,ST s){ST r=newst(BZ);L i;for(i=0;i<len(a->a);++i)psh(r,dup(a->a->st[i]));for(i=0;i<len(b->a);++i)psh(r,dup(b->a->st[i]));R newoa(r);} //mod array
178+
O moda(O a,O b,ST s){ST r=newst();L i;for(i=0;i<len(a->a);++i)psh(r,dup(a->a->st[i]));for(i=0;i<len(b->a);++i)psh(r,dup(b->a->st[i]));R newoa(r);} //mod array
170179
O modd(O a,O b,ST s){if(b->d==0)ex("zero division");R newod(fmod(a->d,b->d));} //mod decimal
171180
O mods(O a,O b,ST st){
172181
L z;S s;C d[BZ];Reprog*p;Resub rs[10];O r,os=pop(top(rst));if(os->t!=TS)TE;s=os->s.s;p=regcomp(a->s.s);if(!p)ex("bad regex");memset(rs,0,sizeof(rs));
@@ -176,7 +185,7 @@ O mods(O a,O b,ST st){
176185
OTF modfn[TN]={modd,mods,moda};
177186
S put(O,I);
178187
O filt(O a,O b,ST s){
179-
O o,on;ST na;if(b->t!=TCB)TE;na=newst(BZ);on=v['n'];rev(a->a);
188+
O o,on;ST na;if(b->t!=TCB)TE;na=newst();on=v['n'];rev(a->a);
180189
while(len(a->a)){v['n']=pop(a->a);excb(b);if(truth(o=pop(s)))psh(na,v['n']);else dlo(v['n']);dlo(o);}
181190
v['n']=on;dlo(a);dlo(b);R newoa(na);} //filter
182191

@@ -199,7 +208,7 @@ V rvx(ST s){O r,o=pop(s);r=o->t==TD?rvxd(o):o->t==TS?rvxs(o):0;if(!r)TE;psh(s,r)
199208

200209
V idc(ST s,C c){O o=pop(s);if(o->t==TR)psh(s,dup(c=='('?o->e.k:o->e.v));else if(o->t==TD)psh(s,newod(c=='('?o->d-1:o->d+1));else TE;dlo(o);} //inc/dec/index entry
201210

202-
V opar(){ST r;O a=pop(top(rst));L i;psh(rst,r=newst(BZ));for(i=0;i<len(a->a);++i)psh(r,dup(a->a->st[i]));dlo(a);} //open array
211+
V opar(){ST r;O a=pop(top(rst));L i;psh(rst,r=newst());for(i=0;i<len(a->a);++i)psh(r,dup(a->a->st[i]));dlo(a);} //open array
203212

204213
V evn(ST s){O o=pop(s);if(o->t==TD)psh(s,newod((I)o->d%2==0));else if(o->t==TS){psh(s,dup(o));psh(s,newod(o->s.z));}else if(o->t==TA){psh(s,dup(o));psh(s,newod(len(o->a)));}else TE;dlo(o);} //even? or push string length or push array length
205214

@@ -217,7 +226,7 @@ V rjf(ST s){I i;O o=pop(s);if(o->t==TD)range(s,o);else if(o->t==TS){O b=pop(s);p
217226
O hsho(O);
218227
O hshd(O o){R dup(o);} //hash decimal
219228
O hshs(O o){L z;S e;F r=0;if(o->s.z==0)R newod(0);r=strtod(o->s.s,&e);if(!*e)R newod(r);for(z=0;z<o->s.z-1;++z)r+=(I)o->s.s[z]*pow(31,o->s.z-z-1);r+=o->s.s[o->s.z-1];R newod(r);} //hash string
220-
O hsha(O o){ST a=newst(BZ);L i;for(i=0;i<len(o->a);++i)psh(a,hsho(o->a->st[i]));R newoa(a);} //hash array
229+
O hsha(O o){ST a=newst();L i;for(i=0;i<len(o->a);++i)psh(a,hsho(o->a->st[i]));R newoa(a);} //hash array
221230
OTB hshf[]={hshd,hshs,hsha,0}; //hash functions
222231
O hsho(O o){OTB f=hshf[o->t];if(f==0)TE;R f(o);} //hash any object
223232
V hsh(ST s){O o=pop(s);psh(s,hsho(o));dlo(o);} //hash
@@ -251,16 +260,18 @@ V take(){O o;if(len(rst)<2)ex("take needs open array");psh(top(rst),pop(rst->st[
251260
I isnum(S s){while(*s){if(isdigit(*s++)==0)R 1;}R 1;}//is string number? (helper func)
252261
V rdq(ST s,I u){S e,i=rdln();F d=strtod(i,&e);if(*e)psh(s,newoskz(i));else{DL(i);psh(s,newod(d));}if(u)v['Q']=dup(top(s));} //q,Q
253262

254-
C pec(C c){static C em[]="abtnvf";S p=strchr(em,c);if(p)R 0x7+(p-em);else R c;} //parse escape code
263+
#define ECOFF 0x7 //escape code offset
264+
static C ecm[] = "abtnvf"; //escape code map
265+
C pec(C c){S p=strchr(ecm,c);if(p)R ECOFF+(p-ecm);else R c;} //parse escape code
255266

256267
typedef V(*SRTF)(V*,ST); //sort function
257268
V dfsrt(V*v,ST s){gnop(s,ltf,1,1,ltcx);} //default sort
258269
V cbsrt(V*v,ST s){excb(v);}
259270

260-
V msrt(SRTF f,V*v,ST s,ST a){I i,j;for(i=1;i<len(a);++i){j=i;for(j=i;j>0;--j){O o;psh(s,dup(a->st[j]));psh(s,dup(a->st[j-1]));f(v,s);o=pop(s);if(o->t!=TD)TE;if(!o->d)BK;dlo(o);o=a->st[j];a->st[j]=a->st[j-1];a->st[j-1]=o;}}} //insertion sort
271+
V msrt(SRTF f,V*v,ST s,ST a){I i,j,k;for(i=1;i<len(a);++i){j=i;for(j=i;j>0;--j){O o;psh(s,dup(a->st[j]));psh(s,dup(a->st[j-1]));f(v,s);o=pop(s);if(o->t!=TD)TE;k=o->d;dlo(o);if(!k)BK;o=a->st[j];a->st[j]=a->st[j-1];a->st[j-1]=o;}}} //insertion sort
261272

262273
V toca(ST st,O o){
263-
if(o->t==TS){ST ca=newst(o->s.z+1);I p=0;for(;p<o->s.z;++p)psh(ca,newosc(o->s.s[p]));psh(st,newoa(ca));dlo(o);}
274+
if(o->t==TS){ST ca=newst();I p=0;for(;p<o->s.z;++p)psh(ca,newosc(o->s.s[p]));psh(st,newoa(ca));dlo(o);}
264275
else if(o->t==TA){msrt(dfsrt,0,st,o->a);psh(st,o);}
265276
else if(o->t==TCB){O a=pop(st);if(a->t!=TA)TE;msrt(cbsrt,o,st,a->a);psh(st,a);}
266277
else TE;} //string to char array/sort
@@ -272,19 +283,30 @@ V key(ST st){
272283
O a=top(st);if(b->t==TD&&a->t==TA){I i=b->d;psh(st,dup(a->a->st[i]));dlo(b);}
273284
else TE;} //key
274285

275-
V sh(ST st,I l){L i;ST r=newst(BZ);if(l)psh(r,top(st));for(i=!l;i<len(st)-l;++i)psh(r,st->st[i]);if(!l)psh(r,st->st[0]);DL(st->st);st->st=r->st;DL(r);} //shift stack
286+
V sh(ST st,I r){L e=st->p-1;O o=st->st[r?e:0];memmove(st->st+r,st->st+!r,e*sizeof(P));st->st[r?0:e]=o;} //shift stack
276287

277288
V uv(ST s,O o){if(o->t==TCB)excb(o);else psh(s,dup(o));} //execute the object if it's a code block, else push its contents to the stack.
278289

279-
V bcv(ST s){ST r;I i=0,a,b;O ao,bo=pop(s);ao=pop(s);if(ao->t!=TD||bo->t!=TD)TE;a=ao->d;b=bo->d/*truncate*/;dlo(ao);dlo(bo);r=newst(BZ);while(a){C c=a%b+'0';if(c>'9')c+=7;psh(r,newod(a%b));if(b==1)--a;else a/=b;}psh(s,newoa(r));} //base conversion
290+
V bcv(ST s){ST r;I i=0,a,b;O ao,bo=pop(s);ao=pop(s);if(ao->t!=TD||bo->t!=TD)TE;a=ao->d;b=bo->d/*truncate*/;dlo(ao);dlo(bo);r=newst();while(a){C c=a%b+'0';if(c>'9')c+=7;psh(r,newod(a%b));if(b==1)--a;else a/=b;}psh(s,newoa(r));} //base conversion
280291

281-
V entry(ST s){O r,v,k=pop(s);
282-
if(k->t==TA){I i;if(len(k->a)%2)ex("array passed to entry must have an even # of elements");r=newoa(newst(BZ));for(i=0;i<len(k->a);i+=2)psh(r->a,newoe(dup(k->a->st[i+1]),dup(k->a->st[i])));dlo(k);}
283-
else r=newoe(k,pop(s));
284-
psh(s,r);
292+
V entry(ST s){O v,k=pop(s);
293+
if(k->t==TA){L i;if(len(k->a)%2)ex("array passed to entry must have an even # of elements");for(i=0;i<len(k->a);i+=2)k->a->st[i/2]=newoe(k->a->st[i+1],k->a->st[i]);k->a->p=i/2;psh(s,k);}
294+
else psh(s,newoe(k,pop(s)));
285295
}
286296
O idx(ST s){O a,k=pop(s);a=pop(s);I i;if(a->t!=TA)TE;for(i=0;i<len(a->a);++i){O e=a->a->st[i];if(e->t!=TR)TE;if(eqo(e->e.k,k)){O v=dup(e->e.v);dlo(a);dlo(k);R v;};}ex("nonexistent key");R 0;}
287297

298+
V dumpo(O o,I n){
299+
L i;I m=n*2;while(m-->0)putchar(' ');
300+
switch(o->t){
301+
case TD:printf("%f\n",o->d);BK;
302+
case TS:putchar('"');for(i=0;i<o->s.z;i++){C c=o->s.s[i];if(c>=ECOFF&&c<(ECOFF+sizeof(ecm)))printf("\\%c",ecm[c-ECOFF]);else putchar(c);}puts("\"");BK;
303+
case TA:puts("[]");for(i=0;i<len(o->a);++i)dumpo(o->a->st[i],n+1);BK;
304+
case TCB:printf("{%s}\n",o->s.s);BK;
305+
case TR:puts(":");dumpo(o->e.k,n+1);dumpo(o->e.v,n+1);BK;
306+
}
307+
} //dump object
308+
V dump(ST s) {L i;puts("[[");for(i=0;i<len(s);++i)dumpo(s->st[i],1);puts("]]");}
309+
288310
S exc(C c){
289311
static S psb; //string buffer
290312
static S pcbb; //codeblock buffer
@@ -319,6 +341,7 @@ S exc(C c){
319341
case '(':sh(st,0);BK;
320342
case ')':sh(st,1);BK;
321343
case '&':psh(st,idx(st));BK;
344+
case '?':dump(st);BK;
322345
default:PE;
323346
}}
324347
else if(pv){pv=0;if(v[c])dlo(v[c]);v[c]=dup(top(st));} //save var
@@ -362,7 +385,7 @@ S exc(C c){
362385
case '\'':pc=1;BK; //begin char
363386
case '"':ps=1;psb=alc(1);BK; //begin string
364387
case '{':pcb=1;pcbb=alc(1);cbi++;BK; //being codeblock
365-
case '[':psh(rst,newst(BZ));BK; //begin array
388+
case '[':psh(rst,newst());BK; //begin array
366389
case ']':if(len(rst)==1)ex("no array to close");pop(rst);psh(top(rst),newoa(st));BK; //end array
367390
case '(':if(((O)top(st))->t==TA){opar();BK;};idc(st,c);BK;
368391
case ')':idc(st,c);BK;
@@ -384,7 +407,7 @@ S exc(C c){
384407
#else
385408
while(len(st))dlo(pop(st)); //free stack contents
386409
#endif
387-
dls(st);dls(rst);for(d=0;d<sizeof(v)/sizeof(O);++d)if(v[d])dlo(v[d]);init=1;BK; //delete everything
410+
dls(st);dls(rst);for(d=0;d<sizeof(v)/sizeof(O);++d)if(v[d])dlo(v[d]);dlfl(&sfl);dlfl(&sifl);dlfl(&ofl);init=1;BK; //delete everything
388411
default:
389412
if(isalpha(c)&&!v[c])BK; //if undefined variable, just continue
390413
if(v[c])uv(st,v[c]); //if variable,call uv
@@ -394,7 +417,7 @@ S exc(C c){
394417
} //exec
395418

396419
V excs(S s,I cl){
397-
if(!rst){rst=newst(BZ);psh(rst,newst(BZ));}ln=1;col=1; //init
420+
if(!rst){rst=newst();psh(rst,newst());}ln=1;col=1; //init
398421
while(*s){while(!ps&&!pc&&isspace(*s)){if(*s=='\n'){++ln;col=0;}else++col;++s;}if(!*s)BK;exc(*s++);++col;} //run
399422
if(cl){exc(0);rst=0;} //finish
400423
} //exec string
@@ -409,7 +432,7 @@ V repl(){ //repl
409432

410433
V file(S f){S b;L z;FP fp=fopen(f,"r");if(!fp)ex("file");fseek(fp,0,SEEK_END);z=ftell(fp);fseek(fp,0,SEEK_SET);b=alc(z+1);fread(b,BZ,1,fp);b[z]=0;if(!feof(fp))ex("file error");fclose(fp);excs(b,1);DL(b);} //run file
411434

412-
V lda(I e,I ac,S*av){I i;ST s=newst(BZ);for(i=e?3:2;i<ac;++i)psh(s,newosz(av[i]));args=newoa(s);} //load arg list
435+
V lda(I e,I ac,S*av){I i;ST s=newst();for(i=e?3:2;i<ac;++i)psh(s,newosz(av[i]));args=newoa(s);} //load arg list
413436
I main(I ac,S*av){if(ac==1)repl();else{I e=ac>=3&&strcmp(av[1],"-e")==0;lda(e,ac,av);if(e)excs(av[2],1);else file(av[1]);}R 0;}
414437

415438
#else //unit tests
@@ -434,7 +457,7 @@ I r=0; //how many tests have failed? (doubles as return value)
434457
#define TXE(s,e) isrepl=1;if(!setjmp(jb)){excs(s,1);if(strcmp(eb,e)!=0)TF("test should raise error "e",got %s",eb);}else TF("test should raise error "e,NULL);isrepl=0;
435458

436459
T(stack){TI
437-
ST s=newst(BZ);psh(s,(P)1);
460+
ST s=newst();psh(s,(P)1);
438461
TEQI(top(s),1);
439462
TEQI(len(s),1);
440463
psh(s,(P)2);TEQI(top(s),2);

0 commit comments

Comments
 (0)