#include #include #include #include "sysdep.h" #include "stack.h" #include "output.h" #include "command.h" #include "input.h" #include "express.h" #include "builtin.h" #include "mainloop.h" #include "udf.h" static char *argname[] = { "arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9","arg10", "arg11","arg12","arg13","arg14","arg15","arg16","arg17","arg18","arg19", "arg20" }; static int xors[20]; static header *running; void make_xors (void) { int i; for (i=0; i<20; i++) xors[i]=xor(argname[i]); } static char *type_udfline (char *start) { char outline[1024],*p=start,*q; double x; int comn; q=outline; while (*p) { if (*p==2) { p++; memmove((char *)(&x),p,sizeof(double)); p+=sizeof(double); sprintf(q,"%g",x); q+=strlen(q); } else if (*p==3) { p++; memmove((char *)(&comn),p,sizeof(int)); p+=sizeof(int); sprintf(q,"%s",command_list[comn].name); q+=strlen(q); } else *q++=*p++; if (q>outline+1022) { q=outline+1023; break; } } *q=0; output(outline); output("\n"); return p+1; } void minput (header *); void trace_udfline (char *next) { int scan,oldtrace; extern header *running; header *hd,*res; output1("%s: ",running->name); type_udfline(next); again: wait_key(&scan); switch (scan) { case fk1 : case cursor_down : break; case fk2 : case cursor_up : trace=2; break; case fk3 : case cursor_right : trace=0; break; case fk4 : case help : hd=(header *)newram; oldtrace=trace; trace=0; new_string("Expression",12,""); if (error) goto cont; minput(hd); if (error) goto cont; res=getvalue(hd); if (error) goto cont; give_out(res); cont : newram=(char *)hd; trace=oldtrace; goto again; case fk9 : case escape : output("Trace interrupted\n"); error=11010; break; case fk10 : case cursor_left : trace=-1; break; default : output( "\nKeys :\n" "cursor_down Single step\n" "cursor_up Step over subroutines\n" "cursor_right Go until return\n" "insert Evaluate expression\n" "escape Abort execution\n" "cursor_left End trace\n\n"); goto again; } } void do_trace(void) /**** do_trace toggles tracing or sets the trace bit of a udf. ****/ { header *f; char name[64]; scan_space(); if (!strncmp(next,"off",3)) { trace=0; next+=3; } else if (!strncmp(next,"alloff",6)) { next+=6; f=(header *)ramstart; while ((char *)ftype==s_udf) { f->flags&=~1; f=nextof(f); } trace=0; } else if (!strncmp(next,"on",2)) { trace=1; next+=2; } else if (*next==';' || *next==',' || *next==0) trace=!trace; else { if (*next=='"') next++; scan_name(name); if (error) return; if (*next=='"') next++; f=searchudf(name); if (!f || f->type!=s_udf) { output("Function not found!\n"); error=11021; return; } f->flags^=1; if (f->flags&1) output1("Tracing %s\n",name); else output1("No longer tracing %s\n",name); scan_space(); } if (*next==';' || *next==',') next++; } header *searchudf (char *name) /***** searchudf search a udf, named "name". return 0, if not found. *****/ { header *hd; int r; r=xor(name); hd=(header *)ramstart; while ((char *)hdtype==s_udf) { if (r==hd->xor && !strcmp(hd->name,name)) return hd; hd=nextof(hd); } return 0; } commandtyp *preview_command (unsigned long *l); char ystring[256]; void get_udf (void) /***** get_udf define a user defined function. *****/ { char name[16],argu[16],*p,*firstchar,*startp; int *ph,*phh,count=0,n; unsigned long l; header *var,*result,*hd; FILE *actfile=infile; commandtyp *com; int comn; double x; if (udfon==1) { output("Cannot define a function in a function!\n"); error=60; return; } scan_space(); scan_name(name); if (error) return; kill_udf(name); var=new_reference(0,name); if (error) return; result=new_udf(""); if (error) return; p=udfof(result); udf=1; /* udf is for the prompt! */ scan_space(); ph=(int *)p; p+=sizeof(inttyp); if (*next=='(') { while(1) { next++; scan_space(); if (*next==')') break; phh=(int *)p; *phh=0; p+=sizeof(inttyp); scan_name(argu); if (error) goto aborted; count++; strcpy(p,argu); p+=16; *((int *)p)=xor(argu); p+=sizeof(inttyp); test: scan_space(); if (*next==')') break; else if (*next=='=') { next++; *phh=1; newram=p; hd=(header *)p; scan_value(); if (error) goto aborted; strcpy(hd->name,argu); hd->xor=xor(argu); p=newram; goto test; } else if (*next==',') continue; else { output("Syntax error in parameter list!\n"); error=701; goto aborted; } } next++; } *ph=count; if (*next==0) { next_line(); } while (1) /* help section of the udf */ { if (*next=='#' && *(next+1)=='#') { while (*next) { *p++=*next++; if (!freeramfrom(p,16)) { output("Memory overflow while defining a function!\n"); error=210; goto stop; } } *p++=0; next_line(); } else break; if (actfile!=infile) { output("End of file reached in function definition!\n"); error=2200; goto stop; } } *udfstartof(result)=(p-(char *)result); startp=p; firstchar=next; while (1) { if (error) goto stop; if (!strncmp(next,"endfunction",strlen("endfunction"))) { if (p==startp || *(p-1)) *p++=0; *p++=1; next+=strlen("endfunction"); break; } if (actfile!=infile) { output("End of file reached in function definition!\n"); error=2200; goto stop; } if (*next=='#' && *(next+1)=='#') { *p++=0; next_line(); firstchar=next; } else if (*next) { if (*next=='"') { *p++=*next++; while (*next!='"' && *next) *p++=*next++; if (*next=='"') *p++=*next++; else { output("\" missing.\n"); error=2200; goto stop; } } else if (*next=='\'' && *(next+1)=='\'') { *p++=*next++; *p++=*next++; while (*next && (*next!='\'' || *(next+1)!='\'')) *p++=*next++; if (*next=='\'') { *p++=*next++; *p++=*next++; } else { output("\'\' missing.\n"); error=2200; goto stop; } } else if (isdigit(*next) || (*next=='.' && isdigit(*(next+1))) ) { if (next!=firstchar && isalpha(*(next-1))) { *p++=*next++; while (isdigit(*next)) *p++=*next++; } else { if ((p-(char *)result)%2==0) *p++=' '; *p++=2; sscanf(next,"%lg%n",&x,&n); next+=n; memmove(p,(char *)(&x),sizeof(double)); p+=sizeof(double); } } else if (isalpha(*next) && (next==firstchar || !isalpha(*(next-1))) && (com=preview_command(&l))!=0) /* Try to find a builtin command */ { if ((p-(char *)result)%2==0) *p++=' '; *p++=3; comn=com-command_list; memmove(p,(char *)(&comn),sizeof(int)); p+=sizeof(int); next+=l; } else if (*next=='.' && *(next+1)=='.') { *p++=' '; next_line(); firstchar=next; } #ifdef YACAS else if (*next=='@' && *(next+1)=='"') { next+=2; char *q=ystring; while (*next!='"' && *next && (q-ystring)<255) *q++=*next++; if (*next=='"') next++; else { output("\" missing.\n"); error=2200; goto stop; } *q++=0; q=call_yacas(ystring); strcpy(p,q); p+=strlen(p); } #endif else *p++=*next++; } else { *p++=0; next_line(); firstchar=next; } if (!freeramfrom(p,80)) { output("Memory overflow while defining a function!\n"); error=210; goto stop; } } stop: udf=0; if (error) return; result->size=(((p-(char *)result)-1)/ALIGNMENT+1)*ALIGNMENT; newram=(char *)result+result->size; assign(var,result); aborted: udf=0; } void do_type (void) { char name[16]; header *hd; char *p,*pnote; int i,count,defaults; builtintyp *b; scan_space(); scan_name(name); hd=searchudf(name); b=find_builtin(name); if (b) { if (b->nargs>=0) output1( "%s is a builtin function with %d argument(s).\n" ,name,b->nargs); else output1( "%s is a builtin function.\n" ,name); } if (hd && hd->type==s_udf) { if (b) output1("%s is also a user defined function.\n",name); output1("function %s (",name); p=helpof(hd); memmove(&count,p,sizeof(inttyp)); p+=sizeof(inttyp); pnote=p; for (i=0; itype==s_udf) { output1("function %s (",name); p=helpof(hd); memmove(&count,p,sizeof(inttyp)); p+=sizeof(inttyp); pnote=p; for (i=0; if==do_end) { if (trace>0) trace_udfline(udfline); return; } else if (com->f==do_repeat || com->f==do_loop || com->f==do_for) { scan_end(); if (error) return; } break; default : next++; } } } static void scan_endif (void) /***** scan_endif scan for "endif". *****/ { commandtyp *com; int comn; char *oldline=udfline; while (1) { switch (*next) { case 1 : output("Endif missing, searching for endif!\n"); error=110; udfline=oldline; return; case 0 : udfline=next+1; next++; break; case 2 : next+=1+sizeof(double); break; case 3 : next++; memmove((char *)(&comn),next,sizeof(int)); next+=sizeof(int); com=command_list+comn; if (com->f==do_endif) { if (trace>0) trace_udfline(udfline); return; } else if (com->f==do_if) { scan_endif(); if (error) return; } break; default : next++; } } } static int scan_else (void) /***** scan_else scan for "else". return 1, if elseif was found. *****/ { commandtyp *com; int comn; char *oldline=udfline; while (1) { switch (*next) { case 1 : output("Endif missing, searching for else!\n"); error=110; udfline=oldline; return 0; case 0 : udfline=next+1; next++; break; case 2 : next+=1+sizeof(double); break; case 3 : next++; memmove((char *)(&comn),next,sizeof(int)); next+=sizeof(int); com=command_list+comn; if (com->f==do_endif || com->f==do_else) { if (trace>0) trace_udfline(udfline); return 0; } else if (com->f==do_elseif) { return 1; } else if (com->f==do_if) { scan_endif(); if (error) return 0; } break; default : next++; } } } void do_global (void) { char name[16]; int r; header *hd; while (1) { scan_space(); scan_name(name); r=xor(name); #ifdef SPLIT_MEM hd=(header *)varstart; #else hd=(header *)udfend; #endif if (hd==(header *)startlocal) break; while ((char *)hdxor && !strcmp(hd->name,name)) break; hd=nextof(hd); } if ((char *)hd>=startlocal) { output1("Variable %s not found!\n",name); error=160; return; } newram=endlocal; hd=new_reference(hd,name); newram=endlocal=(char *)nextof(hd); scan_space(); if (*next!=',') break; else next++; } } void do_useglobal (void) { searchglobal=1; } void do_return (void) { if (!udfon) { output("Use return only in functions!\n"); error=56; return; } else udfon=2; } void do_break (void) { if (!udfon) { output("End only allowed in functions!\n"); error=57; } } void do_for (void) /***** do_for do a for command in a UDF. for i=value to value step value; .... ; end *****/ { int h,signum; char name[16],*jump; header *hd,*init,*end,*step; double vend,vstep; struct { header hd; double value; } rv; if (!udfon) { output("For only allowed in functions!\n"); error=57; return; } rv.hd.type=s_real; *rv.hd.name=0; rv.hd.size=sizeof(header)+sizeof(double); rv.value=0.0; scan_space(); scan_name(name); if (error) return; kill_local(name); newram=endlocal; hd=new_reference(&rv.hd,name); if (error) return; endlocal=newram=(char *)hd+hd->size; scan_space(); if (*next!='=') { output("Syntax error in for.\n"); error=71; goto end; } next++; init=scan(); if (error) goto end; init=getvalue(init); if (error) goto end; if (init->type!=s_real) { output("Startvalue must be real!\n"); error=72; goto end; } rv.value=*realof(init); scan_space(); if (strncmp(next,"to",2)) { output("Endvalue missing in for!\n"); error=73; goto end; } next+=2; end=scan(); if (error) goto end; end=getvalue(end); if (error) goto end; if (end->type!=s_real) { output("Endvalue must be real!\n"); error=73; goto end; } vend=*realof(end); scan_space(); if (!strncmp(next,"step",4)) { next+=4; step=scan(); if (error) goto end; step=getvalue(step); if (error) goto end; if (step->type!=s_real) { output("Stepvalue must be real!\n"); error=73; goto end; } vstep=*realof(step); } else vstep=1.0; signum=(vstep>=0)?1:-1; vend=vend+signum*epsilon; if (signum>0 && rv.value>vend) { scan_end(); goto end; } else if (signum<0 && rv.value0 && rv.value>vend) break; else if (signum<0 && rv.valuetype!=s_real) { output("Startvalue must be real!\n"); error=72; return; } oldindex=loopindex; loopindex=(long)*realof(init); scan_space(); if (strncmp(next,"to",2)) { output("Endvalue missing in loop!\n"); error=73; goto end; } next+=2; end=scan(); if (error) goto end; end=getvalue(end); if (error) goto end; if (end->type!=s_real) { output("Endvalue must be real!\n"); error=73; goto end; } vend=(long)*realof(end); if (loopindex>vend) { scan_end(); goto end; } newram=endlocal; scan_space(); if (*next==';' || *next==',') next++; jump=next; while (!error) { if (*next==1) { output("End missing in loop!\n"); error=401; goto end; } h=command(); if (udfon!=1 || h==c_return) break; if (h==c_break) { scan_end(); break; } if (h==c_end) { loopindex++; if (loopindex>vend) break; else next=jump; if (test_key()==escape) { output("User interrupted!\n"); error=1; break; } } } end : loopindex=oldindex; } void do_repeat (void) /***** do_loop do a loop command in a UDF. for value to value; .... ; endfor *****/ { int h; char *jump; if (!udfon) { output("Repeat only allowed in functions!\n"); error=57; return; } newram=endlocal; scan_space(); if (*next==';' || *next==',') next++; jump=next; while (!error) { if (*next==1) { output("End missing in repeat statement!\n"); error=401; break; } h=command(); if (udfon!=1 || h==c_return) break; if (h==c_break) { scan_end(); break; } if (h==c_end) { next=jump; if (test_key()==escape) { output1("User interrupted\n"); error=1; break; } } } } void do_end (void) { if (!udfon) { output("End only allowed in functions!\n"); error=57; } } static int ctest (header *hd) /**** ctest test, if a matrix contains nonzero elements. ****/ { double *m; long n,i; hd=getvalue(hd); if (error) return 0; if (hd->type==s_string) return (*stringof(hd)!=0); if (hd->type==s_real) return (*realof(hd)!=0.0); if (hd->type==s_complex) return (*realof(hd)!=0.0 && *imagof(hd)!=0.0); if (hd->type==s_matrix) { n=(long)(dimsof(hd)->r)*dimsof(hd)->c; m=matrixof(hd); for (i=0; itype==s_cmatrix) { n=(long)(dimsof(hd)->r)*dimsof(hd)->c; m=matrixof(hd); for (i=0; itype==s_reference && !referenceof(hd)) { if (iname[0]==0 && *(int *)p) { p+=16+2*sizeof(inttyp); moveresult((header *)newram,(header *)p); p=(char *)nextof((header *)p); hd=nextof(hd); continue; } else { hd1=getvalue(hd); if (error) return; } } else hd1=hd; if (iname,p); hd1->xor=*((int *)(p+16)); p+=16+sizeof(inttyp); if (defaults) p=(char *)nextof((header *)p); } else { strcpy(hd1->name,argname[i]); hd1->xor=xors[i]; } hd=nextof(hd); } for (i=n; iname,""); hd->xor=0; hd=nextof(hd); } if (sp==0 && argn>nargu) sp=nargu; udflineold=udfline; oldargn=actargn; oldsp=actsp; actargn=argn; actsp=sp; udfline=next=udfof(var); udfold=udfon; udfon=1; oldstartlocal=startlocal; oldendlocal=endlocal; startlocal=(char *)args; endlocal=newram; oldrunning=running; running=var; oldindex=loopindex; oldsearchglobal=searchglobal; searchglobal=0; oldepsilon=epsilon; oldchanged=epsilon=changedepsilon; if ((oldtrace=trace)>0) { if (trace==2) trace=0; if (trace>0) trace_udfline(next); } else if (var->flags&1) { trace=1; if (trace>0) trace_udfline(next); } udfcount++; if (udfcount>MAXUDF) { output("To many recursions!\n"); error=1; } while (!error && udfon==1) { command(); if (udfon==2) { result=scan_value(); if (error) { output1("Error in function %s\n",var->name); print_error(udfline); break; } moveresult1(st,result); break; } if (test_key()==escape) { output("User interrupted!\n"); error=58; break; } } udfcount--; endlocal=oldendlocal; startlocal=oldstartlocal; running=oldrunning; loopindex=oldindex; if (oldchanged==changedepsilon) epsilon=oldepsilon; else epsilon=changedepsilon; if (trace>=0) trace=oldtrace; if (error) output1("Error in function %s\n",var->name); if (udfon==0) { output1("Return missing in %s!\n",var->name); error=55; } udfon=udfold; next=oldnext; udfline=udflineold; actargn=oldargn; actsp=oldsp; searchglobal=oldsearchglobal; } void mdo (header *hd) { header *st=hd,*hd1,*result; int count=0; unsigned long size; if (!hd) wrong_arg_in("do"); hd=getvalue(hd); result=hd1=next_param(st); if (hd->type!=s_string) wrong_arg_in("do"); if (error) return; hd=searchudf(stringof(hd)); if (!hd || hd->type!=s_udf) wrong_arg_in("do"); while (hd1) { strcpy(hd1->name,argname[count]); hd1->xor=xors[count]; hd1=next_param(hd1); count++; } if (result) { size=(char *)result-(char *)st; if (size>0 && newram!=(char *)result) memmove((char *)st,(char *)result,newram-(char *)result); newram-=size; } interpret_udf(hd,st,count,0); }