home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / AAEMA95A.ZIP / MACROS.CC < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-06  |  33.0 KB  |  682 lines

  1. /* This is file MACROS.CC */
  2. #include "em.h"
  3. /*-----*/
  4. /* int ____; long int bp(){__SR(); ____=_bp; __SR(); return ____;}
  5. void BP(){int i=0; long*p=(long int*)bp();
  6. while(p) {i++; p=(long int*)*p;} for(;i>0;i--) fprintf(debug,"  ");} */
  7. /*-----*/
  8. char*CMN="current_macro",keychar,keyseqc[65]; val keyseq(keyseqc,_keyseq);
  9. macro*Record=0; var*globvars=0; int nglobvars=0; val*refaddr(val L);
  10. mark err(0,0); val comment("/*",2),tnemmoc("*/",2);
  11. /*-----*/
  12. KF(obey){val f; switch(T1.n){
  13. case 0: if(record) MOAN("can't call macro which is being recorded"); T1.m=Macro;
  14. case _macro: (*T1.m)(N); return;
  15. default: MOAN("obey() with bad arg or no arg");
  16. case _keyseq: f=T1.keyseq(); if(f.n==_bad) MOAN(f.s);
  17.     if(f.n!=_macro) MOAN("error in obey(): this key is not bound to a macro");
  18.     (*f.m)(N);}}
  19. /*-----*/
  20. KF(macromenu){macro*M; M=macro_menu(); if(!M) MOAN("aborted"); (*M)();};
  21. /*-----*/
  22. KF(namemacro) {int i; macro*M; val nam; if(T2.n!=_macro)
  23. T2=*getk(T2,"type key sequence bound to the macro (ctrlX E for current macro)");
  24. T1.getifn(T1t,"name to bind to the macro?");
  25. for(i=0;i<T1.n;i++) if(!isalnum(T1.s[i])) MOAN("name must be all alphanumeric");
  26. if(T1.n) {if(!isalpha(T1.s[0])) MOAN("name must start with a letter");
  27.     nam=named(T1); if(nam.n!=_unidfname) {
  28.     pr(CW,"'%s' is already a %t",T1.s,nam.typ()); MOAN(CW);}}
  29. if(!play) if(basemi.rec) {setrek(T1,T1.copy()); setrek(T2,keyseq.copy());}
  30. if(T2.n==_subr?T2.f==&obey:0) M=Macro; /* as 'ctrlX E' calls current macro */
  31. else if(T2.n==_macro) M=T2.m;
  32. else {pr(CW,"%s is not bound to a macro",&keyseq); MOAN(CW);}
  33. if(M->name) if(M->name!=CMN) {
  34.     pr(CW,"macro already named '%s': shall I rename it?",M->name);
  35.     if(!yesno(CW)) MOAN("user abort"); delete M->name;}
  36. M->name=copyof(T1);}
  37. /*-----*/
  38. KF(beginmacro) {macro*m; if(play) return; if(record) MOAN("already recording");
  39. Display="start macro"; if(Macro) if(Macro->name==CMN) Macro->name=0;
  40. if(!Macro?:Macro->bound.n?:Macro->name!=0)Macro=new macro();else Macro->empty();
  41. basemi.rec=0; record=Macro; thisstep.f=&_idle; laststep.del(); laststep.clear();
  42. if(T2.n==_keyseq) bindkeymacro(val(1,0),T2);
  43. if(T1.n>0) namemacro(val(1,0),T1,val(record));
  44. else {for(m=macros;m;m=m->next) if(m->name==CMN)
  45.     if(m->bound.n) m->name=0; else delete m; record->name=CMN;}}
  46. /*-----*/
  47. KF(endmacro) {if(play) return;
  48. Display="end macro"; if(!record) MOAN("not recording"); basemi.rec=0;
  49. record->tidy(); record=0; thisstep.f=&_idle; laststep.del(); laststep.clear();}
  50. /*-----*/
  51. KF(repeat) {if(play) {mi->rec=0; (*mi->prevstep)(N.i); return;}
  52. laststep(N.i); if(record)(*record)+=new macstep(kf(&repeat),N); rept=1;}
  53. /*-----*/
  54. KF(prmacro){Macro->print();}
  55. /*-----*/
  56. KF(prmacros) {prvars(globvars); macro*M; for(M=macros;M;M=M->next) M->print();}
  57. /*-----*/
  58. macro*macros=0;
  59. /*-----*/
  60. macstep laststep,thisstep;
  61. val specialchars("\"\\^`",4); /* chars that need \ before as selves in string */
  62. char*rsvword[]={0};
  63. char*Keysort[]={"magicstring","string","unbound","subroutine","macro","char",
  64.   "keyarray","buffer","int","keysequence","reservedword","unidentifiedname",
  65.   "call","bad","uncheckedsubr","function","functionwithinfo","reference","type",
  66.   "float","label",0};
  67. char**keysort=Keysort+2;
  68. /*-----*/
  69. #define Bad(s) ({err=*this; *this=x; return val(s,_bad);})
  70. #define badq(s) if((s).n==_bad) return (s)
  71. #define Badq(s,delendum) if((s).n==_bad) {(delendum).del(); return (s);}
  72. /*-----*//* skip whites and comments */
  73. void mark::Skip(){int n; char*s;
  74. A: n=r->n; s=r->s;
  75. C: if(c<n) {if(s[c]==' '?:s[c]==9) {c++; goto C;}}
  76. else if(r->next) {r=r->next; c=0; goto A;} else return;
  77. if(c>n-2 ?: s[c]!='/' ?: s[c+1]!='*') return; c+=2;
  78. B: if(c<=n-2) if(s[c]=='*') if(s[c+1]=='/') {c+=2; goto A;}
  79. if(c<n) c++; else if(r->next) {r=r->next;c=0;} else MOAN("missing */"); goto B;}
  80. /*-----*/
  81. int mark::thisch(char C){Skip(); int i; if(i=(**this==C)) ++*this; return i;};
  82. /*-----*//* look for s */
  83. int mark::string(val s){Skip(); if(c+s.n>r->n) return 0;
  84.     if(!strncmp(&r->s[c],s.s,s.n)) {c+=s.n; return 1;} return 0;}
  85. /*-----*/
  86. /* int mark::string(val s){Skip(); mark e=here(*this,s);
  87. if(!e.r) return 0; *this=e; return 1;} */
  88. /*-----*//* if n=0, s = 0 or 1 or -> standard empty string, do not delete it */
  89. void val::del(){int i; call*c; switch(n){
  90. case _keyseq: case _unidfname: delete s; break;
  91. case _call: for(i=(c=C)->n-1;i>=0;i--) c->arg[i].del(); delete c; break;
  92. default: if(n>0 ?: magic()) delete s;} n=0; s=0;}
  93. /*-----*/
  94. char*copyof(char*s,int n/*=0*/){if(!n) n=strlen(s); if(!s?:!n) return "\000";
  95. char*t=new char[n+1]; memcpy(t,s,n); t[n]=0; return t;}
  96. /*-----*/
  97. char*copyof(const val&s){if(!s.s?:s.n<=0) return "\000";
  98. char*t=new char[s.n+1]; memcpy(t,s.s,s.n); t[s.n]=0; return t;}
  99. /*-----*/
  100. val named(val name){int i; Subr*s; char*w; macro*m; val f; var*v;
  101. if(s=namedsubr(name)) return val(s); /* subr name */
  102. for(m=macros;m;m=m->next) if(m->name) if(name==m->name) return val(m);
  103. for(i=0;w=rsvword[i];i++) if(name==w) return val(i,_rsvword);/* reserved word */
  104. for(i=0;i<255;i++) if(name==altnames[i]) return val(256+i,_char); /*****/
  105. for(i=0;f=keynames[i],f.s;i++) {if(name==f.s) return val(f.n,_char);}
  106. if(name.n==5) if(!strncmp(name.s,"ctrl",4)) return val(name.s[4]&31,_char);
  107. for(i=0;w=funcname[i].name;i++) if(name==w) return val(&funcname[i]);
  108. for(i=-2;w=keysort[i];i++) if(name==w) return val(-i,_type);
  109. for(v=globvars;v;v=v->next) if(name==v->name) return val(v);
  110. if(Record) for(v=Record->vars;v;v=v->next) if(name==v->name) return val(v);
  111. return val(copyof(name),_unidfname);}
  112. /*-----*/
  113. val mark::label(){mark x=*this; Skip(); if(!is_alpha()) Bad("not a name");
  114. int y=c; while(is_alnum()) ++*this; int z=c;
  115. if(!thisch(':')) Bad("no ':' after label"); return named(val(r->s+y,z-y));}
  116. /*-----*/
  117. val mark::name(){mark x=*this; Skip(); if(!is_alpha()) Bad("not a name");
  118. int y=c; while(is_alnum()) ++*this; return named(val(r->s+y,c-y));}
  119. /*-----*/
  120. val mark::number(){int C,i=0; mark x=*this; Skip();
  121. if((C=**this-'0')<0?:C>9) Bad("not a number");
  122. do {c++; i=10*i+C;} while((C=**this-'0')<0?0:C<=9); return val(i);}
  123. /*-----*//* look for text in " " */
  124. val mark::string(){int i,j,k,m=0,magic=0; char C,W[i=lwand(strsize)+1];
  125. mark x=*this; for(i--;i>=0;i--) W[i]=0;
  126. if(thisch('"')) for(j=0;;c++) {
  127.     if(magic) {m=1; magic=0; W[j>>3]|=128>>(j&7);}
  128.     if(j>=strsize-1) Bad("string too long");
  129.     switch(C=**this){
  130.     case '`': magic=1; break; /* next char is magic */
  131.     case '\\': c++; C=**this;
  132.         if(C<'0'?0:C<'8') {k=C-'0'; c++; C=**this; /* \ and 3 octal digits */
  133.             if(C<'0'?0:C<'8') {k=k*8+C-'0'; c++; C=**this;
  134.                 if(C<'0'?0:C<'8') {k=k*8+C-'0'; c++; C=**this;}} c--;CW[j++]=k;}
  135.         else {if(!eol()) CW[j++]=**this; /* code char as itself */} break;
  136.     case '^': c++; CW[j++]=**this&31; break; /* control char */
  137.     case '"': CW[j]=0; c++; if(!m) return val(j?copyof(CW,j):"\000",j);
  138.     k=lwand(j); for(i=0;i<k;i++) CW[j+1+i]=W[i];
  139.     return val(copyof(CW,j+1+k),j|0x80000000); /* magic string */
  140.     case LF: Bad("eol in string");
  141.     default: CW[j++]=C;}}
  142. Bad("not a string");}
  143. /*-----*/
  144. val mark::elem(){char C; mark x=*this; Skip();
  145. val s=number(); if(s.n!=_bad) return s;
  146. s=name();       if(s.n!=_bad) return s;
  147. s=string();     if(s.n!=_bad) return s;
  148. if(eol()) Bad("(part of) expression missing at eol");
  149. if((C=**this)=='(') {c++; s=expr(); badq(s); if(thisch(')')) return s;
  150.     s.del(); Bad("rubbish or eol found instead of )");}
  151. Bad(strncmp(s.s,"not a ",6)?s.s:"not an expression element");}
  152. /*-----*/
  153. typedef struct{char res,Lr,L,Rr,R; char*op; char pr; func*f; char*com;} op_use;
  154. int npriosused;
  155. char*Eq=" =="+1,*Ne=" !="+1,*Ge=" >="+1,*Le=" <="+1,*Gt=" >"+1,*Lt=" <"+1,
  156. *Alc=" ="+1,*Add=" +"+1,*Sub=" -"+1,*Tim=" *"+1,*Div=" /"+1;
  157. char*Ops[]={Alc,Add,Sub,Tim,Div,0}; char op_from_right[27]={[14]1};
  158. op_use *PP[28]={0},ops[]={ /*** keep these entries in priority order ***/
  159. {_int   ,1,_int   ,0,_int   ,Alc,14,_allocate,0},
  160. {_string,1,_string,0,_string,Alc,14,_allocate,0},
  161. {_char  ,1,_char  ,0,_char  ,Alc,14,_allocate,0},
  162. {_int   ,0,_string,0,_string,Eq,  7,_eq,      0},
  163. {_int   ,0,_string,0,_string,Ne,  7,_ne,      0},
  164. {_int   ,0,_int   ,0,_int   ,Eq,  7,_eq,      0},
  165. {_int   ,0,_int   ,0,_int   ,Ne,  7,_ne,      0},
  166. {_int   ,0,_int   ,0,_int   ,Ge,  6,_ge,      0},
  167. {_int   ,0,_int   ,0,_int   ,Le,  6,_le,      0},
  168. {_int   ,0,_int   ,0,_int   ,Gt,  6,_gt,      0},
  169. {_int   ,0,_int   ,0,_int   ,Lt,  6,_lt,      0},
  170. {_int   ,0,_int   ,0,_int   ,Add, 4,_plus,    0},
  171. {_int   ,0, 0     ,0,_int   ,Add, 4,_same,    0},
  172. {_int   ,0,_int   ,0,_int   ,Sub, 4,_minus,   0},
  173. {_int   ,0, 0     ,0,_int   ,Sub, 4,_neg,     0},
  174. {_int   ,0,_int   ,0,_int   ,Tim, 3,_times,   0},
  175. {_int   ,0,_int   ,0,_int   ,Div, 3,_divide,  "rounds towards -inf; x/0 = 0"},
  176. {0,0,0,0,0,0,27,0,0}};
  177. enum{MINUSPR=4};
  178. /**** and secure all func's & subr's against bad values in args ****/
  179. /*-----*//* set up info tables re operators */
  180. void set_up_PP(){op_use*B; int i=0,j=0; if(PP[0]) return;
  181. for(B=ops;B->op;B++) {if(j!=B->pr) j=(PP[i++]=B)->pr; B->op[-1]=i-1;}
  182. PP[npriosused=i]=B;}
  183. /*-----*/
  184. int display_op_uses(){int i,j=1; op_use*P; set_up_PP();
  185. display("operator uses allowed in macros (# = must be a variable)",0,0,Green);
  186. for(i=0;(P=&ops[i])->op;i++) {
  187.     if(P->L) pr(CW,"%s%t%T",P->Lr?"#":" ",P->L,9); else pr(CW,"%T",9);
  188.     pa(CW,"%-2s %s%t%T: returns %t%T: priority %1d %s",P->op,
  189.       P->Rr?"#":" ",P->R,11,P->res,28,npriosused-P->op[-1],P->com?:"");
  190.     if(j==gp_Rows-1) {display("(More)",j,0,Green); get_key(); j=0;}
  191.     display(CW,j++,0,Orange);}
  192. return j;}
  193. /*-----*/
  194. char*mark::op(int p){mark x=*this; Skip();
  195. char*s, a=**this, b=c+1>=r->n?CR:r->s[c+1]; op_use*B,*C=PP[p+1];
  196. for(B=PP[p];B<C;B++) if(a==(s=B->op)[0]) if(!s[1]?1:b==s[1]) goto A;
  197. err=*this; *this=x; return 0; A: c++; if(s[1]) c++; return s;}
  198. /*-----*/
  199. val callop(val L,char*op,val R){
  200. int Lt=L.type(),Rt=R.type(),prio=op[-1]; op_use*B,*C=PP[prio+1]; val t,ar[3];
  201. for(B=PP[prio];B<C;B++) if(op==B->op) if(Lt==B->L) if(Rt==B->R)
  202.   if(B->Lr?L.n==_ref:1) if(B->Rr?R.n==_ref:1) goto OK;
  203. pr(CW,"type error in expr:");
  204. if(L.n) pa(CW," %s %t",   L.n==_ref?"ref":"nonref",Lt);
  205. pa(CW,     " %s %s %t",op,R.n==_ref?"ref":"nonref",Rt);
  206. L.del(); R.del(); return val(CW,_bad);
  207. OK: ar[0]=ff(B->f); ar[1]=L; ar[2]=R; t=call_n(3,B->res,B->pr,B->op,ar);
  208. if(L.known_now()) if(R.known_now()) {val u=t(); t.del(); return u;} return t;}
  209. /*-----*/
  210. val mark::expr(int p/*=0*/){char *Op; val X,*Y,Z; int fr; mark x=*this;
  211. set_up_PP(); Skip(); if(eol()) Bad("expression missing at eol");
  212. if(p>=npriosused) return Call();
  213. Op=op(p); X=expr(p+1); badq(X); if(Op) {X=callop(val(),Op,X); badq(X);}
  214. if(fr=op_from_right[PP[p]->pr]) Y=&X.C->arg[2]; else Y=&X;
  215. while(Op=op(p)) {Z=monexpr_upto(p+1); Badq(Z,X); *Y=callop(*Y,Op,Z);
  216.     if(fr) {Badq(*Y,X); Y=&Y->C->arg[2];}} return X;}
  217. /*-----*/
  218. val mark::monexpr_upto(int p){mark x=*this; Skip();
  219. val X; char*op, a=**this, b=c+1>=r->n?CR:r->s[c+1]; op_use*B,*C=PP[p];
  220. for(B=PP[0];B<C;B++) if(a==(op=B->op)[0]) if(!op[1]?1:b==op[1]) goto A;
  221. err=*this; *this=x; return expr(p); A:
  222. c++; if(op[1]) c++; X=monexpr_upto(p); badq(X); X=callop(val(),op,X); return X;}
  223. /*-----*/
  224. static var*declare(char*name,int type){
  225. if(type==_label) return Record->vars=new var(name,type,0,Record->vars);
  226. else if(Record)
  227.     return Record->vars=new var(name,type,Record->nvars++,Record->vars);
  228. else return globvars=new var(name,type,nglobvars++,globvars);}
  229. /*-----*/
  230. int val::type(){int i; short*Z; switch(n) {
  231. default: return magic()?_magic:notstring()?n:_string;
  232. case _ref: return v->type;
  233. case _subr: case _Subr: case _macro: return 0;
  234. case _func: i=(Z=Funcinfo()->args)[0]; return i!=_adinf?i:Z[1];
  235. case _Func: i=(Z=Fn        ->args)[0]; return i!=_adinf?i:Z[1];
  236. case _call: return C->type;}}
  237. /*-----*/
  238. int val::typ(){switch(n) {
  239. default: return magic()?_magic:notstring()?n:_string;
  240. case _ref: return v->type;}}
  241. /*-----*/
  242. int val::checktype(int typ){int m=type(); if(typ==m ?: typ==666) return 1;
  243. switch(typ){
  244. case _magic: return m==_string;
  245. case _keyseq: return m==_char;
  246. case _char: return m==_string;
  247. case _label: if(m==_unidfname) {*this=named(s); /* already thus declared? */
  248.     if(n==_unidfname) {n=_ref; v=declare(copyof(s),_label);} return 1;}}
  249. return 0;}
  250. /*-----*/
  251. val val::convto(int t){int f=typ(); if(t==f) return *this; switch(f){
  252. case _string: if(t==_magic?:t==_char) return *this;
  253. case _char: if(t==_keyseq) return *this; break;}
  254. pr(CW,"can't convert %t to %t",f,t); MOAN(CW); return val();}
  255. /*-----*/
  256. int val::known_now(){
  257. switch(n){case _subr: case _macro: case _call: case _Subr:
  258. case _func: case _Func: case _ref: return 0;} return 1;};
  259. #define MoaN(s) ({err=*this; *this=x; Moan=s; goto BAD;})
  260. /*-----*/
  261. val mark::Call(){
  262. val t,u,args[32],N,Arg[4]; int i=0,j,k,l,n,se; mark x=*this;
  263. char*ac; mark q[33]; static short MA[]={_int,0}; jmp_buf*oldbad,failed;
  264. short*a; Skip(); q[0]=*this; n=0; if(eol()) MoaN("matter missing at eol");
  265. t=elem(); badq(t); args[0]=t; q[1]=*this; n=1;
  266. if(thisch('(')) if(!thisch(')')) {
  267.     do {u=expr(); q[i=n+1]=*this; if(u.bad()) {Moan=u.s; goto BAD;}
  268.     if(n>31) {u.del(); MoaN("> 31 args");}
  269.     args[n++]=u;} while(thisch(','));
  270.     if(!thisch(')')) MoaN("rubbish after arg");}
  271. switch(t.n) {
  272. case _Subr: a=t.S->args-1;
  273.     Arg[1]=val(1,0); Arg[2]=val(); Arg[3]=val();
  274.     for(i=j=1;(k=a[j])?i<n:0;j++) if(args[i].checktype(k)) Arg[j]=args[i++];
  275.     if(i!=n) goto BADARG;
  276.     Arg[0]=kf(t.S->f); return val(call_n(4,0,0,t.S->name,Arg));
  277. case _Func: a=t.Fn->args; if(se=(a[0]==_adinf)) a++;
  278.     for(i=j=1;i<n;i++) {
  279.     if(!a[j]) MoaN("too many args");
  280.     if(!args[i].checktype(a[j])) {a++; goto BADARG;}
  281.     if(a[j+1]!=_adinf) j++;}
  282.     if(a[j]) if(a[j+1]!=_adinf) MoaN("too few args");
  283.     k=a[0]; if(se) goto Z;
  284.     for(i=1;i<n;i++) if(!args[i].known_now()) goto Z; /* can I find value now?*/
  285.     oldbad=bad; bad=&failed; if(setjmp(*bad)) goto BADD;
  286.     t=t.Fn->f(n,args); for(i=0;i<n;i++) args[i].del(); bad=oldbad; return t;
  287. BADD: err=x; bad=oldbad; return val(Moan,_bad);
  288. /* case _func: k=Funcinfo()->args[0]; */
  289. Z:  return val(call_n(n,k,0,t.Fn->name,args));
  290. case _macro: i=1; N=val(1,0); if(i<n) if(args[i].checktype(_int)) N=args[i++];
  291.     if(i!=n) {a=MA; goto BADARG;}
  292.     Arg[0]=kf(&obey); Arg[1]=N; Arg[2]=t; Arg[3]=val();
  293.     return val(call_n(4,0,0,"obey",Arg));
  294. case _type: if(n!=1) {pr(CW,"'%t' should not have args",t.i); i=1; MoaN(CW);}
  295.     return t;
  296. default: if(n==1) return t; /* has no args so isn't a call */
  297.     pr(CW,"a %t can't be a call base",t.n); i=0; MoaN(CW);}
  298. BADARG:
  299. if(a[1]) {pr(CW,"args %sshould be:",t.n==_Func?"":"(can be omitted) ");
  300.     for(l=1;k=a[l];l++) {if(k==_adinf) {pa(CW,"s"); /* plural */ break;}
  301.     else pa(CW," %t",k);}}
  302. else pr(CW,"should have no args");
  303. ac=CW+strlen(CW);
  304. if(n) {pa(CW," args are:"); for(l=1;l<n;l++) pa(CW," %t",args[l].type());}
  305. else pa(CW," has no args");
  306. *ac=0; Display=CW; Moan=ac+1;
  307. BAD: err=q[i]; for(i=0;i<n;i++) args[i].del(); *this=x; return val(Moan,_bad);;}
  308. #define Bad(s) ({err=*this; *this=x; return val(s,_bad);})
  309. /*-----*/
  310. char*not_a_decl="not a decl";
  311. val mark::decl(){val args[32]; int i=0,n=0; mark q[33],x=*this; Skip();
  312. if(eol()) return val(); q[0]=*this; args[0]=name(); q[1]=*this; n=1;
  313. if(args[0].n!=_type?: (Skip(), !is_alnum())) {Moan=not_a_decl; goto BAD;}
  314. do {val u=name(); q[i=n+1]=*this;
  315.     if(u.bad()) {Moan="bad name in decl"; goto BAD;}
  316.     if(n>31) {u.del(); Moan="declaration has > 31 args"; goto BAD;}
  317.     if(u.n!=_unidfname) {
  318.     u.print(Moan=CW); pa(CW," is already a %t",u.typ()); u.del(); goto BAD;}
  319.     args[n++]=u;} while(thisch(','));
  320. return val(call_n(n,0,0,keysort[-args[0].i],args));
  321. BAD: err=q[i]; for(i=0;i<n;i++) args[i].del(); *this=x; return val(Moan,_bad);;}
  322. /*-----*/
  323. call*call_n(int n,int type,int pr,char*name,val*a){
  324. call*c=(call*)myalloc(sizeof(call)+(n-1)*sizeof(val));
  325. c->n=n; c->type=type; c->pr=pr; c->name=name;
  326. int i; val*b=c->arg; for(i=0;i<n;i++) b[i]=a[i]; return c;}
  327. /*-----*/
  328. KF(_idle){}
  329. /*-----*/
  330. static macstep*jump=0;
  331. KF(go_to){if(T1.n==_ref) if(T1.v->type==_label) jump=(macstep*)(T1.v->offset);}
  332. /*-----*/
  333. KF(If){} /* 'if' is handled elsewhere */
  334. /*-----*/
  335. subr*subrcalled(val V){if(V.n==_call) V=V.C->arg[0]; switch(V.n){
  336. case _subr: return V.f; case _Subr: return V.S->f; default: return 0;}}
  337. /*----- is val a char or the name of a (char or special key)? */
  338. int val::charval(){
  339. if(n==1) return s[0]; /* string with one char */
  340. if(n==_char) return i;
  341. if(n<1) return -1; int j;
  342. if(n<4) for(j=0;j<255;j++) if(*this==altshortnames[j]) return j+256; return -1;}
  343. /*-----*/
  344. void val::expandkeyseq(char*K,int plain/*=0*/){int e,j,k,p; char *x,*S=s,a[3];
  345. if(n==_char) if(S=a,i&~255) {a[0]=3; a[1]=0; a[2]=i&255;} else {a[0]=2; a[1]=i;}
  346. else if(n!=_keyseq) MOAN("BUG: expandkeyseq bad arg"); p=(byte)S[0];
  347. if(plain) {for(e=1,K[0]=0;e<p;e++) if(S[e]) {
  348.     strcat(K,keyname((byte)S[e],e>1?!S[e-1]:0)); strcat(K," ");}
  349.     e=strlen(K); K[e-1]=0; return;}
  350. strcpy(K,"keyseq("); k=6;
  351. for(e=1;e<p;e++) if(S[e]) {x=keyname((byte)S[e],e>1?!S[e-1]:0);
  352.     if(x[1]) {strcat(K,x); k=strlen(K);}
  353.     else {j=(byte)*x;
  354.     K[k++]='"'; if(j=='"'?:j=='\\') K[k++]='\\'; K[k++]=j; K[k++]='"';}
  355.     K[k++]=','; K[k]=0;}
  356. K[k-1]=')'; K[k]=0;}
  357. /*-----*/
  358. #undef Bad
  359. /*----- translate buffer to macro */
  360. void translate(buffer*BB){int i; buffer*BBB=B; macro*m;
  361. val *arg,*K=0,N,T,T1,T2,U,W; Record=0; char spec; mark par,x,y; subr*Z;
  362. jmp_buf*oldbad=bad,failed; bad=&failed; if(setjmp(*bad)) goto BAD;
  363. /* if(record) {Moan="can't read in macros while recording a macro"; goto BAD;}*/
  364. T=val(); if(B!=BB) BB->go_to();
  365. for(i=0;i<basemi.nvars;i++) basemi.stack[i].del();
  366. delete globvars; delete basemi.stack;
  367. globvars=0; basemi.stack=0; nglobvars=basemi.nvars=0; par=mark(B->text.next,0);
  368. NEXTINSTR: B->dot=par; B->dotcc=-1; B->display();
  369. x=par; par.Skip(); err=par; spec=0;
  370. if(par.eof()) {if(B!=BBB) BBB->go_to(); bad=oldbad; Moan=0; return;} y=par;
  371. if(Record) if(T=par.label(), T.n!=_bad) {
  372.     if(T.n==_unidfname) {T.n=_ref; T.v=declare(copyof(T.s),_label);}
  373.     if(T.n==_ref) {*Record+=new macstep(T);
  374.         if(T.v->type==_label) {
  375.             if(T.v->offset) {Moan="label defined twice"; goto BAD;}
  376.             T.v->offset=(long int)Record->last; goto NEXTINSTR;}
  377.         else {pr(Moan=CW,"this label is already declared as a %t",T.v->type);
  378.             goto BAD;}}
  379.     else {pr(Moan=CW,"a %t can't be a label",T.n); goto BAD;}}
  380. T=par.decl(); if(T.n!=_bad ?: T.s!=not_a_decl) goto A; Moan=0; par=y;
  381. spec=par.thisch('#'); T=par.expr(); if(T.n==_bad) {Moan=T.s; goto BAD;}
  382. A: if(!par.thisch(';')) {
  383.     err=par; par=x; T.del(); Moan="rubbish after command"; goto BAD;}
  384. if(spec) switch(T.n) {
  385. default: pr(Moan=CW,"%t after '#'",T.typ()); goto BAD;
  386. case _bad: Moan=T.s; goto BAD;
  387. case _subr: Z=T.f; goto Y;
  388. case _Subr: Z=T.S->f; Y: N=val(1,0); T1=val(); T2=val(); goto Z;
  389. case _call: switch(U=(arg=T.C->arg)[0], Z=U.f, U.n) {
  390.     case _Subr: U=kf(Z=U.S->f);
  391.     case _subr: N=arg[1]; T1=arg[2]; T2=arg[3];
  392. Z:    if(Z==&unbindkey) {if(T1.n) if(K=&T1.keyseq()) K->unbind(); K=0;}
  393.     else if(Z==&buffer_) {if(T1.n) buffer_(N,T1,T2); BB->go_to();}
  394.     else if(Z==&beginmacro) { /* new macro named T1 bound to key T2 */
  395.         if(T2.n) {if(Moan=(K=&T2.keyseq())->moanifbound(T2,0)) goto BAD;
  396.         (Record=new macro())->bound=keyseq.copy();
  397.         if(T1.n>0) namemacro(val(1,0),T1,val(Record)); *K=*Record;}
  398.         else {K=0; Record=new macro();
  399.         if(T1.n>0) namemacro(val(1,0),T1,val(Record));
  400.         else {for(m=macros;m;m=m->next) if(m->name==CMN)
  401.             if(m->bound.n) m->name=0;
  402.             else if(Macro!=record) delete m;
  403.             Record->name=CMN; record=0; Macro=Record;}}}
  404. /* unnamed & unbound macro terminates and replaces current macro */
  405.     else if(Z==&endmacro) {Record=0; K=0; break;}
  406.     else {Moan="wrong subroutine after '#'"; goto BAD;} break;
  407.     default: pr(Moan=CW,"call of a %t after '#'",U.n); goto BAD;}
  408.     break;}
  409.  
  410. else switch(T.n) {
  411. case _bad: Moan=T.s; goto BAD;
  412. case _rsvword: pr(Moan=CW,"'%s' used wrongly",rsvword[T.i]); goto BAD;
  413. case _unidfname: pr(Moan=CW,"'%s' not known",T.s); goto BAD;
  414. default: pr(Moan=CW,"this is a %t",T.typ()); goto BAD;
  415. case _Subr: case _subr: case _Func: case _macro: *Record+=new macstep(T); break;
  416. case _call: U=(arg=T.C->arg)[0];
  417.     if(U.n!=_type)if(!Record){Moan="instruction not in a macro body"; goto BAD;}
  418.     switch(U.n) {
  419.     case _type: switch(U.i) {
  420.     default: Moan="can't declare this type of variable yet"; goto BAD;
  421.     case _int: case _string: for(i=1;i<T.C->n;i++) {W=T.C->arg[i];
  422.         if(W.n==_unidfname) W=named(val(W.s)); if(W.n!=_unidfname) {
  423.         W.print(Moan=CW); pa(CW," is already a %t",W.typ()); goto BAD;}
  424.         declare(W.s,U.i);}} break;
  425.     case _Subr: case _subr: *Record+=new macstep(U,arg[1],arg[2],arg[3]);
  426.         break;
  427.     case _macro: *Record+=new macstep(U,arg[1]); break;
  428. /*    case _macro: *Record+=new macstep(kf(&obey),arg[1],U); break;*/
  429.     case _Func: case _func: *Record+=new macstep(T); T=val(); break;
  430.     default: pr(Moan=CW,"call base is a %t",U.typ()); goto BAD;}}
  431. goto NEXTINSTR;
  432. BAD: bad=oldbad; BB->go_to(); T.del(); B->dotcc=-1; err.c<?=err.r->n;B->dot=err;
  433. if(Record) {if(K) *K=val(); delete Record; Record=0;} MOAN(Moan);}
  434. /* unbind & delete incomplete macro */
  435. /*-----*/
  436. #define __(name,Name,args) {&name,0,Name,args}
  437. val __idle(int i,val*v){return val();}
  438. Func anonfunc=__(__idle,"###",0); Subr anonsubr=__(_idle,"@@@",0);
  439. /*-----*/
  440. Subr*val::Subrinfo(){reg int i; reg char*s;
  441. for(i=0;s=subrname[i].name;i++) if(f==subrname[i].f) return &subrname[i];
  442. return &anonsubr;}
  443. /*-----*/
  444. Func*val::Funcinfo(){reg int i; reg char*s;
  445. for(i=0;s=funcname[i].name;i++) if(fn==funcname[i].f) return &funcname[i];
  446. return &anonfunc;}
  447. /*-----*/
  448. char*val::Subrname(){return f ?Subrinfo()->name:"<<unknown subroutine>>";}
  449. char*val::Funcname(){return fn?Funcinfo()->name:"<<unknown function>>";}
  450. /*-----*/
  451. char*chname(int c){static char ct[3]="^ ",sc[3]="\\ ",cc[2]=" ",cs[5]="\\000";
  452. c&=255; if(c>=128) {pr(cs,"\\%03o",c); return cs;}
  453. if(specialchars>>c) {sc[1]=c; return sc;}
  454. if(c<32) {ct[1]=c+64; return ct;} cc[0]=c; return cc;}
  455. /*----- if ')' last before B->dot, replace it with ',', else insert '(' */
  456. void start_an_arg(){int i=!B->dot.c?0:B->dot.r->s[B->dot.c-1]==')';
  457. if(i) B->dot.bs(); *B+=i?',':'(';}
  458. /*-----*/
  459. val val::copy(){switch(n){
  460. default: if(magic()) {int i=n&0x7fffffff; return val(copyof(s,i+1+lwand(i)),n);}
  461.     if(n<=0) return *this; return val(copyof(s,n),n);
  462. case _keyseq: return val(copyof(s,(byte)s[0]),n);
  463. case _unidfname: return val(copyof(s,0),n);}}
  464. /*-----*/
  465. void prvars(var*V){int i,j; var*v; int Nt[_typeend-_typebeg],*nt=Nt-_typebeg;
  466. for(i=_typebeg;i<_typeend;i++) nt[i]=0;
  467. for(j=0,v=V;v;v=v->next) {nt[v->type]++; j++;}
  468. if(j) for(i=_typebeg;i<_typeend;i++) if(nt[i]) if(i!=_label) {
  469.     pb("%t ",i); for(v=V;v;v=v->next) if(v->type==i) pb("%s,",v->name);
  470.     B->dot.bs(); *B+=";\n";}}
  471. /*-----*/
  472. void macro::print(){macstep *A; char*N=name?:CMN; *B+="#beginmacro";
  473. if(bound.n) if(N!=CMN) pb("(%S,%K)",N,&bound); else pb("(%K)",&bound);
  474. else if(N!=CMN) pb("(%S)",N); *B+=';'; newline(); prvars(vars);
  475. for(A=text;A;A=A->next) A->print(); *B+="#endmacro;\n";}
  476. /*-----*/
  477. void prsubrargs(val f,val N,val T1,val T2){f.print();
  478. if(N.n ?:(uns int)N.s >=4096) {start_an_arg();  N.print(); *B+=')';}
  479. if(T1.n?:(uns int)T1.s>=4096) {start_an_arg(); T1.print(); *B+=')';}
  480. if(T2.n?:(uns int)T2.s>=4096) {start_an_arg(); T2.print(); *B+=')';}}
  481. /*-----*/
  482. void macstep::print(){val v; switch(f.n){
  483. case _Subr: if(f.S->f==&_idle) return; break;
  484. case _subr: if(f.f==&_idle) return; break;
  485. case _macro: if(f.m->name) break; v=kf(obey);
  486.     macstep(v,N,f.m->bound,val()).print(); return;
  487. default: if(!f.magic()) if(f.notstring()) break;
  488. case _char: case _keyseq: case _int: pb("*** "); break;
  489. case _rsvword: pb("*** reserved: "); break;
  490. case _ref: pb("%s: ",f.v->name); return;}
  491. prsubrargs(f,N,T1,T2); *B+=';'; newline();}
  492. /*-----*/
  493. void val::print(char*Z/*=(char*)_buffer*/,int pr/*=1000*/){
  494. int j,k,p; val*a; char*z;
  495. if(this) switch(n){
  496. default: if((j=type())<=0) p_r(Z,"<<<%t>>>",j); else p_r(Z,"%v",this); break;
  497. case 0: if(!s) p_r(Z,"%s","<<<null>>>"); else p_r(Z,"\"\""); break;
  498. case _type: p_r(Z,keysort[-i]); break;
  499. case _keyseq: p_r(Z,"%K",this); break;
  500. case _Subr: p_r(Z,S->name); break;
  501. case _subr: p_r(Z,Subrname()); break;
  502. case _Func: p_r(Z,Fn->name); break;
  503. case _func: p_r(Z,Funcname()); break;
  504. case _macro: if(m->name) p_r(Z,m->name);
  505.     else if(m->bound.n) p_r(Z,"%K",&m->bound);
  506.     else p_r(Z,"<<<unnamed unbound macro>>>"); break;
  507. case _char: if(i<256) p_r(Z,"\"%s\"",chname(i));
  508.     else if(z=altnames[i&255]) p_r(Z,"%s",z);
  509.     else p_r(Z,"<<<char 0 %1d>>>",i&255); break;
  510. case _buffer: p_r(Z,"<<<buffer \"%s\">>>",b->name); break;
  511. case _int: z="%1d"; if(i<0) if(pr<=MINUSPR) z="(%1d)"; p_r(Z,z,i); break;
  512. case _rsvword: p_r(Z,"%s",rsvword[i]); break;
  513. case _unidfname: p_r(Z,"<<<unknown word: %s>>>",s); break;
  514. case _bad: p_r(Z,"<<<bad parsing: %s>>>",s); break;
  515. case _call: if(!C) break; p=C->n; a=C->arg; if(!a) break;
  516.     if(a[0].n==_func) {if(pr) goto EXPR; else p_r(Z,C->name);}
  517.     else if(a[0].n==_subr) {prsubrargs(a[0],a[1],a[2],a[3]); break;}
  518.     else a[0].print();
  519.     if(p<2) break;
  520.     for(j=1;j<p;j++) {start_an_arg(); a[j].print(); p_r(Z,")");} break;
  521. EXPR: p=C->pr; j=1; k=0;
  522.     if(op_from_right[p]) {j=0; k=1;} if(pr<=p) p_r(Z,"(");
  523.     if(a[1].n?:a[1].i) a[1].print(Z,p+j); p_r(Z,C->name); a[2].print(Z,p+k);
  524.     if(pr<=p) p_r(Z,")"); break;
  525. case _ref: p_r(Z,v->name); break;}}
  526. /*-----*/
  527. void macstep::del(){f.del(); N.del(); T1.del(); T2.del(); clear();}
  528. /*----- remove pointers to buffers & macros which are being deleted */
  529. void del_every(val f,keyarray&ka){int i,n=ka.n; val*F=ka.a;
  530.   for(i=0;i<n;i++,F++) if(F->n==_keyarray) {del_every(f,*F->k); return;}
  531.   else if(f==*F) F->n=F->i=0;}
  532. void del_every(val f,val&m){val*a; int i,n; /* look in macro args */
  533.   if(m.n==_call) {a=m.C->arg; n=m.C->n; for(i=0;i<n;i++) del_every(f,*a++);}
  534.   else if(f==m) m.n=m.i=0;}
  535. void del_every(val f,macstep*M){for(;M;M=M->next){del_every(f,M->f);
  536.   del_every(f,M->N); del_every(f,M->T1); del_every(f,M->T2);}}
  537. void del_every(val f){macro*m; for(m=macros;m;m=m->next) del_every(f,m->text);
  538.   del_every(f,&thisstep); del_every(f,&laststep); del_every(f,keys);}
  539. /*-----*/
  540. macro::~macro(){macro**I; del_every(val(this));
  541. for(I=&(macros);*I;I=&((*I)->next)) if(*I==(this)) {*I=(*I)->next; break;}
  542. empty();};
  543. /*----- delete all macsteps in macro */
  544. void macro::empty(){macstep *A,*B; if(bound.n) delete bound.s; delete vars;
  545. if(name!=CMN) delete name; for(B=text;A=B;B=A->next) delete A; text=last=0;}
  546. /*----- macro+=macstep : append macstep to macro */
  547. void macro::operator+=(macstep*m){if(play?:!this) return;
  548. if(last) last->next=m; else text=m; (last=m)->next=0;}
  549. /*----- tidy macro */ /* chain up insert/overlay char macsteps */
  550. void macro::tidy(){int i,n; subr*u; macstep*M,*N,*P; char*s; if(!text) return;
  551. for(M=text;M;M=M->next) if(M->T1.n==_char) if(M->N.i==1)
  552.   if((u=M->f.f)==&insert?:u==&overlay?:u==&nomove){/* chain chars into string */
  553.     for(n=1,N=(P=M)->next;;P=N,N=N->next,n++)
  554.       if(!N ?: N->T1.n!=_char ?: N->f.f!=u ?: N->N.i!=1) break;
  555.     if(N) if(N->f.f==&repeat) n--; if(n<=1) continue;
  556.     s=new char[n+1]; s[n]=0; s[0]=M->T1.i;
  557.     for(i=1,N=M->next;i<n;) {s[i++]=N->T1.i; P=N->next; delete N; N=P;};
  558.     M->T1=val(s,n); M->next=N;}
  559. last=0; for(M=text;M;M=M->next) if(M) last=M;}
  560. /*-----*/
  561. macro *record=0,*Macro=0; int macdepth; macstep _lazy(kf(&_idle));
  562. /*-----*/
  563. static void G(){int i; if(!basemi.stack) {basemi.stack=new val[nglobvars];
  564.     for(i=0;i<nglobvars;i++) basemi.stack[i]=val();}}
  565. /*-----*/
  566. void macro::operator()(val N/*=val(1,0)*/,int r/*=0*/){
  567. int nn=N.n==_int?N.i:1; strings*S,*T;
  568. val *p; int i,n,b=0; macstep*A; macrinfo MI,*oldmi=mi; mi=&MI; G();
  569. jmp_buf*oldbad=bad,failed; bad=&failed; if(setjmp(*bad)) {b=1; goto BAD;}
  570. if(n=nvars) {p=mi->stack=new val[mi->nvars=n]; for(i=0;i<n;i++) p[i]=val();}
  571. if(macdepth++>16) {Moan="macro calls >16 deep"; goto BAD;}
  572. for(i=0;jump=0,Breakin()?0:i<nn;i++)
  573.   for(A=text,MI.prevstep=&_lazy;A;A=jump?:A->next){
  574.     MI.rec=1; jump=0; (*A)(); mi=&MI;
  575.     if(MI.rec) MI.prevstep=A; if(Breakin()) goto BAD;}
  576. BAD: for(i=0;i<mi->nvars;i++) mi->stack[i].del();
  577. T=MI.delenda; while(S=T){T=S->next; delete S->s; delete S;}
  578. macdepth--; mi=oldmi; bad=oldbad; if(b) MOAN(Moan);}
  579. /*-----*//*** be careful in case a loose macstep is a &repeat ***/
  580. void macstep::operator()(int p/*=1*/){int i; subr*S;
  581. prevobtype=obtype; obtype=ob_other; G();
  582. switch(f.n) {default: break;
  583. case _func: case _Func: case _call: for(i=0;i<p;i++) f(); break;
  584. case _Subr: S=f.S->f; goto SS; case _subr: S=f.f;
  585. SS: if(S==If) for(i=0;i<p;i++) N().i?T1():T2();
  586.     else for(i=0;i<p;i++) S(N(),T1(),T2()); break;
  587. case _macro: for(i=0;Breakin()?0:i<p;i++) (*f.m)(N);} B->dotcc=-1;}
  588. /*-----*/
  589. val val::operator()(){val r,*arg,*lhs; subr*sub; func*fun; macro*M; G();
  590. switch(n){default: return*this;
  591. case _macro: (*m)(); return val();
  592. case _subr:    (*f)(val(1,0),val(),val()); return val();
  593. case _Subr: (*S->f)(val(1,0),val(),val()); return val();
  594. case _func: return fn(1,this);
  595. case _Func: return Fn->f(1,this);
  596. case _ref: if(v->type==_label) return*this;
  597.     lhs=refaddr(*this); return lhs?*lhs:val();
  598. case _call:;}
  599. switch((arg=C->arg)[0].n){
  600. default: pr(CW,"tried to call a %t",arg[0].type()); MOAN(CW);
  601. case _macro: M=arg[0].m; (*M)(arg[1]); break;
  602. case _subr: sub=arg[0].f; goto F;
  603. case _Subr: sub=arg[0].S->f;
  604. F:  if(sub==If) arg[1]().i?arg[2]():arg[3]();
  605.     else (*sub)(arg[1](),arg[2](),arg[3]()); break;
  606. case _func: fun=arg[0].fn; goto H;
  607. case _Func: fun=arg[0].Fn->f;   H:  r=(*fun)(C->n,arg);
  608.     if(!r.notstring()) mi->delenda=new strings(r.s,mi->delenda); return r;
  609. case _type: pr(CW,"illegal call of `%t'",i); MOAN(CW);}
  610. return val();}
  611. /*-----*/
  612. macro*macro_menu() {int i,n; macro*M; for(n=0,M=macros;M;M=M->next) n++;
  613. if(play) MOAN("BUG: obeyed macromenu from macro"); if(!n) return 0;
  614. mousestate ms; ms=Jerry; Jerry.mc=1; Jerry.range(n,80); Jerry.move(0,0);
  615. int j=0,k,m,w=gp_Rows-2,c=0; char*s; macro*macs[n];
  616. for(i=0,M=macros;M;M=M->next,i++) macs[i]=M;
  617. E: k=w/2; k=j<w?0:((j-w/4)/k)*k; display("MACROS DEFINED",0,0,Magenta+8);
  618. for(i=k;i<n;i++) {if(i-k>=w) break; s=macs[i]->name; *CW=0;
  619.     if(macs[i]->bound.n) pr(CW," %K",&macs[i]->bound); if(s) pa(CW," `%s'",s);
  620.     if(!*CW) pr(CW,CMN); CW[gp_Cols]=0; display(CW,i-k+1,0,Magenta+8);}
  621. for(i=(w<?n)-1;i>=n-k;i--) display(" ",i,0,Magenta+8);
  622. display("(\030\031 move, RET chooses, alt_end quits)", (w<?n)+1,0,Magenta+8);
  623. A: i=k; k=w/2; k=j<w?0:((j-w/4)/k)*k; if(i!=k) goto E; m=j-k+1;
  624. scr(m,0)=sch(2,White); switch(c=getkey()) {
  625. case -mousemove: j=Jerry.y; break;
  626. case -downarrow: j=(j+1  )%n; break;
  627. case -uparrow:   j=(j-1+n)%n; break;
  628. case -alt_end: case -mbutton: case -rbutton: Jerry=ms; return 0;
  629. case CR: case -lbutton: Jerry=ms; return macs[j];}
  630. scr(m,0)=sch(' ',White); if(c!=-mousemove) Jerry.move(0,j); goto A;}
  631. /*-----*/
  632. /* enum {_unbound=0,_subr=-1,_macro=-2,_char=-3,_keyarray=-4,_buffer=-5,_int=-6,
  633. _keyseq=-7,_rsvword=-8,_unidfname=-9,_call=-10,_bad=-11,_Subr=-12,_func=-13,
  634. _Func=-14}; */
  635. /*-----*/
  636. val*refaddr(val L){int i; if(L.n!=_ref) return 0;
  637. return &(((i=L.v->offset)&0x80000000)?basemi:*mi)[i&0x7fffffff];}
  638. /*-----*/
  639. FN(_allocate){val*lhs=refaddr(arg[1]),x=arg[2]().copy();
  640. if(lhs) {lhs->del(); *lhs=x;} return x;}
  641. /*-----*/
  642. FN(_andthen){if(macdepth++>16) MOAN("macro calls >16 deep");
  643. macstep prev(_lazy); int i; macrinfo MI,*oldmi=mi; mi=&MI; mi->prevstep=&prev;
  644. for(i=1;i<n;i++) {MI.rec=1; arg[i](); mi=&MI; if(MI.rec) prev.f=arg[i];}
  645. macdepth--; mi=oldmi; return val();}
  646. /*-----*/
  647. int byteq(char*a,char*b,int n){reg byte *s=(byte*)a,*t=(byte*)b,*u=s+n;
  648.     while(s<u) if(*s++!=*t++) return 0; return 1;}
  649. int streq(val a,val b){if(a.n!=b.n?:a.n<0) return 0; return byteq(a.s,b.s,a.n);}
  650. /*-----*//* treat val() = undefined as 0 */
  651. #define EA val a=arg[1](),b=arg[2]();
  652. FN(_eq    ){EA; return a.n==_int ? a.i == b.i :  streq(a,b);}
  653. FN(_ne    ){EA; return a.n==_int ? a.i != b.i : !streq(a,b);}
  654. FN(_ge    ){return arg[1]().i >= arg[2]().i;}
  655. FN(_le    ){return arg[1]().i <= arg[2]().i;}
  656. FN(_gt    ){return arg[1]().i > arg[2]().i;}
  657. FN(_lt    ){return arg[1]().i < arg[2]().i;}
  658. FN(_plus  ){return arg[1]().i + arg[2]().i;}
  659. FN(_minus ){return arg[1]().i - arg[2]().i;}
  660. FN(_times ){return arg[1]().i * arg[2]().i;}
  661. FN(_divide){val b=arg[2](); return b.i?arg[1]().i/b.i:0;} /* x/0 = 0 here */
  662. FN(_same  ){return   arg[2]().i;}
  663. FN(_neg   ){return - arg[2]().i;}
  664. /*-----*/
  665. FN(currentbuffer){return val(copyof(B->name?:".no file."));}
  666. /*-----*/
  667. FN(keyseq_){int i,j,m; for(i=j=1;i<n;i++) {
  668.     if((m=arg[i]().charval())<0) MOAN("bad keyseq arg");
  669.     if(m>255) keyseqc[j++]=0; keyseqc[j++]=m&255;
  670.     if(j>61) MOAN("keyseq with too many args");}
  671. keyseqc[0]=j; return keyseq.copy();}
  672. /*-----*/
  673. #define FN(name) val name(int n,val*arg)
  674. FN(_yesno){B->display(); return yesno(arg[1].s);}
  675. /*-----*/
  676. FN(lastkill){return killring[nkill].asstring();};
  677. /*-----*/
  678. /* In run time, FN's return value, or val() (= void)), or val(<string>,_bad).
  679. In compile time, ditto, or val(type,_bad) = "delivers that type but I can't
  680. find its value now". val(_bad,_bad) = "ditto but I can't tell now what type
  681. it delivers". val(1,_bad) = "ditto but delivers string". */
  682.