├── README.md ├── go ├── ji.c └── mj.c /README.md: -------------------------------------------------------------------------------- 1 | j-incunabulum 2 | ============= 3 | 4 | `ji.c` is the "J incunabulum", a small prototype for an array language interpreter: 5 | 6 | > One summer weekend in 1989, Arthur Whitney visited Ken Iverson at Kiln Farm and produced — on 7 | > one page and in one afternoon—an interpreter fragment on the AT&T 3B1 computer. I studied this 8 | > interpreter for about a week for its organization and programming style; and on Sunday, 9 | > August 27, 1989, at about four o'clock in the afternoon, wrote the first line of code that 10 | > became the implementation described in this document. 11 | -- Roger Hui, [An Implementation of J](http://www.jsoftware.com/jwiki/Doc/An%20Implementation%20of%20J) 12 | 13 | The code was rather cryptic to begin with and no longer compiles on modern C compilers. 14 | 15 | `mj.c` is a partial rewrite that I created in modern C to try and understand the code. 16 | I did my best to emulate the style of the original code, but with more comments, and a 17 | little more whitespace. 18 | 19 | Although the code is terse and may seem unreadable at first, it can be understood with 20 | a little effort. It may help to understand that the code was written for and by people 21 | who were very familiar with array-centric languages (APL) and who came from a strong 22 | mathematical background. Indeed, one of the main reasons for adopting a style like this 23 | is that it meakes it easier to reason about and manipulate the code algebraically. 24 | 25 | --- 26 | 27 | For an interesting interview with Arthur Whitney, see : http://queue.acm.org/detail.cfm?id=1531242 28 | 29 | For more on the J language, see http://jsoftware.com/ 30 | -------------------------------------------------------------------------------- /go: -------------------------------------------------------------------------------- 1 | clang -Wno-implicit-int mj.c -O0 -g -o mj && ./mj 2 | -------------------------------------------------------------------------------- /ji.c: -------------------------------------------------------------------------------- 1 | typedef char C;typedef long I; 2 | typedef struct a{I t,r,d[3],p[2];}*A; 3 | #define P printf 4 | #define R return 5 | #define V1(f) A f(w)A w; 6 | #define V2(f) A f(a,w)A a,w; 7 | #define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}} 8 | I *ma(n){R(I*)malloc(n*4);}mv(d,s,n)I *d,*s;{DO(n,d[i]=s[i]);} 9 | tr(r,d)I *d;{I z=1;DO(r,z=z*d[i]);R z;} 10 | A ga(t,r,d)I *d;{A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r); 11 | R z;} 12 | V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;} 13 | V2(plus){I r=w->r,*d=w->d,n=tr(r,d);A z=ga(0,r,d); 14 | DO(n,z->p[i]=a->p[i]+w->p[i]);R z;} 15 | V2(from){I r=w->r-1,*d=w->d+1,n=tr(r,d); 16 | A z=ga(w->t,r,d);mv(z->p,w->p+(n**a->p),n);R z;} 17 | V1(box){A z=ga(1,0,0);*z->p=(I)w;R z;} 18 | V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn; 19 | A z=ga(w->t,1,&n);mv(z->p,a->p,an);mv(z->p+an,w->p,wn);R z;} 20 | V2(find){} 21 | V2(rsh){I r=a->r?*a->d:1,n=tr(r,a->p),wn=tr(w->r,w->d); 22 | A z=ga(w->t,r,a->p);mv(z->p,w->p,wn=n>wn?wn:n); 23 | if(n-=wn)mv(z->p+wn,z->p,n);R z;} 24 | V1(sha){A z=ga(0,1,&w->r);mv(z->p,w->d,w->r);R z;} 25 | V1(id){R w;}V1(size){A z=ga(0,0,0);*z->p=w->r?*w->d:1;R z;} 26 | pi(i){P("%d ",i);}nl(){P("\n");} 27 | pr(w)A w;{I r=w->r,*d=w->d,n=tr(r,d);DO(r,pi(d[i]));nl(); 28 | if(w->t)DO(n,P("< ");pr(w->p[i]))else DO(n,pi(w->p[i]));nl();} 29 | 30 | C vt[]="+{~<#,"; 31 | A(*vd[])()={0,plus,from,find,0,rsh,cat}, 32 | (*vm[])()={0,id,size,iota,box,sha,0}; 33 | I st[26]; qp(a){R a>='a'&&a<='z';}qv(a){R a<'a';} 34 | A ex(e)I *e;{I a=*e; 35 | if(qp(a)){if(e[1]=='=')R st[a-'a']=ex(e+2);a= st[ a-'a'];} 36 | R qv(a)?(*vm[a])(ex(e+1)):e[1]?(*vd[e[1]])(a,ex(e+2)):(A)a;} 37 | noun(c){A z;if(c<'0'||c>'9')R 0;z=ga(0,0,0);*z->p=c-'0';R z;} 38 | verb(c){I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;} 39 | I *wd(s)C *s;{I a,n=strlen(s),*e=ma(n+1);C c; 40 | DO(n,e[i]=(a=noun(c=s[i]))?a:(a=verb(c))?a:c);e[n]=0;R e;} 41 | 42 | main(){C s[99];while(gets(s))pr(ex(wd(s)));} 43 | -------------------------------------------------------------------------------- /mj.c: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | typedef char C; typedef long I; typedef void _; 5 | typedef struct a{I t,r,d[3],p[2];}* A; 6 | #define P printf 7 | #define R return 8 | #define D I*d 9 | #define S I*s 10 | #define DO(n,x){I i=0,_n=(n);for(;i<_n;++i){x;}} 11 | 12 | I*ma(I n ) { R(I*)malloc(n*4); } 13 | _ mv( D, S, n) { DO(n,d[i]=s[i]); } 14 | I tr(I r, D) { I z=1;DO(r,z=z*d[i]); R z; } // total number of cells. 15 | A ar(I t, r, D) { A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r);R z;} 16 | 17 | // print 18 | _ nl( ) { P("\n");} 19 | _ pi( i ) { P("%d ",i);} 20 | _ pr(A w ) { I r=w->r,*d=w->d,n=tr(r,d); 21 | P("[ "); DO(r,pi(d[i])) P("]: "); // print shape 22 | DO(n, pi(w->p[i])); // print values 23 | nl();} 24 | 25 | // verbs 26 | #define MO(fn) A fn(A w) 27 | #define DY(fn) A fn(A a, A w) 28 | MO( id){ P("id\n."); // identity function 29 | R w;} 30 | MO(iota){ I n=*w->p; // iota/enumerate 31 | A z=ar(0,1,&n); 32 | DO(n,z->p[i]=i); 33 | R z;} 34 | DY( nop){ P("nop.\n"); // no-op (J: "]") 35 | R w;} 36 | DY( add){ I r=w->r, *d=w->d, n=tr(r,d); 37 | A z=ar(0,r,d); 38 | DO(n,z->p[i]=a->p[i]+w->p[i]); 39 | R z;} 40 | 41 | // eval 42 | A st[26]; // storage for pronouns 43 | C vt[]="+!~<#,"; // verb table 44 | A (*mo[])()={ id, id, iota, id, id, id, id}, // monadic 45 | (*dy[])()={nop, add, nop, nop, nop, nop, nop}; // dyadic 46 | 47 | I qp(I a) { R a>='a'&&a<='z';} // is it a pronoun? 48 | I qv(I a) { R a<'a';} // is it a verb? 49 | A ev(I*e) { I a=*e; 50 | if(qp(a)){ // P("ev> pronoun: %c\n", (char)a); 51 | if(e[1]=='=') 52 | R st[a-'a']=ev(e+2); // set 53 | a=(I)st[a-'a'];} // get 54 | // -- right-to-left recursive evaluator 55 | R (qv(a)) ? (*mo[a])(ev(e+1)) 56 | : (e[1]) ? (*dy[e[1]])(a,ev(e+2)) 57 | : (A)a; } 58 | 59 | // read (nouns and verbs) 60 | I nn(C c ) { A z;if(c<'0'||c>'9') R 0; // nn only handles 0..9 61 | z=ar(0,0,0); *z->p=c-'0'; // create rank 0 array 62 | //P("nn> noun: %ld\n", *z->p); 63 | R (I)z;} // cast A->I and return 64 | I vb(C c ) { I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;} 65 | I*rd(C*s ) { I a,n=strlen(s),*e=ma(n+1); C c; 66 | DO(n,e[i]=(a=nn(c=s[i]))?a // noun? (single digit) 67 | :(a=vb(c))?a // verb? (see vt[]) 68 | :c); // else pronoun (a..z) 69 | e[n-1]=0; // strip linefeed 70 | //P("rd> n: %ld\n", n); 71 | //DO(n, P("rd> i: %ld, e[i]: %ld\n", i, e[i])); 72 | R e;} 73 | #define sz 99 74 | main() {C s[sz]; DO(26,st[i]=ar(0,0,0)) 75 | while(fgets(s,sz,stdin))pr(ev(rd(s)));} 76 | --------------------------------------------------------------------------------