#include #include #include #include #include #include #include #include "header.h" #include "sysdep.h" #include "funcs.h" #include "graphics.h" char *ramstart,*ramend,*udfend,*startlocal,*endlocal,*newram, *varstart,*udframend; char *next,*udfline; FILE *metafile=0; double epsilon; char titel[]="This is EULER, Version 3.04 compiled %s.\n\n" "Type help(Return) for help.\n" "Enter command: (%ld Bytes free.)\n\n"; int error,quit,surpressed,udf=0,errorout,outputing=1,stringon=0, trace=0; char line[1024]; long loopindex=0; int fieldw=15,linew=5; double maxexpo=1.0e5,minexpo=1.0e-7; char expoformat[16]=" %14.5e"; char fixedformat[16]=" %14.7f"; int nosubmref=0; FILE *infile=0,*outfile=0; header commandheader; int commandtype; /* dumping to file */ void output (char *s) { text_mode(); if (outputing || error) gprint(s); if (outfile) { fprintf(outfile,"%s",s); if (ferror(outfile)) { output("Error on dump file (disk full?).\n"); error=200; fclose(outfile); outfile=0; } } } void output1 (char *s, ...) { char text [1024]; va_list v; text_mode(); va_start(v,s); vsprintf(text,s,v); if (outputing || error) gprint(text); if (outfile) { vfprintf(outfile,s,v); if (ferror(outfile)) { output("Error on dump file (disk full?).\n"); error=200; fclose(outfile); outfile=0; } } } /* help */ extern commandtyp command_list[]; int dohelp (char start[256], char extend[16][16]) /* dohelp Extend a start string in up to 16 ways to a command or function. This function is called from the line editor, whenever the HELP key is pressed. */ { int count=0,ln,l; header *hd=(header *)ramstart; builtintyp *b=builtin_list; commandtyp *c=command_list; ln=(int)strlen(start); while (b->name) { if (!strncmp(start,b->name,ln)) { l=(int)strlen(b->name)-ln; if (l>0 && l<16) { strcpy(extend[count],b->name+ln); count++; } if (count>=16) return count; } b++; } while (hd<(header *)udfend) { if (!strncmp(start,hd->name,ln)) { l=(int)strlen(hd->name)-ln; if (l>0 && l<16) { strcpy(extend[count],hd->name+ln); count++; } if (count>=16) return count; } hd=nextof(hd); } while (c->name) { if (!strncmp(start,c->name,ln)) { l=(int)strlen(c->name)-ln; if (l>0 && l<16) { strcpy(extend[count],c->name+ln); count++; } if (count>=16) return count; } c++; } return count; } /* functions that manipulate the stack */ void kill_local (char *name); void clear (void) /***** clear clears the stack and remove all variables and functions. *****/ { char name[32]; scan_space(); if (*next==';' || *next==',' || *next==0) { endlocal=startlocal; } else while(1) { scan_name(name); if (error) return; kill_local(name); scan_space(); if (*next==',') { next++; continue; } else break; } } int xor (char *n) /***** xor compute a hashcode for the name n. *****/ { int r=0; while (*n) r^=*n++; return r; } void *make_header (stacktyp type, size_t size, char *name) /***** make_header pushes a new element on the stack. return the position after the header. ******/ { header *hd; char *erg; #ifdef SPECIAL_ALIGNMENT size=(((size-1)/8)+1)*8; #endif hd=(header *)(newram); if (newram+size>ramend) { output("Stack overflow!\n"); error=2; return 0; } hd=(header *)newram; hd->size=size; hd->type=type; hd->flags=0; if (*name) { strcpy(hd->name,name); hd->xor=xor(name); } else { *(hd->name)=0; hd->xor=0; } erg=newram+sizeof(header); newram+=size; return erg; } header *new_matrix (int rows, int columns, char *name) /***** new_matrix pops a new matrix on the stack. *****/ { size_t size; dims *d; header *hd=(header *)newram; size=matrixsize(rows,columns); d=(dims *)make_header(s_matrix,size,name); if (d) { d->c=columns; d->r=rows; } return hd; } header *new_cmatrix (int rows, int columns, char *name) /***** new_matrix pops a new matrix on the stack. *****/ { size_t size; dims *d; header *hd=(header *)newram; size=matrixsize(rows,2*columns); d=(dims *)make_header(s_cmatrix,size,name); if (d) { d->c=columns; d->r=rows; } return hd; } header *new_command (int no) /***** new_command pops a command on stack. *****/ { size_t size; int *d; header *hd=(header *)newram; size=sizeof(header)+sizeof(int); d=(int *)make_header(s_command,size,""); if (d) *d=no; return hd; } header *new_real (double x, char *name) /***** new real pops a double on stack. *****/ { size_t size; double *d; header *hd=(header *)newram; size=sizeof(header)+sizeof(double); d=(double *)make_header(s_real,size,name); if (d) *d=x; return hd; } header *new_string (char *s, size_t length, char *name) /***** new real pops a string on stack. *****/ { size_t size; char *d; header *hd=(header *)newram; size=sizeof(header)+((int)(length+1)/2+1)*2; d=(char *)make_header(s_string,size,name); if (d) strncpy(d,s,length); d[length]=0; return hd; } header *new_udf (char *name) /***** new real pops a udf on stack. *****/ { size_t size; size_t *d; header *hd=(header *)newram; size=sizeof(header)+sizeof(size_t)+(LONG)2; d=(size_t *)make_header(s_udf,size,name); if (d) { *d=sizeof(header)+sizeof(size_t); *((char *)(d+1))=0; } return hd; } header *new_complex (double x, double y, char *name) /***** new real pushes a complex on stack. *****/ { size_t size; double *d; header *hd=(header *)newram; size=sizeof(header)+2*sizeof(double); d=(double *)make_header(s_complex,size,name); if (d) *d=x; *(d+1)=y; return hd; } header *new_reference (header *ref, char *name) { size_t size; header **d; header *hd=(header *)newram; size=sizeof(header)+sizeof(header *); d=(header **)make_header(s_reference,size,name); if (d) *d=ref; return hd; } header *new_subm (header *var, LONG l, char *name) /* makes a new submatrix, which is a single element */ { size_t size; header **d,*hd=(header *)newram; dims *dim; int *n,r,c; size=sizeof(header)+sizeof(header *)+ sizeof(dims)+2*sizeof(int); d=(header **)make_header(s_submatrix,size,name); if (d) *d=var; else return hd; dim=(dims *)(d+1); dim->r=1; dim->c=1; n=(int *)(dim+1); c=dimsof(var)->c; if (c==0 || dimsof(var)->r==0) { output("Matrix is empty!\n"); error=1031; return hd; } else r=(int)(l/c); *n++=r; *n=(int)(l-(LONG)r*c-1); return hd; } header *new_csubm (header *var, LONG l, char *name) /* makes a new submatrix, which is a single element */ { size_t size; header **d,*hd=(header *)newram; dims *dim; int *n,r,c; size=sizeof(header)+sizeof(header *)+ sizeof(dims)+2*sizeof(int); d=(header **)make_header(s_csubmatrix,size,name); if (d) *d=var; else return hd; dim=(dims *)(d+1); dim->r=1; dim->c=1; n=(int *)(dim+1); c=dimsof(var)->c; if (c==0 || dimsof(var)->r==0) { output("Matrix is empty!\n"); error=1031; return hd; } else r=(int)(l/c); *n++=r; *n=(int)(l-r*c-1); return hd; } header *hnew_submatrix (header *var, header *rows, header *cols, char *name, int type) { size_t size; header **d; double *mr,*mc=0,x,*mvar; dims *dim; int c,r,*n,i,c0,r0,cvar,rvar,allc=0,allr=0; header *hd=(header *)newram; getmatrix(var,&rvar,&cvar,&mvar); if (rows->type==s_matrix) { if (dimsof(rows)->r==1) r=dimsof(rows)->c; else if (dimsof(rows)->c==1) r=dimsof(rows)->r; else { output("Illegal index!\n"); error=41; return 0; } mr=matrixof(rows); } else if (rows->type==s_real) { r=1; mr=realof(rows); } else if (rows->type==s_command && *commandof(rows)==c_allv) { allr=1; r=rvar; } else { output("Illegal index!\n"); error=41; return 0; } if (cols->type==s_matrix) { if (dimsof(cols)->r==1) c=dimsof(cols)->c; else if (dimsof(cols)->c==1) c=dimsof(cols)->r; else { output("Illegal index!\n"); error=41; return 0; } mc=matrixof(cols); } else if (cols->type==s_real) { c=1; mc=realof(cols); } else if (cols->type==s_command && *commandof(cols)==c_allv) { allc=1; c=cvar; } else { output("Illegal index!\n"); error=41; return 0; } size=sizeof(header)+sizeof(header *)+ sizeof(dims)+((LONG)r+c)*sizeof(int); d=(header **)make_header(type,size,name); if (d) *d=var; else return hd; dim = (dims *)(d+1); n=(int *)(dim+1); r0=0; if (allr) { for (i=0; i=rvar)) ) { *n++=(int)x; r0++; } } c0=0; if (allc) { for (i=0; i=cvar))) { *n++=(int)x; c0++; } } dim->r=r0; dim->c=c0; size=(char *)n-(char *)hd; #ifdef SPECIAL_ALIGNMENT size=((size-1)/8+1)*8; #endif newram=(char *)hd; hd->size=size; return hd; } header *built_csmatrix (header *var, header *rows, header *cols) /***** built_csmatrix built a complex submatrix from the matrix hd on the stack. *****/ { double *mr,*mc=0,*mvar,*mh,*m; int n,c,r,c0,r0,i,j,cvar,rvar,allc=0,allr=0,*pc,*pr,*nc,*nr; header *hd; char *ram; getmatrix(var,&rvar,&cvar,&mvar); if (rows->type==s_matrix) { if (dimsof(rows)->r==1) r=dimsof(rows)->c; else if (dimsof(rows)->c==1) r=dimsof(rows)->r; else { output("Illegal index!\n"); error=41; return 0; } mr=matrixof(rows); } else if (rows->type==s_real) { r=1; mr=realof(rows); } else if (rows->type==s_command && *commandof(rows)==c_allv) { allr=1; r=rvar; } else { output("Illegal index!\n"); error=41; return 0; } if (cols->type==s_matrix) { if (dimsof(cols)->r==1) c=dimsof(cols)->c; else if (dimsof(cols)->c==1) c=dimsof(cols)->r; else { output("Illegal index!\n"); error=41; return 0; } mc=matrixof(cols); } else if (cols->type==s_real) { c=1; mc=realof(cols); } else if (cols->type==s_command && *commandof(cols)==c_allv) { allc=1; c=cvar; } else { output("Illegal index!\n"); error=41; return 0; } ram=newram; if (ram+((LONG)(c)+(LONG)(r))*sizeof(int)>ramend) { output("Out of memory!\n"); error=710; return 0; } nr=pr=(int *)ram; nc=pc=pr+r; newram=(char *)(pc+c); c0=0; r0=0; if (allc) { for (i=0; i=0 && n=0 && ntype==s_matrix) { if (dimsof(rows)->r==1) r=dimsof(rows)->c; else if (dimsof(rows)->c==1) r=dimsof(rows)->r; else { output("Illegal index!\n"); error=41; return 0; } mr=matrixof(rows); } else if (rows->type==s_real) { r=1; mr=realof(rows); } else if (rows->type==s_command && *commandof(rows)==c_allv) { allr=1; r=rvar; } else { output("Illegal index!\n"); error=41; return 0; } if (cols->type==s_matrix) { if (dimsof(cols)->r==1) c=dimsof(cols)->c; else if (dimsof(cols)->c==1) c=dimsof(cols)->r; else { output("Illegal index!\n"); error=41; return 0; } mc=matrixof(cols); } else if (cols->type==s_real) { c=1; mc=realof(cols); } else if (cols->type==s_command && *commandof(cols)==c_allv) { allc=1; c=cvar; } else { output("Illegal index!\n"); error=41; return 0; } ram=newram; if (ram+((LONG)(c)+(LONG)(r))*sizeof(int)>ramend) { output("Out of memory!\n"); error=710; return 0; } nr=pr=(int *)ram; nc=pc=pr+r; newram=(char *)(pc+c); c0=0; r0=0; if (allc) { for (i=0; i=0 && n=0 && np) { output1("error in:\n%s\n",line); if ((int)(p-line)name); q+=strlen(q); } else *q++=*p++; if (q>outline+1022) { q=outline+1023; break; } } *q++=0; output1("Error in :\n%s\n",outline); output("\n"); } errorout=1; } void read_line (char *line) { int count=0,input; char *p=line; while(1) { input=getc(infile); if (input==EOF) { fclose(infile); *p++=1; infile=0; break; } if (input=='\n') break; if (count>=1023) { output("Line to long!\n"); error=50; *line=0; return; } if ((char)input>=' ' || (signed char)input<0 || (char)input==TAB) { *p++=(char)input; count++; } } *p=0; } char *type_udfline (char *start) { char outline[1024],*p=start,*q; double x; commandtyp *com; 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 *)(&com),p,sizeof(commandtyp *)); p+=sizeof(commandtyp *); sprintf(q,"%s",com->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 *hd); 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 : trace=-1; break; default : output( "\nKeys:\n" "F1 (cursor_down) Single step\n" "F2 (cursor_up) Step over subroutines\n" "F3 (cursor_right) Go until return\n" "F4 (help) Evaluate expression\n" "F9 (escape) Abort execution\n" "F10 End trace\n\n"); goto again; } } void next_line (void) /**** next_line read a line from keyboard or file. ****/ { if (udfon) { while (*next) next++; next++; if (*next==1) udfon=0; else udfline=next; if (trace>0) trace_udfline(next); return; } else { if (trace==-1) trace=1; if (stringon) { error=2300; output("Input ended in string!\n"); return; } if (!infile) edit(line); else read_line(line); next=line; } } void scan_space (void) { start: while (*next==' ' || *next==TAB) next++; if (!udfon && *next=='.' && *(next+1)=='.') { next_line(); if (error) return; goto start; } } void do_end (void); void do_loop (void); void do_repeat (void); void do_for (void); void scan_end (void) /***** scan_end scan for "end". *****/ { commandtyp *com; char *oldline=udfline; while (1) { switch (*next) { case 1 : output("End missing!\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 *)(&com),next,sizeof(commandtyp *)); next+=sizeof(commandtyp *); if (com->f==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++; } } } void do_endif (void); void do_else (void); void do_if (void); void scan_endif (void) /***** scan_endif scan for "endif". *****/ { commandtyp *com; 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 *)(&com),next,sizeof(commandtyp *)); next+=sizeof(commandtyp *); 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++; } } } void scan_else (void) /***** scan_else scan for "else". *****/ { commandtyp *com; char *oldline=udfline; while (1) { switch (*next) { case 1 : output("Endif missing, searching for else!\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 *)(&com),next,sizeof(commandtyp *)); next+=sizeof(commandtyp *); if (com->f==do_endif || com->f==do_else) { if (trace>0) trace_udfline(udfline); return; } else if (com->f==do_if) { scan_endif(); if (error) return; } break; default : next++; } } } void scan_name (char *name) { int count=0; if (!isalpha(*next)) { error=11; *name=0; return; } while (isalpha(*next) || isdigit(*next)) { *name++=*next++; count++; if (count>=15) { output("Name to long!\n"); error=11; break; } } *name=0; } void getmatrix (header *hd, int *r, int *c, double **m) /***** getmatrix get rows and columns from a matrix. *****/ { dims *d; if (hd->type==s_real || hd->type==s_complex) { *r=*c=1; *m=realof(hd); } else { d=dimsof(hd); *m=matrixof(hd); *r=d->r; *c=d->c; } } header *searchvar (char *name) /***** searchvar search a local variable, named "name". return 0, if not found. *****/ { int r; header *hd=(header *)startlocal; r=xor(name); while ((char *)hdxor && !strcmp(hd->name,name)) return hd; hd=nextof(hd); } return 0; } 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; } void kill_local (char *name) /***** kill_local kill a loal variable name, if there is one. *****/ { size_t size,rest; header *hd=(header *)startlocal; while ((char *)hdname,name)) /* found! */ { size=hd->size; rest=newram-(char *)hd-size; if (size) memmove((char *)hd,(char *)hd+size,rest); endlocal-=size; newram-=size; return; } hd=(header *)((char *)hd+hd->size); } } void kill_udf (char *name) /***** kill_udf kill a local variable name, if there is one. *****/ { size_t size,rest; header *hd=(header *)ramstart; while ((char *)hdname,name)) /* found! */ { size=hd->size; #ifndef SPLIT_MEM rest=newram-(char *)hd-size; if (size && rest) memmove((char *)hd,(char *)hd+size,rest); endlocal-=size; startlocal-=size; newram-=size; #else rest=udfend-(char *)hd-size; if (size && rest) memmove((char *)hd,(char *)hd+size,rest); #endif udfend-=size; return; } hd=(header *)((char *)hd+hd->size); } } int sametype (header *hd1, header *hd2) /***** sametype returns true, if hd1 and hd2 have the same type and dimensions. *****/ { dims *d1,*d2; if (hd1->type!=hd2->type || hd1->size!=hd2->size) return 0; if (hd1->type==s_matrix) { d1=dimsof(hd1); d2=dimsof(hd2); if (d1->r!=d2->r) return 0; } return 1; } header *assign (header *var, header *value) /***** assign assign the value to the variable. *****/ { char name[16],*nextvar; size_t size,dif; double *m,*mv,*m1,*m2; int i,j,c,r,cv,rv,*rind,*cind; dims *d; header *help,*orig; if (error) return 0; size=value->size; if (var->type==s_reference && !referenceof(var)) /* seems to be a new variable */ { strcpy(name,var->name); if (value->type==s_udf) { strcpy(value->name,name); value->xor=xor(name); #ifndef SPLIT_MEM if (newram+size>ramend) { output("Memory overflow.\n"); error=500; return value; } memmove(ramstart+size,ramstart,newram-ramstart); newram+=size; endlocal+=size; startlocal+=size; value=(header *)((char *)value+size); #else if (udfend+size>udframend) { output("Memory overflow.\n"); error=500; return value; } memmove(ramstart+size,ramstart,udfend-ramstart); #endif udfend+=size; memmove(ramstart,(char *)value,size); return (header *)ramstart; } memmove(endlocal+size,endlocal,newram-endlocal); value=(header *)((char *)value+size); newram+=size; memmove(endlocal,(char *)value,size); strcpy(((header *)endlocal)->name,name); ((header *)endlocal)->xor=xor(name); value=(header *)endlocal; endlocal+=size; return value; } else { while (var && var->type==s_reference) var=referenceof(var); if (!var) { error=43; output("Internal variable error!\n"); return 0; } if (var->type!=s_udf && value->type==s_udf) { output("Cannot assign a UDF to a variable!\n"); error=320; return var; } if (var->type==s_submatrix) { d=submdimsof(var); if (value->type==s_complex || value->type==s_cmatrix) { orig=submrefof(var); help=new_reference(orig,""); if (error) return 0; mcomplex(help); if (error) return 0; var->type=s_csubmatrix; submrefof(var)=help; assign(var,value); if (error) return 0; submrefof(var)=orig; assign(orig,help); return orig; } else if (value->type!=s_real && value->type!=s_matrix) { output("Illegal assignment!\n"); error=45; return 0; } getmatrix(value,&rv,&cv,&mv); getmatrix(submrefof(var),&r,&c,&m); if (d->r!=rv || d->c!=cv) { output("Illegal assignment!\n"); error=45; return 0; } rind=rowsof(var); cind=colsof(var); for (i=0; ir; i++) { m1=mat(m,c,rind[i],0); m2=mat(mv,cv,i,0); for (j=0; jc; j++) { m1[cind[j]]=*m2++; } } return submrefof(var); } else if (var->type==s_csubmatrix) { d=submdimsof(var); if (value->type==s_real || value->type==s_matrix) { help=new_reference(value,""); if (error) return 0; mcomplex(help); if (error) return 0; assign(var,help); return submrefof(var); } if (value->type!=s_complex && value->type!=s_cmatrix) { output("Illegal assignment!\n"); error=45; return 0; } getmatrix(value,&rv,&cv,&mv); getmatrix(submrefof(var),&r,&c,&m); if (d->r!=rv || d->c!=cv) { output("Illegal assignment!\n"); error=45; return 0; } rind=rowsof(var); cind=colsof(var); for (i=0; ir; i++) { m1=cmat(m,c,rind[i],0); m2=cmat(mv,cv,i,0); for (j=0; jc; j++) { copy_complex(m1+(LONG)2*cind[j],m2); m2+=2; } } return submrefof(var); } else { if ((char *)varendlocal) /* its not a local variable! */ { if (!sametype(var,value)) { output1("Cannot change type of non-local variable %s!\n", var->name); error=12; return 0; } memcpy((char *)(var+1),(char *)(value+1), value->size-sizeof(header)); return var; } dif=value->size-var->size; if (newram+dif>ramend) { output("Memory overflow\n"); error=501; return value; } nextvar=(char *)var+var->size; if (dif!=0) memmove(nextvar+dif,nextvar,newram-nextvar); newram+=dif; endlocal+=dif; value=(header *)((char *)value+dif); strcpy(value->name,var->name); value->xor=var->xor; memmove((char *)var,(char *)value,value->size); } } return var; } header *next_param (header *hd) /***** next_param get the next value on stack, if there is one *****/ { hd=(header *)((char *)hd+hd->size); if ((char *)hd>=newram) return 0; else return hd; } /********************* interpreter **************************/ void double_out (double x) /***** double_out print a double number. *****/ { if ((fabs(x)>maxexpo || fabs(x)=c) cend=c-1; if (c>linew) output2("Column %d to %d:\n",c0+1,cend+1); for (i=0; imaxexpo || fabs(x)maxexpo || fabs(y)=c) cend=c-1; if (c>linew/2) output2("Column %d to %d:\n",c0+1,cend+1); for (i=0; itype) { case s_real : double_out(*realof(hd)); output("\n"); break; case s_complex : complex_out(*realof(hd),*(realof(hd)+1)); output("\n"); break; case s_matrix : out_matrix(hd); break; case s_cmatrix : out_cmatrix(hd); break; case s_string : output(stringof(hd)); output("\n"); break; default : output("?\n"); } } /***************** some builtin commands *****************/ void load_file (void) /***** load_file inerpret a file. *****/ { header *filename; char oldline[1024],fn[256],*oldnext; FILE *oldinfile; filename=scan_value(); if (error) return; if (filename->type!=s_string) { output("Illegal filename!\n"); error=52; return; } if (udfon) { output("Cannot load a file in a function!\n"); error=221; return; } oldinfile=infile; infile=fopen(stringof(filename),"r"); if (!infile) { strcpy(fn,stringof(filename)); strcat(fn,EXTENSION); infile=fopen(fn,"r"); if (!infile) { output1("Could not open %s!\n",stringof(filename)); error=53; infile=oldinfile; return; } } strcpy(oldline,line); oldnext=next; *line=0; next=line; while (!error && infile && !quit) command(); if (infile) fclose(infile); infile=oldinfile; strcpy(line,oldline); next=oldnext; } commandtyp *preview_command (size_t *l); 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; size_t l; header *var,*result,*hd; FILE *actfile=infile; commandtyp *com; 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(int); if (*next=='(') { while(1) { next++; scan_space(); if (*next==')') break; phh=(int *)p; *phh=0; p+=sizeof(int); scan_name(argu); if (error) goto aborted; count++; strcpy(p,argu); p+=16; *((int *)p)=xor(argu); p+=sizeof(int); 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("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 (p>=ramend) { output("Memory overflow!\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 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; memmove(p,(char *)(&com),sizeof(commandtyp *)); p+=sizeof(commandtyp *); next+=l; } else if (*next=='.' && *(next+1)=='.') { *p++=' '; next_line(); firstchar=next; } else *p++=*next++; } else { *p++=0; next_line(); firstchar=next; } if (p>=ramend-80) { output("Memory overflow!\n"); error=210; goto stop; } } stop: udf=0; if (error) return; result->size=((p-(char *)result)/2+1)*2; #ifdef SPECIAL_ALIGNMENT result->size=((result->size-1)/8+1)*8; #endif newram=(char *)result+result->size; assign(var,result); aborted: udf=0; } void do_return (void) { if (!udfon) { output("No user defined function active!\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); if (signum && rv.value>vend) { scan_end(); goto end; } else if (!signum && rv.valuevend) break; else if (!signum && 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 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=(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!\n"); error=401; goto end; } h=command(); if (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) { 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("Loop 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!\n"); error=401; break; } h=command(); if (h==c_return) break; if (h==c_break) { scan_end(); break; } if (h==c_end) { next=jump; if (test_key()==escape) { error=1; break; } } } } void do_end (void) { if (!udfon) { output("End only allowed in functions!\n"); error=57; } } void do_else (void) { if (!udfon) { output("Else only allowed in functions!\n"); error=57; return; } scan_endif(); } void do_endif (void) { if (!udfon) { output("Endif only allowed in functions!\n"); error=57; } } 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_string) { output("Cannot execute a number or matrix!\n"); error=130; return; } s=stringof(name); while (*s && !isspace(*s)) s++; if (*s) *s++=0; if (execute(stringof(name),s)) { output("Execution failed or program returned a failure!\n"); error=131; } } void do_forget (void) { char name[16]; header *hd; int r; if (udfon) { output("Cannot forget functions in a function!\n"); error=720; return; } while (1) { scan_space(); scan_name(name); r=xor(name); hd=(header *)ramstart; while ((char *)hdxor && !strcmp(hd->name,name)) break; hd=nextof(hd); } if ((char *)hd>=udfend) { output1("Function %s not found!\n",name); error=160; return; } kill_udf(name); scan_space(); if (*next!=',') break; else 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 print_commands (void); void do_list (void) { header *hd; int lcount=0; output(" *** Builtin functions:\n"); print_builtin(); output(" *** Commands:\n"); print_commands(); output(" *** Your functions:\n"); hd=(header *)ramstart; while ((char *)hdtype!=s_udf) break; if (lcount+(int)strlen(hd->name)+2>=linelength) { lcount=0; output("\n"); } output1("%s ",hd->name); lcount+=(int)strlen(hd->name)+1; hd=nextof(hd); } output("\n"); } void do_type (void) { char name[16]; header *hd; char *p,*pnote; int i,count,defaults; scan_space(); scan_name(name); hd=searchudf(name); if (hd && hd->type==s_udf) { output1("function %s (",name); p=helpof(hd); count=*((int *)p); p+=sizeof(int); pnote=p; for (i=0; itype==s_udf) { output1("function %s (",name); end=udfof(hd); p=helpof(hd); count=*((int *)p); p+=sizeof(int); pnote=p; for (i=0; ihelp shortformat\n" " You can get a list of all functions with\n >list\n\n" " If you need online help for builtin functions enter:\n" " >load \"help\"" "\n\n To run a demo use:\n >load \"demo\"\n >demo()\n" "\n >quit\n quits this program.\n\n"); } } void do_dump (void) { header *file; if (outfile) { if (fclose(outfile)) { output("Error while closing dumpfile.\n"); } outfile=0; } scan_space(); if (*next==';' || *next==',' || *next==0) { if (*next) next++; return; } file=scan_value(); if (error || file->type!=s_string) { output("Dump needs a filename!\n"); error=201; return; } outfile=fopen(stringof(file),"a"); if (!outfile) { output1("Could not open %s.\n",stringof(file)); } } void do_meta (void) { header *file; if (metafile) { if (fclose(metafile)) { output("Error while closing metafile.\n"); } metafile=0; } scan_space(); if (*next==';' || *next==',' || *next==0) { if (*next) next++; return; } file=scan_value(); if (error || file->type!=s_string) { output("Meta needs a filename!\n"); error=201; return; } metafile=fopen(stringof(file),"ab"); if (!metafile) { output1("Could not open %s.\n",stringof(file)); } } void do_remove (void) { header *file; file=scan_value(); if (error || file->type!=s_string) { output("Remove needs a string!\n"); error=202; return; } remove(stringof(file)); } void do_do (void) { int udfold; char name[16]; char *oldnext=next,*udflineold; header *var; scan_space(); scan_name(name); if (error) return; var=searchudf(name); if (!var || var->type!=s_udf) { output("Need a udf!\n"); error=220; return; } udflineold=udfline; udfline=next=udfof(var); udfold=udfon; udfon=1; while (!error && udfon==1) { command(); if (udfon==2) break; if (test_key()==escape) { output("User interrupted!\n"); error=58; break; } } 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; udfline=udflineold; if (udfon) next=oldnext; else { next=line; *next=0; } } void do_mdump (void) { header *hd; #ifndef SPLIT_MEM output1("ramstart : 0\nstartlocal : %ld\n",startlocal-ramstart); output1("endlocal : %ld\n",endlocal-ramstart); output1("newram : %ld\n",newram-ramstart); output1("ramend : %ld\n",ramend-ramstart); #else output1("ramstart : 0\nstartlocal : %ld\n",startlocal-varstart); output1("endlocal : %ld\n",endlocal-varstart); output1("newram : %ld\n",newram-varstart); output1("ramend : %ld\n",ramend-varstart); #endif hd=(header *)ramstart; #ifdef SPLIT_MEM while ((char *)hdname); output1("size %6ld ",(long)hd->size); output1("type %d\n",hd->type); hd=nextof(hd); } hd=(header *)varstart; #endif while ((char *)hdname); #else output1("%6ld : %16s, ",(char *)hd-varstart,hd->name); #endif output1("size %6ld ",(long)hd->size); output1("type %d\n",hd->type); hd=nextof(hd); } } void hex_out1 (int n) { if (n<10) output1("%c",n+'0'); else output1("%c",n-10+'A'); } void hex_out (unsigned int n) { hex_out1(n/16); hex_out1(n%16); output(" "); } void string_out (unsigned char *p) { int i; unsigned char a; for (i=0; i<16; i++) { a=*p++; output1("%c",(a<' ')?'_':a); } } void do_hexdump (void) { char name[16]; unsigned char *p,*end; int i=0,j; size_t count=0; header *hd; scan_space(); scan_name(name); if (error) return; hd=searchvar(name); if (!hd) hd=searchudf(name); if (error || hd==0) return; p=(unsigned char *)hd; end=p+hd->size; output1("\n%5lx ",count); while (p=16) { i=0; string_out(p-16); output1("\n%5lx ",count); if (test_key()==escape) break; } } for (j=i; j<16; j++) output(" "); string_out(p-i); output("\n"); } void do_output (void) /**** do_output toggles output. ****/ { scan_space(); if (!strncmp(next,"off",3)) { outputing=0; next+=3; } else if (!strncmp(next,"on",2)) { outputing=1; output("\n"); next+=2; } else outputing=!outputing; } void do_comment (void) { FILE *fp=infile; if (!fp || udfon) { output("comment illegal at this place"); error=1001; return; } while (strncmp(next,"endcomment",10)!=0) { next_line(); if (infile!=fp) { output("endcomment missing!\n"); error=1002; return; } } next_line(); } 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++; } int command_count; commandtyp command_list[] = {{"quit",c_quit,do_quit}, {"hold",c_hold,ghold}, {"shg",c_shg,show_graphics}, {"load",c_load,load_file}, {"function",c_udf,get_udf}, {"return",c_return,do_return}, {"for",c_for,do_for}, {"endif",c_endif,do_endif}, {"end",c_end,do_end}, {"break",c_break,do_break}, {"loop",c_loop,do_loop}, {"else",c_else,do_else}, {"if",c_if,do_if}, {"repeat",c_repeat,do_repeat}, {"clear",c_clear,do_clear}, {"clg",c_clg,do_clg}, {"cls",c_cls,do_cls}, {"exec",c_exec,do_exec}, {"forget",c_forget,do_forget}, {"global",c_global,do_global}, {"list",c_global,do_list}, {"type",c_global,do_type}, {"dump",c_global,do_dump}, {"remove",c_global,do_remove}, {"help",c_global,do_help}, {"do",c_global,do_do}, {"memorydump",c_global,do_mdump}, {"hexdump",c_global,do_hexdump}, {"output",c_global,do_output}, {"meta",c_global,do_meta}, {"comment",c_global,do_comment}, {"trace",c_global,do_trace}, {0,0,0} }; void print_commands (void) { int linel=0,i; for (i=0; ilinelength) { output("\n"); linel=0; } output1("%s ",command_list[i].name); linel+=(int)strlen(command_list[i].name)+1; } output("\n"); } int command_compare (const commandtyp *p1, const commandtyp *p2) { return strcmp(p1->name,p2->name); } void sort_command (void) { command_count=0; while (command_list[command_count].name) command_count++; qsort(command_list,command_count,sizeof(commandtyp), (int (*)(const void *, const void *))command_compare); } commandtyp *preview_command (size_t *l) { commandtyp h; char name[16],*a,*n; *l=0; a=next; n=name; while (*l<15 && isalpha(*a)) { *n++=*a++; *l+=1; } *n++=0; if (isalpha(*a)) return 0; h.name=name; return bsearch(&h,command_list,command_count,sizeof(commandtyp), (int (*)(const void *, const void *))command_compare); } int builtin (void) /***** builtin interpret a builtin command, number no. *****/ { size_t l; commandtyp *p; if (*next==3) { next++; #ifdef SPECIAL_ALIGNMENT memmove((char *)(&p),next,sizeof(commandtyp *)); #else p=*((commandtyp **)next); #endif l=sizeof(commandtyp *); } else if (udfon) return 0; else p=preview_command(&l); if (p) { next+=l; p->f(); if (*next==';' || *next==',') next++; commandtype=p->nr; return 1; } return 0; } header *scan_expression (void) /***** scan_expression scans a variable, a value or a builtin command. *****/ { if (builtin()) return &commandheader; return scan(); } #define addsize(hd,size) ((header *)((char *)(hd)+size)) void do_assignment (header *var) /***** do_assignment assign a value to a variable. *****/ { header *variable[8],*rightside[8],*rs,*v,*mark; int rscount,varcount,i,j; size_t offset,oldoffset,dif; char *oldendlocal; scan_space(); if (*next=='=') { next++; nosubmref=1; rs=scan_value(); nosubmref=0; if (error) return; varcount=0; /* count the variables, that get assigned something */ while (vartype!=s_reference && var->type!=s_submatrix && var->type!=s_csubmatrix) { output("Illegal assignment!\n"); error=210; } variable[varcount]=var; var=nextof(var); varcount++; if (varcount>=8) { output("To many commas!\n"); error=100; return; } } /* count and note the values, that are assigned to the variables */ rscount=0; while (rs<(header *)newram) { rightside[rscount]=rs; rs=nextof(rs); rscount++; if (rscount>=8) { output("To many commas!\n"); error=101; return; } } /* cannot assign 2 values to 3 variables , e.g. */ if (rscount>1 && rscount1)?i:0],offset)); offset=endlocal-oldendlocal; if (oldoffset!=offset) /* size of var. changed */ { v=addsize(variable[i],offset); if (v->type==s_reference) mark=referenceof(v); else mark=submrefof(v); /* now shift all references of the var.s */ if (mark) /* not a new variable */ for (j=i+1; jtype==s_reference && referenceof(v)>mark) referenceof(v)=addsize(referenceof(v),dif); else if (submrefof(v)>mark) submrefof(v)=addsize(submrefof(v),dif); } } } } else /* just an expression which is a variable */ { var=getvalue(var); } if (error) return; if (*next!=';') give_out(var); if (*next==',' || *next==' ' || *next==';') next++; } int command (void) /***** command scan a command and interpret it. return, if the user wants to quit. *****/ { header *expr; int ret=c_none; quit=0; error=0; errorout=0; while(1) { scan_space(); if (*next) break; else next_line(); } if (*next==1) return ret; expr=scan_expression(); if (!expr) { newram=endlocal; return ret; } if (error) { newram=endlocal; print_error(next); next=line; line[0]=0; return ret; } if (expr==&commandheader) { newram=endlocal; return commandtype; } switch (expr->type) { case s_real : case s_complex : case s_matrix : case s_cmatrix : case s_string : if (*next!=';') give_out(expr); if (*next==',' || *next==' ' || *next==';') next++; break; case s_reference : case s_submatrix : case s_csubmatrix : do_assignment(expr); break; default : break; } if (error) print_error(next); newram=endlocal; if (error) { next=line; line[0]=0; } return ret; } /******************* main functions ************************/ void clear_fktext (void) { int i; for (i=0; i<10; i++) fktext[i][0]=0; } void main_loop (int argc, char *argv[]) { int i; #ifndef SPLIT_MEM output2(titel,__DATE__,(unsigned long)(ramend-ramstart)); #else output2(titel,__DATE__,(unsigned long)(ramend-varstart)); #endif #ifndef SPLIT_MEM newram=startlocal=endlocal=ramstart; #else newram=startlocal=endlocal=varstart; #endif udfend=ramstart; epsilon=10000*DBL_EPSILON; sort_builtin(); sort_command(); make_xors(); clear_fktext(); next=line; /* clear input line */ strcpy(line,"load \"euler.cfg\";"); for (i=1; i