//----------------------------------------------------------------------------- int main(int argc, char *argv[]) { mgl_suppress_warn(true); mglGraph gr; mglParse p(true); char buf[2048], iname[256]="", oname[256]=""; std::vector<std::wstring> var; std::wstring str; bool none=false; while(1) { int ch = getopt(argc, argv, "1:2:3:4:5:6:7:8:9:hno:L:C:A:s:S:q:v:g:"); if(ch>='1' && ch<='9') p.AddParam(ch-'0', optarg); else if(ch=='s') { setlocale(LC_CTYPE, ""); FILE *fp = fopen(optarg,"r"); if(fp) { wchar_t ch; while(!feof(fp) && size_t(ch=fgetwc(fp))!=WEOF) str.push_back(ch); fclose(fp); str += L"\n"; } } else if(ch=='n') none = true; else if(ch=='L') setlocale(LC_CTYPE, optarg); else if(ch=='S') mgl_set_size_scl(atof(optarg)); else if(ch=='q') gr.SetQuality(atoi(optarg)); else if(ch=='v') p.SetVariant(atoi(optarg)); else if(ch=='g') gr.Gray(atoi(optarg)); else if(ch=='A') { std::wstring str; for(size_t i=0;optarg[i];i++) str.push_back(optarg[i]); var.push_back(str); } else if(ch=='C') { double v1,v2,dv=1,v; int res=sscanf(optarg,"%lg:%lg:%lg",&v1,&v2,&dv); if(res<3) dv=1; wchar_t num[64]; for(v=v1;v<=v2;v+=dv) { mglprintf(num,64,L"%g",v); var.push_back(num); } } else if(ch=='h' || (ch==-1 && optind>=argc)) { printf("mglconv convert mgl script to bitmap png file.\nCurrent version is 2.%g\n",MGL_VER2); printf("Usage:\tmglconv [parameter(s)] scriptfile\n"); printf( "\t-1 str set str as argument $1 for script\n" "\t... ...\n" "\t-9 str set str as argument $9 for script\n" "\t-L loc set locale to loc\n" "\t-s fname set MGL script for setting up the plot\n" "\t-S val set scaling factor for images\n" "\t-q val set quality for output (val=0...9)\n" "\t-g val set gray-scale mode (val=0|1)\n" "\t-v val set variant of arguments\n" "\t-o name set output file name\n" "\t-n no default output (script should save results by itself)\n" "\t-A val add animation value val\n" "\t-C n1:n2:dn add animation value in range [n1,n2] with step dn\n" "\t-C n1:n2 add animation value in range [n1,n2] with step 1\n" "\t- get script from standard input\n" "\t-h print this message\n" ); return 0; } else if(ch=='o') strncpy(oname, optarg,256); else if(ch==-1 && optind<argc) { strncpy(iname, argv[optind][0]=='-'?"":argv[optind],256); break; } } if(*oname==0) { strncpy(oname,*iname?iname:"out",250); strcat(oname,".png"); } else none = false; mgl_ask_func = mgl_ask_gets; // prepare for animation setlocale(LC_CTYPE, ""); FILE *fp = *iname?fopen(iname,"r"):stdin; if(!fp) { printf("No file for MGL script\n"); return 0; } wchar_t cw; while(!feof(fp) && size_t(cw=fgetwc(fp))!=WEOF) str.push_back(cw); if(*iname) fclose(fp); size_t n; for(size_t i=0;;) // collect exact values { n = str.find(L"##a ",i); if (n == mnpos) break; i = n+4; var.push_back(str.substr(i,str.find('\n',i))); } n = str.find(L"##c "); if (n != mnpos) { double v1,v2,dv,v; wscanf(str.c_str()+n+4,L"%lg%lg%lg",&v1,&v2,&dv); wchar_t ss[64]; for(v=v1;v<=v2;v+=dv) { mglprintf(ss,64,L"%g",v); var.push_back(ss); } } bool gif = !strcmp(oname+strlen(oname)-4,".gif"); gr.SetSize(600,400); // specially call for "S" option if(var.size()>1) // there is animation { if(gif) gr.StartGIF(oname); for(size_t i=0;i<var.size();i++) { gr.NewFrame(); printf("frame %zu for $0 = \"%ls\"\n",i,var[i].c_str()); p.AddParam(0,var[i].c_str()); p.Execute(&gr,str.c_str()); if(gr.Message()[0]) printf("%s\n",gr.Message()); gr.EndFrame(); snprintf(buf,2048,"%s-%zu",oname,i); buf[2047]=0; if(!gif) gr.WriteFrame(buf); } if(gif) gr.CloseGIF(); } else { p.Execute(&gr,str.c_str()); if(gr.Message()[0]) printf("%s\n",gr.Message()); if(!none) gr.WriteFrame(oname); } if(!mglGlobalMess.empty()) printf("%s",mglGlobalMess.c_str()); if(!none || gif) printf("Write output to %s\n",oname); return 0; }
//----------------------------------------------------------------------------- // return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string int mglParser::Parse(mglGraph *gr, std::wstring str, long pos) { if(Stop || gr->NeedStop()) return 0; curGr = gr->Self(); std::wstring arg[1024]; str=mgl_trim_ws(str); long n,k=0,m=0,mm=0,res; // try parse ':' -- several commands in line for(n=0;n<long(str.length());n++) { if(str[n]=='\'' && (n==0 || str[n-1]!='\\')) k++; if(k%2) continue; if(str[n]=='(') m++; if(str[n]==')') m--; if(str[n]=='{') mm++; if(str[n]=='}') mm--; if(str[n]=='#') break; if((str[n]==':' || str[n]=='\n') && k%2==0 && m==0 && mm==0) { res=Parse(gr,str.substr(0,n),pos); if(!res) res=Parse(gr,str.substr(n+1),pos); return res; } } if(k%2 || m || mm) return 4; // strings is not closed // define parameters or start cycle res = ParseDef(str); if(res) return res-1; // parse arguments (parameters $1, ..., $9) PutArg(str,false); str=mgl_trim_ws(str); std::wstring opt; for(k=0;k<1024;k++) // parse string to substrings (by spaces) { n = mglFindArg(str); if(n<1) // this is option { if(str[-n]==';') opt = str.substr(-n+1); if(n<0) str = str.substr(0,-n); break; } arg[k] = str.substr(0,n); str = mgl_trim_ws(str.substr(n+1)); } // try to find last argument if(str[0]!=0 && str[0]!='#' && str[0]!=';') { arg[k] = str; k++; } if(k<1) n =0; else { // fill arguments by its values mglArg *a = new mglArg[k]; FillArg(gr, k, arg, a); // execute first special (program-flow-control) commands if(!skip() && !arg[0].compare(L"stop")) { Stop = true; delete []a; return 0; } if(!arg[0].compare(L"func")) { Stop = true; delete []a; return 0; } n = FlowExec(gr, arg[0].c_str(),k-1,a); if(n) { delete []a; return n-1; } if(skip()) { delete []a; return 0; } if(!arg[0].compare(L"load")) { int n = a[0].type==1?0:1; a[0].s.assign(a[0].w.begin(),a[0].w.end()); if(!n) mgl_parser_load(this,a[0].s.c_str()); delete []a; return n; } if(!arg[0].compare(L"define")) { if(k==3) { DeleteVar(arg[1].c_str()); // force to delete variable with the same name mglNum *v=AddNum(arg[1].c_str()); if(arg[2][0]=='!') // complex number is added { HADT dd = mglFormulaCalcC(arg[2].substr(1),this, DataList); v->d=NAN; v->c = dd->a[0]; delete dd; } else { HMDT dd = mglFormulaCalc(arg[2],this, DataList); v->c = v->d = dd->a[0]; delete dd; } } delete []a; return k==3?0:1; } if(!arg[0].compare(L"rkstep")) { int res=1; if(k>2 && a[0].type==1 && a[1].type==1) { std::wstring a1 = arg[1], a2=arg[2]; res = 0; if(a1[0]=='\'') a1 = a1.substr(1,a1.length()-2); if(a2[0]=='\'') a2 = a2.substr(1,a2.length()-2); mgl_rk_step_w(this, a1.c_str(), a2.c_str(), (k>=3 && a[2].type==2)?a[2].v:1); } delete []a; return res; } if(!arg[0].compare(L"call")) { n = 1; if(a[0].type==1) { int na=0; a[0].s.assign(a[0].w.begin(),a[0].w.end()); n=-IsFunc(a[0].w.c_str(),&na); if(n && k!=na+2) { char buf[64]; snprintf(buf,64,"Bad arguments for %ls: %ld instead of %d\n", a[0].w.c_str(),k-2,na); buf[63]=0; gr->SetWarn(-1,buf); n = 1; } else if(n) { mglFnStack fn; fn.pos = pos; for(int i=0;i<10;i++) { fn.par[i] = par[i]; par[i]=L""; } for(int i=1;i<k-1;i++) AddParam(i,arg[i+1].c_str()); fn_stack.push_back(fn); n--; } else if(AllowFileIO) // disable external scripts if AllowFileIO=false { FILE *fp = fopen(a[0].s.c_str(),"rt"); if(fp) { register int i; mglParser *prs = new mglParser(AllowSetSize); prs->DataList.swap(DataList); prs->NumList.swap(NumList); prs->Cmd=Cmd; for(i=10;i<30;i++) prs->AddParam(i,par[i].c_str()); prs->Execute(gr,fp); for(i=10;i<30;i++) AddParam(i,prs->par[i].c_str()); DataList.swap(prs->DataList); NumList.swap(prs->NumList); prs->Cmd=0; delete prs; fclose(fp); } else n=1; } } delete []a; return n; } if(!arg[0].compare(L"for")) { n = 1; char ch = arg[1][0]; int r = ch-'0'; if(ch>='a' && ch<='z') r = 10+ch-'a'; // int r = int(a[0].v); if(arg[1][1]==0 && (r>=0 && r<40)) { if(a[1].type==0) { n=0; fval[r] = *(a[1].d); fval[r].nx *= fval[r].ny*fval[r].nz; } else if(a[1].type==2 && a[2].type==2 && a[2].v>a[1].v) { mreal step = a[3].type==2?a[3].v:1; mm = int(step>0 ? (a[2].v-a[1].v)/step : 0); if(mm>0) { n=0; fval[r].Create(mm+1); for(int ii=0;ii<mm+1;ii++) fval[r].a[ii] = a[1].v + step*ii; } } if(n==0) { for(int i=39;i>0;i--) { for_stack[i]=for_stack[i-1]; if_for[i]=if_for[i-1]; } for_stack[0] = r+1; fval[r].nz = pos; if_for[0]=if_pos; wchar_t buf[32]; mglprintf(buf,32,L"%g",fval[r].a[0]); AddParam(r, buf); fval[r].ny = 1; } } delete []a; return n; } // alocate new arrays and execute the command itself n = PreExec(gr, k, arg, a); if(n>0) n--; else if(!arg[0].compare(L"setsize") && !AllowSetSize) n = 2; else n = Exec(gr, arg[0].c_str(),k-1,a, arg[1].c_str(), opt.c_str()); delete []a; } // delete temporary data arrays for(size_t i=0;i<DataList.size();i++) if(DataList[i] && DataList[i]->temp) { mglDataA *u=DataList[i]; DataList[i]=0; delete u; } return n; }
//----------------------------------------------------------------------------- int mglParser::FlowExec(mglGraph *, const std::wstring &com, long m, mglArg *a) { int n=-1; if(!ifskip() && !com.compare(L"once")) { if(a[0].type==2) { n = 0; if(a[0].v) Skip = !Once; else Skip = Once = false; } else n = 1; } else if(!Skip && !com.compare(L"if")) { int cond; if(a[0].type==2) { n = 0; cond = (a[0].v!=0)?3:0; } else if(a[0].type==0) { n = 0; a[1].s.assign(a[1].w.begin(),a[1].w.end()); cond = a[0].d->FindAny((m>1 && a[1].type==1) ? a[1].s.c_str():"u")?3:0; } else n = 1; if(n==0) { if_stack[if_pos] = cond; if_pos = if_pos<39 ? if_pos+1 : 39; } } else if(!Skip && !com.compare(L"endif")) { if_pos = if_pos>0 ? if_pos-1 : 0; n = 0; } else if(!Skip && !com.compare(L"else")) { if(if_pos>0) { n=0; if_stack[if_pos-1] = (if_stack[if_pos-1]&2)?2:3; } else n = 1; } else if(!Skip && !com.compare(L"elseif")) { int cond; if(if_pos<1 || m<1) n = 1; else if(if_stack[if_pos-1]&2) { n = 0; cond = 2; } else if(a[0].type==2) { n = 0; cond = (a[0].v!=0)?3:0; } else if(a[0].type==0) { n = 0; a[1].s.assign(a[1].w.begin(),a[1].w.end()); cond = a[0].d->FindAny((m>1 && a[1].type==1) ? a[1].s.c_str():"u")?3:0; } else n = 1; if(n==0) if_stack[if_pos-1] = cond; } else if(!ifskip() && !Skip && !com.compare(L"break")) { if(if_pos==if_for[0]) if_pos = if_pos>0 ? if_pos-1 : 0; } else if(!skip() && !com.compare(L"return")) { if(fn_stack.size()<1) return 2; const mglFnStack &fn=fn_stack.back(); for(int i=0;i<10;i++) par[i]=fn.par[i]; n = -fn.pos-1; fn_stack.pop_back(); } else if(!ifskip() && !Skip && !com.compare(L"next")) { if(if_pos==if_for[0]) if_pos = if_pos>0 ? if_pos-1 : 0; int r = for_stack[0]-1; n = for_stack[0] ? 0:1; if(for_stack[0]) { if(fval[r].ny<fval[r].nx && !for_br) { wchar_t buf[32]; mglprintf(buf,32,L"%g",fval[r].a[fval[r].ny]); AddParam(r, buf); fval[r].ny += 1; n = -fval[r].nz-1; } else { for(int i=0;i<39;i++) { for_stack[i]=for_stack[i+1]; if_for[i]=if_for[i+1]; } for_stack[39] = 0; for_br=false; } } } else if(!ifskip() && !Skip && !com.compare(L"continue")) { if(if_pos==if_for[0]) if_pos = if_pos>0 ? if_pos-1 : 0; int r = for_stack[0]-1; n = for_stack[0] ? 0:1; if(for_stack[0]) { if(fval[r].ny<fval[r].nx) { wchar_t buf[32]; mglprintf(buf,32,L"%g",fval[r].a[fval[r].ny]); AddParam(r, buf); fval[r].ny += 1; n = -fval[r].nz-1; } else for_br = true; } } return n+1; }
//----------------------------------------------------------------------------- // convert substrings to arguments void mglParser::FillArg(mglGraph *gr, int k, std::wstring *arg, mglArg *a) { register long n; for(n=1;n<k;n++) { mglDataA *v; mglNum *f; a[n-1].type = -1; if(arg[n][0]=='|') a[n-1].type = -1; else if(arg[n][0]=='\'') // this is string (simplest case) { a[n-1].type = 1; std::wstring &w=arg[n],f; wchar_t buf[32]; long i,i1,ll=w.length(); for(i=1;i<ll;i++) { if(w[i]=='\'') { if(i==ll-1) continue; i++; i1 = i; if(w[i1]==',') i1++; if(w[i1]==0) continue; for(;i<ll && w[i]!='\'';i++); if(i>i1) { if(w[i1]=='!') { HADT d = mglFormulaCalcC(w.substr(i1+1,i-i1-(w[i]=='\''?1:0)), this, DataList); mreal di = imag(d->a[0]), dr = real(d->a[0]); if(di>0) mglprintf(buf,32,L"%g+%gi",dr,di); else if(di<0) mglprintf(buf,32,L"%g-%gi",dr,-di); // TODO use \u2212 ??? else mglprintf(buf,32,L"%g",dr); a[n-1].w += buf; delete d; } else { HMDT d = mglFormulaCalc(w.substr(i1,i-i1-(w[i]=='\''?1:0)), this, DataList); mglprintf(buf,32,L"%g",d->a[0]); a[n-1].w += buf; delete d; } } } else a[n-1].w += w[i]; } } else if(arg[n][0]=='{') { // this is temp data mglData *u=new mglData; std::wstring s = arg[n].substr(1,arg[n].length()-2); a[n-1].w = u->s = L"/*"+s+L"*/"; a[n-1].type = 0; ParseDat(gr, s, *u); a[n-1].d = u; u->temp=true; DataList.push_back(u); } else if((v = FindVar(arg[n].c_str()))!=0) // try to find normal variables (for data creation) { a[n-1].type=0; a[n-1].d=v; a[n-1].w=v->s; } else if((f = FindNum(arg[n].c_str()))!=0) // try to find normal number (for data creation) { a[n-1].type=2; a[n-1].d=0; a[n-1].v=f->d; a[n-1].c=f->c; a[n-1].w = f->s; } else if(arg[n][0]=='!') // complex array is asked { // parse all numbers and formulas by unified way HADT d = mglFormulaCalcC(arg[n].substr(1), this, DataList); if(d->GetNN()==1) { if(CheckForName(arg[n].substr(1))) { a[n-1].type = 2; a[n-1].v = d->v(0); a[n-1].c = d->a[0]; } else { a[n-1].type = 0; a[n-1].d = AddVar(arg[n].c_str()); } delete d; } else { a[n-1].w = L"/*"+arg[n]+L"*/"; d->temp=true; DataList.push_back(d); a[n-1].type = 0; a[n-1].d = d; } } else { // parse all numbers and formulas by unified way HMDT d = mglFormulaCalc(arg[n], this, DataList); if(d->GetNN()==1) { if(CheckForName(arg[n])) { a[n-1].type = 2; a[n-1].c = a[n-1].v = d->v(0); } else { a[n-1].type = 0; a[n-1].d = AddVar(arg[n].c_str()); } delete d; } else { a[n-1].w = L"/*"+arg[n]+L"*/"; d->temp=true; DataList.push_back(d); a[n-1].type = 0; a[n-1].d = d; } } } }