1 /***************************************************************************
2  * parse.cpp is part of Math Graphic Library
3  * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru>       *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License  as       *
7  *   published by the Free Software Foundation; either version 3 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Lesser General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include <ctype.h>
21 #include "mgl2/parser.h"
22 #include "mgl2/canvas_cf.h"
23 #include "mgl2/base.h"
24 //-----------------------------------------------------------------------------
mgl_cmd_cmp(const void * a,const void * b)25 int MGL_LOCAL_PURE mgl_cmd_cmp(const void *a, const void *b)
26 {
27 	const mglCommand *aa = (const mglCommand *)a;
28 	const mglCommand *bb = (const mglCommand *)b;
29 	return strcmp(aa->name, bb->name);
30 }
31 //-----------------------------------------------------------------------------
32 mglCommand *mglParser::BaseCmd=NULL;	///< Base table of MGL commands. It MUST be sorted by 'name'!!!
FillBaseCmd()33 void mglParser::FillBaseCmd()
34 {
35 	if(BaseCmd)	return;
36 	size_t na=0, nd=0, ng=0, np=0, ns=0, nr=0, nsum=0;
37 	while(mgls_prg_cmd[na].name[0])	na++;
38 	while(mgls_dat_cmd[nd].name[0])	nd++;
39 	while(mgls_grf_cmd[ng].name[0])	ng++;
40 	while(mgls_prm_cmd[np].name[0])	np++;
41 	while(mgls_set_cmd[ns].name[0])	ns++;
42 	while(mgls_rnd_cmd[nr].name[0])	nr++;
43 	BaseCmd = new mglCommand[na+nd+ng+np+ns+nr+1];
44 	memcpy(BaseCmd, 	mgls_prg_cmd, na*sizeof(mglCommand));	nsum+=na;
45 	memcpy(BaseCmd+nsum,mgls_dat_cmd, nd*sizeof(mglCommand));	nsum+=nd;
46 	memcpy(BaseCmd+nsum,mgls_grf_cmd, ng*sizeof(mglCommand));	nsum+=ng;
47 	memcpy(BaseCmd+nsum,mgls_prm_cmd, np*sizeof(mglCommand));	nsum+=np;
48 	memcpy(BaseCmd+nsum,mgls_rnd_cmd, nr*sizeof(mglCommand));	nsum+=nr;
49 	memcpy(BaseCmd+nsum,mgls_set_cmd,(ns+1)*sizeof(mglCommand));nsum+=ns;
50 	qsort(BaseCmd, nsum, sizeof(mglCommand), mgl_cmd_cmp);
51 #if DEBUG
52 	long stat[17];	memset(stat,0,17*sizeof(long));
53 	const char *name[17] = { _("0 - special plot"), _("1 - other plot"), _("2 - setup"), _("3 - data handle"), _("4 - data create"), _("5 - subplot"), _("6 - program flow"), _("7 - 1d plot"), _("8 - 2d plot"), _("9 - 3d plot"), _("10 - dd plot"), _("11 - vector plot"), _("12 - axis"), _("13 - primitives"), _("14 - axis setup"), _("15 - text/legend"), _("16 - data transform") };
54 	for(size_t i=0;BaseCmd[i].name[0];i++)	stat[BaseCmd[i].type]+=1;
55 	for(size_t i=0;i<17;i++)	printf("%s: %ld\n",name[i],stat[i]);
56 	printf("\n");	fflush(stdout);
57 #endif
58 }
59 //-----------------------------------------------------------------------------
60 HMDT MGL_NO_EXPORT mglFormulaCalc(const std::wstring &string, mglParser *arg, const std::vector<mglDataA*> &head);
61 HADT MGL_NO_EXPORT mglFormulaCalcC(const std::wstring &string, mglParser *arg, const std::vector<mglDataA*> &head);
62 //-----------------------------------------------------------------------------
63 MGL_EXPORT void (*mgl_ask_func)(const wchar_t *, wchar_t *)=0;
mgl_ask_gets(const wchar_t * quest,wchar_t * res)64 void MGL_EXPORT mgl_ask_gets(const wchar_t *quest, wchar_t *res)
65 {	printf("%ls\n",quest);	if(!fgetws(res,1024,stdin))	*res=0;	}
66 //-----------------------------------------------------------------------------
mgl_progress_txt(int value,int maximal,HMGL)67 void MGL_EXPORT mgl_progress_txt(int value, int maximal, HMGL)
68 {
69 	static int prev = 0;
70 	if(value<=0 || value>=maximal)	{	printf("\n");	value=0;	}
71 	else	for(int i=prev;i<value;i++)	printf("#");
72 	prev = value;	fflush(stdout);
73 }
74 MGL_EXPORT void (*mgl_progress_func)(int value, int maximal, HMGL)=mgl_progress_txt;
mgl_progress(int value,int maximal,HMGL gr)75 void MGL_EXPORT mgl_progress(int value, int maximal, HMGL gr)
76 {	mgl_progress_func(value, maximal, gr);	}
77 //-----------------------------------------------------------------------------
mglFunc(long p,const wchar_t * f)78 mglFunc::mglFunc(long p, const wchar_t *f):func(f)
79 {
80 	pos = p;
81 	size_t i;
82 	for(i=0;(isalnum(f[i]) || f[i]=='_');i++);
83 	narg = wcstol(f+i+1,0,0);	func.crop(0,i);
84 	if(narg<0 || narg>9)	narg=0;
85 }
86 //-----------------------------------------------------------------------------
IsFunc(const wchar_t * name,int * na)87 long mglParser::IsFunc(const wchar_t *name, int *na)
88 {
89 	for(size_t i=0;i<func.size();i++)
90 	{
91 		const mglFunc &f = func[i];
92 		if(f.func==name)
93 		{	if(na)	*na=f.narg;	return f.pos+1;	}
94 	}
95 	return 0;
96 }
97 //-----------------------------------------------------------------------------
ScanFunc(const wchar_t * line)98 void mglParser::ScanFunc(const wchar_t *line)
99 {
100 	static long num=0;
101 	if(!line)
102 	{	func.clear();	num=0;	return;	}
103 	num++;
104 	while(*line<=' ' && *line!=0)	line++;
105 	if(wcsncmp(line,L"func",4) || line[4]>' ')	return;
106 	long i;
107 	for(i=4;line[i]<=' ' || line[i]=='\'';i++);
108 	func.push_back(mglFunc(num-1, line+i));
109 }
110 //-----------------------------------------------------------------------------
mgl_str_copy(const char * s)111 MGL_NO_EXPORT wchar_t *mgl_str_copy(const char *s)
112 {
113 	size_t i,l=strlen(s);
114 	wchar_t *str = new wchar_t[l+1];
115 	for(i=0;i<l;i++)	str[i] = s[i];
116 	str[i] = 0;	return str;
117 }
118 //-----------------------------------------------------------------------------
CheckForName(const std::wstring & s)119 bool mglParser::CheckForName(const std::wstring &s)
120 {
121 	return !isalpha(s[0]) || s.find_first_of(L"!@#$%%^&*/()-+|,.<>:")!=std::wstring::npos || s==L"rnd" || FindNum(s.c_str());
122 //	return !isalpha(s[0])||s.find_first_of(L".:()")!=std::wstring::npos;
123 }
124 //-----------------------------------------------------------------------------
FindCommand(const char * com) const125 const mglCommand *mglParser::FindCommand(const char *com) const
126 {
127 	if(!AllowFileIO && ( !strncmp(com,"read",4) || !strncmp(com,"save",4) || !strcmp(com,"fgets") || !strcmp(com,"import") || !strcmp(com,"export") ))
128 		return 0;
129 	mglCommand tst, *rts, *cmd = Cmd;
130 	long i;
131 	for(i=0;cmd[i].name[0];i++);	// determine the number of symbols
132 	tst.name = com;
133 	rts = (mglCommand *) bsearch(&tst, cmd, i, sizeof(mglCommand), mgl_cmd_cmp);
134 	return rts;
135 }
136 //-----------------------------------------------------------------------------
FindCommand(const wchar_t * com) const137 const mglCommand *mglParser::FindCommand(const wchar_t *com) const
138 {
139 	char cmd[33]="";
140 	size_t s = wcstombs(0,com,0);	// NOTE: command name should be less than 32
141 	if(s<32)	{	wcstombs(cmd,com,s+1);	cmd[s]=0;	}
142 	return FindCommand(cmd);
143 }
144 //-----------------------------------------------------------------------------
145 // return values : 0 -- OK, 1 -- wrong arguments, 2 -- wrong command, 3 -- unclosed string
Exec(mglGraph * gr,const wchar_t * com,long n,mglArg * a,const std::wstring &,const wchar_t * opt)146 int mglParser::Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const std::wstring &/*var*/, const wchar_t *opt)
147 {
148 	const char *id="dsn";
149 	std::string k;
150 	for(long i=0;i<n;i++)	k += id[a[i].type];
151 	const mglCommand *rts=FindCommand(com);
152 	if(!rts || !rts->exec)	return 2;
153 /*	if(rts->type == 4)
154 	{
155 		if(n<1 || CheckForName(var))	return 2;
156 		a[0].type = 0;	a[0].d = AddVar(var.c_str());
157 		a[0].w = var;	k[0] = 'd';
158 	}*/
159 	std::string vopt;
160 	if(opt && *opt)	// TODO: parse arguments of options
161 	{
162 		size_t len = mgl_wcslen(opt);
163 		std::vector<std::wstring> ss;
164 		std::wstring s, o;
165 		bool st = true, name = true;
166 		for(size_t i=0;i<len+1;i++)
167 		{
168 			if(st && opt[i]<=' ')	continue;	// skip spaces at beginning
169 			st = false;
170 			if(i<len && opt[i]!=';')
171 			{
172 				if(name && opt[i]<=' ')	{	name = false;	o = s;	}
173 				s.push_back(opt[i]);
174 			}
175 			else
176 			{
177 				size_t j = o.size(),k;
178 				wchar_t buf[64];
179 				if(o==L"xrange" || o==L"yrange" || o==L"zrange" || o==L"crange")	// 2 arguments
180 				{
181 					bool alph=false;
182 					for(k=j;k<s.length();k++)
183 					{
184 						if(s[k]>' ')	alph=true;
185 						if(alph && s[k]<=' ')	break;
186 					}
187 					if(k<s.length())
188 					{
189 						HMDT d1 = mglFormulaCalc(s.substr(j+1,k-j),this, DataList);
190 						HMDT d2 = mglFormulaCalc(s.substr(k+1),this, DataList);
191 						mglprintf(buf,64,L" %g %g",d1->a[0],d2->a[0]);
192 						s = o+buf;	delete d1;	delete d2;
193 					}
194 				}
195 				else if(o!=L"legend")	// 1 argument
196 				{
197 					HMDT dd = mglFormulaCalc(s.substr(j+1),this, DataList);
198 					mglprintf(buf,64,L" %g",dd->a[0]);
199 					s = o+buf;	delete dd;
200 				}
201 				st = name = true;	ss.push_back(s);
202 				o.clear();	s.clear();
203 			}
204 		}
205 		for(size_t i=0;i<ss.size();i++)
206 		{
207 			for(size_t j=0;j<ss[i].length();j++)	vopt += ss[i][j];
208 			vopt += ';';
209 		}
210 	}
211 	int res=rts->exec(gr, n, a, k.c_str(), vopt.c_str());
212 	return res;
213 }
214 //-----------------------------------------------------------------------------
mglParser(bool setsize)215 mglParser::mglParser(bool setsize)
216 {
217 	InUse = 1;	curGr = 0;	Variant = 0;
218 	Skip=Stop=false;	StarObhID = 0;
219 	for(long i=0;i<40;i++)	par[i]=L"";
220 
221 	FillBaseCmd();	Cmd = BaseCmd;
222 	AllowSetSize=setsize;	AllowFileIO=true;	AllowDllCall=true;
223 	Once = true;
224 	mglNum *v;
225 	v = new mglNum(0);	v->s = L"off";	NumList.push_back(v);
226 	v = new mglNum(1);	v->s = L"on";	NumList.push_back(v);
227 	v = new mglNum(-1);	v->s = L"all";	NumList.push_back(v);
228 	v = new mglNum(NAN);	v->s = L"nan";	NumList.push_back(v);
229 	v = new mglNum(M_PI);	v->s = L"pi";	NumList.push_back(v);
230 	v = new mglNum(INFINITY);	v->s = L"inf";	NumList.push_back(v);
231 #if MGL_HAVE_LTDL
232 	lt_dlinit();
233 #endif
234 }
235 //-----------------------------------------------------------------------------
~mglParser()236 mglParser::~mglParser()
237 {
238 	DeleteAll();
239 	for(size_t i=0;i<NumList.size();i++)	// force delete built-in variables
240 		if(NumList[i])	delete NumList[i];
241 	NumList.clear();
242 #if MGL_HAVE_LTDL
243 	lt_dlexit();
244 #endif
245 }
246 //-----------------------------------------------------------------------------
DeleteAll()247 void mglParser::DeleteAll()
248 {
249 	for(size_t i=0;i<DataList.size();i++)
250 		if(DataList[i])	delete DataList[i];
251 	DataList.clear();
252 	for(size_t i=0;i<NumList.size();i++)
253 		if(NumList[i])	delete NumList[i];
254 	NumList.clear();
255 	mglNum *v;
256 	v = new mglNum(0);	v->s = L"off";	NumList.push_back(v);
257 	v = new mglNum(1);	v->s = L"on";	NumList.push_back(v);
258 	v = new mglNum(-1);	v->s = L"all";	NumList.push_back(v);
259 	v = new mglNum(NAN);	v->s = L"nan";	NumList.push_back(v);
260 	v = new mglNum(M_PI);	v->s = L"pi";	NumList.push_back(v);
261 	v = new mglNum(INFINITY);	v->s = L"inf";	NumList.push_back(v);
262 	if(Cmd && Cmd!=BaseCmd)	{	delete []Cmd;	Cmd = BaseCmd;	}
263 #if MGL_HAVE_LTDL
264 	for(size_t i=0;i<DllOpened.size();i++)
265 		lt_dlclose(DllOpened[i]);
266 	DllOpened.clear();
267 #endif
268 }
269 //-----------------------------------------------------------------------------
AddParam(int n,const char * str)270 void mglParser::AddParam(int n, const char *str)
271 {
272 	MGL_TO_WCS(str,AddParam(n,wcs));
273 }
274 //-----------------------------------------------------------------------------
Parse(mglGraph * gr,const char * str,long pos)275 int mglParser::Parse(mglGraph *gr, const char *str, long pos)
276 {
277 	int r=0;
278 	MGL_TO_WCS(str,r = Parse(gr,wcs,pos));
279 	return r;
280 }
281 //-----------------------------------------------------------------------------
AddVar(const char * str)282 mglDataA *mglParser::AddVar(const char *str)
283 {
284 	mglDataA *v=0;
285 	MGL_TO_WCS(str,v = AddVar(wcs));
286 	return v;
287 }
288 //-----------------------------------------------------------------------------
FindVar(const char * str)289 mglDataA *mglParser::FindVar(const char *str)
290 {
291 	mglDataA *v=0;
292 	MGL_TO_WCS(str,v = FindVar(wcs));
293 	return v;
294 }
295 //-----------------------------------------------------------------------------
AddNum(const char * str)296 mglNum *mglParser::AddNum(const char *str)
297 {
298 	mglNum *v=0;
299 	MGL_TO_WCS(str,v = AddNum(wcs));
300 	return v;
301 }
302 //-----------------------------------------------------------------------------
FindNum(const char * str)303 mglNum *mglParser::FindNum(const char *str)
304 {
305 	mglNum *v=0;
306 	MGL_TO_WCS(str,v = FindNum(wcs));
307 	return v;
308 }
309 //-----------------------------------------------------------------------------
AddParam(int n,const wchar_t * str)310 void mglParser::AddParam(int n, const wchar_t *str)
311 {
312 //	if(str && n>=0 && n<40 && !wcschr(str,'$'))	par[n] = str;
313 	if(str && n>=0 && n<40)	par[n] = str;
314 }
315 //-----------------------------------------------------------------------------
FindVar(const wchar_t * name)316 mglDataA *mglParser::FindVar(const wchar_t *name)
317 {
318 	if(name[0]=='!')	name = name+1;	// ignore complex prefix
319  	for(size_t i=0;i<DataList.size();i++)
320  		if(DataList[i] && !wcscmp(DataList[i]->Name(),name))
321 			return DataList[i];
322 	return 0;
323 }
324 //-----------------------------------------------------------------------------
AddVar(const wchar_t * name)325 mglDataA *mglParser::AddVar(const wchar_t *name)
326 {	// TODO add list of forbidden names (like function names)
327 	mglDataA *d=FindVar(name);
328 	if(name[0]=='!' && dynamic_cast<mglDataC*>(d)==0)
329 	{	d = new mglDataC;	d->Name(name+1);	DataList.push_back(d);	}
330 	else if(!d)
331 	{	d = new mglData;	d->Name(name);	DataList.push_back(d);	}
332 	return d;
333 }
334 //-----------------------------------------------------------------------------
FindNum(const wchar_t * name)335 mglNum *mglParser::FindNum(const wchar_t *name)
336 {
337 	for(size_t i=0;i<NumList.size();i++)
338 		if(NumList[i] && NumList[i]->s==name)	return NumList[i];
339 	return 0;
340 }
341 //-----------------------------------------------------------------------------
AddNum(const wchar_t * name)342 mglNum *mglParser::AddNum(const wchar_t *name)
343 {
344 	mglNum *v = FindNum(name);
345 	if(!v)	{	v=new mglNum;	v->s = name;	NumList.push_back(v);	}
346 	return v;
347 }
348 //-----------------------------------------------------------------------------
mglFindArg(const std::wstring & str)349 int MGL_LOCAL_PURE mglFindArg(const std::wstring &str)
350 {
351 	long l=0,k=0;
352 	const size_t s=str.length();
353 	for(size_t i=0;i<s;i++)
354 	{
355 		if(str[i]=='\'') l++;
356 		if(str[i]=='{') k++;
357 		if(str[i]=='}') k--;
358 		if(l%2==0 && k==0)
359 		{
360 			if(str[i]=='#' || str[i]==';')	return -long(i);
361 			if(str[i]<=' ')	return long(i);
362 		}
363 	}
364 	return 0;
365 }
366 //-----------------------------------------------------------------------------
367 // convert substrings to arguments
FillArg(mglGraph * gr,int k,std::wstring * arg,mglArg * a)368 void mglParser::FillArg(mglGraph *gr, int k, std::wstring *arg, mglArg *a)
369 {
370 	for(long n=1;n<k;n++)
371 	{
372 		mglDataA *v;	mglNum *f;
373 		a[n-1].type = -1;
374 		std::wstring str = arg[n];
375 		size_t i1=0, i2=str.length(), j=0;
376 		bool s=true;
377 		for(size_t i=0;i<i2;i++)
378 		{
379 			if(str[i]=='\'')	s = !s;
380 			if(s && str[i]=='?')
381 			{
382 				if(j<Variant)	i1=i+1;
383 				else	i2=i;
384 				j++;
385 			}
386 		}
387 		str = str.substr(i1,i2-i1);
388 
389 		if(str.empty())	a[n-1].type = -2;
390 		else if(str[0]=='|')	a[n-1].type = -1;
391 		else if(str[0]=='\'')	// this is string (simplest case)
392 		{
393 			a[n-1].type = 1;
394 			long na=1, ns=0, np=0, ll=str.length(), ii=1, op=0;
395 			std::vector<std::wstring> s;
396 			std::vector<int> id;	// 0 - string, 1 - cval, 2 - rval, 3 - plus, 4 - index
397 			for(long i=1;i<ll;i++)
398 			{
399 				if(str[i]=='\'')
400 				{
401 					if(na%2==1)
402 					{	id.push_back(0);	s.push_back(str.substr(ii,i-ii));	}
403 					else if(op && i>ii)
404 					{	id.push_back(op);	s.push_back(str.substr(ii,i-ii));	}
405 					na++;	ii=i+1;	op=0;
406 				}
407 				else if(na%2==0 && ns==0 && np==0)
408 				{
409 					if(str[i]=='+' && str[i-1]=='\'')
410 					{	op=3;	ii=i+1;	}
411 					else if(str[i]==',' && str[i+1]=='!')
412 					{
413 						if(op && i>ii)
414 						{	id.push_back(op);	s.push_back(str.substr(ii,i-ii));	}
415 						op=1;	ii=i+2;
416 					}
417 					else if(str[i]==',')
418 					{
419 						if(op && i>ii)
420 						{	id.push_back(op);	s.push_back(str.substr(ii,i-ii));	}
421 						op=2;	ii=i+1;
422 					}
423 					else if(str[i]=='[' && str[i-1]=='\'')
424 					{	ii=i+1;	ns++;	}
425 					else if(str[i]=='(')	np++;
426 				}
427 				else if(na%2==0 && np==0 && str[i]==']' && ns==1)
428 				{
429 					id.push_back(4);	s.push_back(str.substr(ii,i-ii));
430 					op=0;	ii=i+1;	ns--;
431 				}
432 				else if(na%2==0 && np>0 && ns==0)
433 				{
434 					if(str[i]==')')	np--;
435 					if(str[i]=='(')	np++;
436 				}
437 			}
438 			if(op && ll>ii)
439 			{	id.push_back(op);	s.push_back(str.substr(ii,ll-ii));	}
440 			wchar_t buf[32];
441 			for(size_t i=0;i<id.size();i++)
442 			{
443 				if(id[i]==0)	a[n-1].s += s[i].c_str();
444 				else if(id[i]==1)
445 				{
446 					HADT d = mglFormulaCalcC(s[i], this, DataList);
447 					mreal di = imag(d->a[0]), dr = real(d->a[0]);
448 					if(di>0)	mglprintf(buf,32,L"%g+%gi",dr,di);
449 					else if(di<0)	mglprintf(buf,32,L"%g-%gi",dr,-di);	// TODO use \u2212 ???
450 					else	mglprintf(buf,32,L"%g",dr);
451 					a[n-1].s += buf;	delete d;
452 				}
453 				else if(id[i]==2)
454 				{
455 					HMDT d = mglFormulaCalc(s[i], this, DataList);
456 					mglprintf(buf,32,L"%g",d->a[0]);	a[n-1].s += buf;	delete d;
457 				}
458 				else if(id[i]==3)
459 				{
460 					HMDT d = mglFormulaCalc(s[i], this, DataList);
461 					a[n-1].s[a[n-1].s.length()-1] += d->a[0];	delete d;
462 				}
463 				else if(id[i]==4)
464 				{
465 					HMDT d = mglFormulaCalc(s[i], this, DataList);
466 					long v = long(d->a[0]+0.5);	delete d;
467 					if(v>=0 && v<long(a[n-1].s.length()))	a[n-1].s = a[n-1].s[v];
468 					else	a[n-1].s = L"";
469 				}
470 			}
471 		}
472 		else if(str[0]=='{')
473 		{	// this is temp data
474 			mglData *u=new mglData;
475 			std::wstring s = str.substr(1,str.length()-2);
476 			a[n-1].s = L"/*"+s+L"*/";
477 			a[n-1].type = 0;	u->Name(a[n-1].s.w);
478 			ParseDat(gr, s, *u);	a[n-1].d = u;
479 			u->temp=true;	DataList.push_back(u);
480 		}
481 		else if((v = FindVar(str.c_str()))!=0)	// try to find normal variables (for data creation)
482 		{	a[n-1].type=0;	a[n-1].d=v;	a[n-1].s=v->Name();	}
483 		else if((f = FindNum(str.c_str()))!=0)	// try to find normal number (for data creation)
484 		{	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].s = f->s;	}
485 		else if(str[0]=='!')	// complex array is asked
486 		{	// parse all numbers and formulas by unified way
487 			HADT d = mglFormulaCalcC(str.substr(1), this, DataList);
488 			if(d->GetNN()==1)
489 			{
490 				if(CheckForName(str.substr(1)))
491 				{	a[n-1].type = 2;	a[n-1].v = d->v(0);	a[n-1].c = d->a[0];	}
492 				else
493 				{	a[n-1].type = 0;	a[n-1].d = AddVar(str.c_str());	}
494 				delete d;
495 			}
496 			else
497 			{
498 				a[n-1].s = L"/*"+str+L"*/";
499 				d->temp=true;	DataList.push_back(d);
500 				a[n-1].type = 0;	a[n-1].d = d;
501 			}
502 		}
503 		else
504 		{	// parse all numbers and formulas by unified way
505 			HMDT d = mglFormulaCalc(str, this, DataList);
506 			if(d->GetNN()==1)
507 			{
508 				if(CheckForName(str))
509 				{	a[n-1].type = 2;	a[n-1].c = a[n-1].v = d->v(0);	}
510 				else
511 				{	a[n-1].type = 0;	a[n-1].d = AddVar(str.c_str());	}
512 				delete d;
513 			}
514 			else
515 			{
516 				a[n-1].s = L"/*"+str+L"*/";
517 				d->temp=true;	DataList.push_back(d);
518 				a[n-1].type = 0;	a[n-1].d = d;
519 			}
520 		}
521 	}
522 }
523 //-----------------------------------------------------------------------------
524 // return values: 0 - not found, 1 - OK, 2 - wrong arguments, 3 - wrong command, 4 - string too long
PreExec(mglGraph *,long k,std::wstring * arg,mglArg * a)525 int mglParser::PreExec(mglGraph *, long k, std::wstring *arg, mglArg *a)
526 {
527 	long n=0;
528 	if(!arg[0].compare(L"list"))	// parse command "list"
529 	{
530 		if(k<3 || CheckForName(arg[1]))	return 2;
531 		long nx=0, ny=1,j=0,i,t=0;
532 		for(i=2;i<k;i++)
533 		{
534 			char ch = arg[i][0];
535 			if(a[i-1].type==1)	return 2;
536 			if(a[i-1].type==0)
537 			{
538 				if(t==1)	return 2;
539 				t=2;	nx++;
540 			}
541 			if(a[i-1].type==2)
542 			{
543 				if(t==2)	return 2;
544 				j++;	t=1;
545 			}
546 			if(ch=='|' && t==1)		{	nx = j>nx ? j:nx;	j=0;	ny++;	}
547 		}
548 		mglDataA *vv = AddVar(arg[1].c_str());
549 		mglData *v = dynamic_cast<mglData*>(vv);
550 		mglDataC *vc = dynamic_cast<mglDataC*>(vv);
551 		if(v)
552 		{
553 			if(t==1)	nx = j>nx ? j:nx;
554 			if(t==1)	// list of numeric values
555 			{
556 				v->Create(nx,ny);
557 				j=t=0;
558 				for(i=2;i<k;i++)
559 				{
560 					if(arg[i][0]=='|')	{	t++;	j=0;	}
561 					else
562 					{	v->a[j+nx*t] = a[i-1].v;	j++;	}
563 				}
564 			}
565 			if(t==2)	// list of data
566 			{
567 				v->Set(a[1].d);
568 				for(long i=2;i<k;i++)	v->Join(*(a[i].d));
569 			}
570 			n=1;
571 		}
572 		if(vc)
573 		{
574 			if(t==1)	nx = j>nx ? j:nx;
575 			if(t==1)	// list of numeric values
576 			{
577 				vc->Create(nx,ny);
578 				j=t=0;
579 				for(i=2;i<k;i++)
580 				{
581 					if(arg[i][0]=='|')	{	t++;	j=0;	}
582 					else
583 					{	vc->a[j+nx*t] = a[i-1].c;	j++;	}
584 				}
585 			}
586 			if(t==2)	// list of data
587 			{
588 				vc->Set(a[1].d);
589 				for(long i=2;i<k;i++)	vc->Join(*(a[i].d));
590 			}
591 			n=1;
592 		}
593 	}
594 	return n;
595 }
596 //-----------------------------------------------------------------------------
PutArg(std::wstring & str,bool def)597 void mglParser::PutArg(std::wstring &str, bool def)
598 {
599 	size_t pos = str.find('$',def?10:0);
600 	while(pos<str.length())
601 	{
602 		wchar_t ch = str[pos+1];
603 		if(ch>='0' && ch<='9')	str.replace(pos,2,par[ch-'0'].w);
604 		else if(ch>='a' && ch<='z')	str.replace(pos,2,par[ch-'a'+10].w);
605 		else if(ch=='$')	str.replace(pos,2,L"\uffff");
606 		else str.replace(pos,1,L"\uffff");
607 		pos = str.find('$',def?10:0);
608 	}
609 	while((pos = str.find(L'\uffff'))<str.length())	str[pos]='$';
610 }
611 //-----------------------------------------------------------------------------
mgl_trim_ws(const std::wstring & str)612 std::wstring mgl_trim_ws(const std::wstring &str)
613 {
614 	size_t n=str.length(), k, i;
615 	for(k=0;k<n;k++)	if(str[k]>' ')	break;
616 	for(i=n;i>k;i--)	if(str[i-1]>' ')	break;
617 	return str.substr(k,i-k);
618 }
619 //-----------------------------------------------------------------------------
ParseDef(std::wstring & str)620 int mglParser::ParseDef(std::wstring &str)
621 {
622 	if(!skip() && !str.compare(0,3,L"def") && (str[6]==' ' || str[6]=='\t'))
623 	{
624 		int res = 1;	mreal d;
625 		PutArg(str,true);
626 		size_t end;	bool ss=false;
627 		for(end=7;str[end] && (str[end]!='#' || ss);end++)
628 		{	if(str[end]=='\'')	ss=!ss;	}
629 		const std::wstring s = mgl_trim_ws(str.substr(7,end-7));
630 		if(!str.compare(3,3,L"ine"))
631 		{
632 			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
633 			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
634 			{
635 				AddParam(nn, mgl_trim_ws(s.substr(2)).c_str());	return 1;
636 			}
637 		}
638 		if(!str.compare(3,3,L"num"))
639 		{
640 			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
641 			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
642 			{
643 				res = 0;
644 				HMDT dd = mglFormulaCalc(mgl_trim_ws(s.substr(2)), this, DataList);
645 				d = dd->a[0];	delete dd;
646 				AddParam(nn, mgl_str_num(d).c_str());
647 			}
648 			return res+1;
649 		}
650 		if(!str.compare(3,3,L"chr"))
651 		{
652 			int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
653 			if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
654 			{
655 				res = 0;
656 				HMDT dd = mglFormulaCalc(mgl_trim_ws(s.substr(2)), this, DataList);
657 				d=dd->a[0];	delete dd;
658 				wchar_t buf[2]={0,0};	buf[0] = wchar_t(d);	AddParam(nn, buf);
659 			}
660 			return res+1;
661 		}
662 	}
663 	if(!skip() && !str.compare(0,3,L"ask") && (str[3]==' ' || str[3]=='\t'))
664 	{
665 		PutArg(str,true);
666 		std::wstring s = mgl_trim_ws(str.substr(4));
667 		int nn = s[1]<='9' ? s[1]-'0' : (s[1]>='a' ? s[1]-'a'+10:-1);
668 		if(s[0]=='$' && nn>=0 && nn<='z'-'a'+10)
669 		{
670 			s = mgl_trim_ws(s.substr(2));
671 			if(s[0]=='\'')	s=s.substr(1,s.length()-2);
672 			if(mgl_ask_func)
673 			{
674 				static wchar_t res[1024];
675 				mgl_ask_func(s.c_str(),res);
676 				if(*res)	AddParam(nn, res);
677 			}
678 			return mgl_ask_func?1:2;
679 		}
680 		else	return 2;
681 	}
682 	if(!skip() && !str.compare(0,3,L"for") && (str[3]==' ' || str[3]=='\t'))
683 	{
684 		size_t i;	for(i=4;str[i]<=' ';i++);
685 		// if command have format 'for $N ...' then change it to 'for N ...'
686 		if(str[i]=='$' && str[i+1]>='0' && str[i+1]<='9')	str[i] = ' ';
687 		if(str[i]=='$' && str[i+1]>='a' && str[i+1]<='z')	str[i] = ' ';
688 	}
689 	return 0;
690 }
691 //-----------------------------------------------------------------------------
692 // return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string
Parse(mglGraph * gr,std::wstring str,long pos)693 int mglParser::Parse(mglGraph *gr, std::wstring str, long pos)
694 {
695 	if(Stop || gr->NeedStop())	return 0;
696 	curGr = gr->Self();	gr->pr = this;
697 	str=mgl_trim_ws(str);
698 	long n,k=0,m=0,mm=0,res;
699 	// try parse ':' -- several commands in line
700 	for(n=0;n<long(str.length());n++)
701 	{
702 		if(str[n]=='\'' && (n==0 || str[n-1]!='\\'))	k++;
703 		if(k%2)	continue;
704 		if(str[n]=='(')	m++;
705 		if(str[n]==')')	m--;
706 		if(str[n]=='{')	mm++;
707 		if(str[n]=='}')	mm--;
708 		if(str[n]=='#')	break;
709 		if((str[n]==':' || str[n]=='\n') && k%2==0 && m==0 && mm==0)
710 		{
711 			res=Parse(gr,str.substr(0,n),pos);
712 			if(!res)	res=Parse(gr,str.substr(n+1),pos);
713 			return res;
714 		}
715 	}
716 	if(k%2 || m || mm)	return 4;	// strings is not closed
717 	// define parameters or start cycle
718 	res = ParseDef(str);	if(res)	return res-1;
719 	// parse arguments (parameters $1, ..., $9)
720 	PutArg(str,false);	str=mgl_trim_ws(str);
721 
722 	std::wstring opt;
723 	std::vector<std::wstring> arg;
724 	while(!str.empty())	// parse string to substrings (by spaces)
725 	{
726 		n = mglFindArg(str);
727 		if(n<1)	// this is option
728 		{
729 			if(str[-n]==';')	opt = str.substr(-n+1);
730 			if(n<0)	str = str.substr(0,-n);
731 			break;
732 		}
733 		arg.push_back(str.substr(0,n));
734 		str = mgl_trim_ws(str.substr(n+1));
735 	}
736 	// try to find last argument
737 	if(str[0]!=0 && str[0]!='#' && str[0]!=';')	arg.push_back(str);
738 	k = arg.size();
739 	if(k<1) n = 0;
740 	else
741 	{
742 		// fill arguments by its values
743 		mglArg *a = new mglArg[k];
744 		FillArg(gr, k, &(arg[0]), a);
745 		// execute first special (program-flow-control) commands
746 		if(!skip() && !arg[0].compare(L"stop"))
747 		{	Stop = true;	delete []a;	return 0;	}
748 		if(!arg[0].compare(L"func"))
749 		{	Stop = true;	delete []a;	return 0;	}
750 		n = FlowExec(gr, arg[0].c_str(),k-1,a);
751 		if(n)		{	delete []a;	return n-1;	}
752 		if(skip())	{	delete []a;	return 0;	}
753 		if(!arg[0].compare(L"define"))
754 		{
755 			if(k==3)
756 			{
757 				DeleteVar(arg[1].c_str());	// force to delete variable with the same name
758 				mglNum *v=AddNum(arg[1].c_str());
759 				if(arg[2][0]=='!')	// complex number is added
760 				{	HADT dd = mglFormulaCalcC(arg[2].substr(1),this, DataList);
761 					v->d=NAN;	v->c = dd->a[0];	delete dd;	}
762 				else
763 				{	HMDT dd = mglFormulaCalc(arg[2],this, DataList);
764 					v->c = v->d = dd->a[0];	delete dd;	}
765 			}
766 			delete []a;	return k==3?0:1;
767 		}
768 		if(!arg[0].compare(L"call"))
769 		{
770 			n = 1;
771 			if(a[0].type==1)
772 			{
773 				int na=0;
774 				n=-IsFunc(a[0].s.w,&na);
775 				if(n && k!=na+2)
776 				{
777 					char buf[64];
778 					snprintf(buf,64,_("Bad arguments for %ls: %ld instead of %d\n"), a[0].s.w,k-2,na);
779 					buf[63]=0;	gr->SetWarn(-1,buf);	n = 1;
780 				}
781 				else if(n)
782 				{
783 					mglFnStack fn;			fn.pos = pos;	fn.stk = stack.size();
784 					for(int i=0;i<10;i++)	{	fn.par[i] = par[i];	par[i]=L"";	}
785 					for(int i=1;i<k-1;i++)	AddParam(i,arg[i+1].c_str());
786 					fn_stack.push_back(fn);	n--;
787 				}
788 				else if(AllowFileIO)	// disable external scripts if AllowFileIO=false
789 				{
790 					FILE *fp = fopen(a[0].s.s,"rt");
791 					if(fp)
792 					{
793 						mglParser *prs = new mglParser(AllowSetSize);
794 						prs->DataList.swap(DataList);	prs->NumList.swap(NumList);	prs->Cmd=Cmd;
795 						for(int i=10;i<30;i++)	prs->AddParam(i,par[i].w);
796 						prs->Execute(gr,fp);
797 						for(int i=10;i<30;i++)	AddParam(i,prs->par[i].w);
798 						DataList.swap(prs->DataList);	NumList.swap(prs->NumList);
799 						prs->Cmd=0;	delete prs;	fclose(fp);
800 					}
801 					else	n=1;
802 				}
803 			}
804 			delete []a;	return n;
805 		}
806 		if(!arg[0].compare(L"if") && k>3 && !arg[2].compare(L"then"))
807 		{
808 			bool cond=false;	n=0;
809 			if(a[0].type==2)	cond = (a[0].v!=0);
810 			else if(a[0].type==0)
811 			{	cond = a[0].d->FindAny((m>1 && a[1].type==1) ? a[1].s.s:"u");	}
812 			if(cond)
813 			{	// alocate new arrays and execute the command itself
814 				n = FlowExec(gr, arg[3].c_str(),k-4,a+3);
815 				if(!n && !skip())
816 				{
817 					n = PreExec(gr, k-4, &(arg[3]), a+3);
818 					if(n>0)	n--;
819 					else if(!arg[3].compare(L"setsize") && !AllowSetSize)	n = 2;
820 					else	n = Exec(gr, arg[3].c_str(),k-4,a+3, k>3?arg[4]:L"", opt.c_str());
821 				}
822 				else	n = skip()?0:n-1;
823 			}
824 			delete []a;	DeleteTemp();	return n;
825 		}
826 		if(!arg[0].compare(L"do"))
827 		{
828 			mglPosStack st(MGL_ST_LOOP);
829 			st.pos = pos;	st.par = -1;	st.ind = -1;
830 			stack.push_back(st);	delete []a;	return n;
831 		}
832 		if(!arg[0].compare(L"for"))
833 		{
834 			if(k<2)	{	delete []a;	return 1;	}
835 			n = 1;
836 			char ch = arg[1][0];
837 			int r = ch-'0';
838 			if(ch>='a' && ch<='z')	r = 10+ch-'a';
839 //			int r = int(a[0].v);
840 			mglPosStack st(MGL_ST_LOOP);
841 			if(arg[1][1]==0 && (r>=0 && r<40))
842 			{
843 				if(a[1].type==0)	{	st.v = *(a[1].d);	n=0;	}
844 				else if(a[1].type==2 && a[2].type==2 && a[2].v>=a[1].v)
845 				{
846 					mreal step = a[3].type==2?a[3].v:1;
847 					mm = int(step>0 ? (a[2].v-a[1].v)/step : 0);
848 					if(mm>=0)
849 					{
850 						n=0;	st.v.Create(mm+1);
851 						for(int ii=0;ii<mm+1;ii++)	st.v.a[ii] = a[1].v + step*ii;
852 					}
853 				}
854 				if(n==0)
855 				{
856 					st.pos = pos;	st.par = r;	st.ind = 1;
857 					st.v.nx *= st.v.ny*st.v.nz;	st.v.ny=st.v.nz=1;
858 					wchar_t buf[32];	mglprintf(buf,32,L"%g",st.v.a[0]);
859 					AddParam(r, buf);
860 				}
861 			}
862 			if(n)	st.state = MGL_ST_BREAK;
863 			stack.push_back(st);	delete []a;	return n;
864 		}
865 		// allocate new arrays and execute the command itself
866 		n = PreExec(gr, k, &(arg[0]), a);
867 		if(n>0)	n--;
868 		else if(!arg[0].compare(L"setsize") && !AllowSetSize)	n = 2;
869 		else	n = Exec(gr, arg[0].c_str(),k-1,a, k>1?arg[1]:L"", opt.c_str());
870 		delete []a;
871 	}
872 	DeleteTemp();	return n;
873 }
874 //-----------------------------------------------------------------------------
875 // return values: 0 - OK, 1 - wrong arguments, 2 - wrong command, 3 - string too long, 4 -- unclosed string
ParseDat(mglGraph * gr,std::wstring str,mglData & res)876 int mglParser::ParseDat(mglGraph *gr, std::wstring str, mglData &res)
877 {
878 	std::wstring arg[32];
879 	str = mgl_trim_ws(str);
880 	long n,k=0;
881 	for(k=0;k<32;k++)	// parse string to substrings (by spaces)
882 	{
883 		n = mglFindArg(str);
884 		if(n<1)	{	if(n<0)	str=str.substr(0,-n);	break;	}
885 		arg[k] = str.substr(0,n);//	k++;
886 		str = str.substr(n+1);	str = mgl_trim_ws(str);
887 	}
888 	// try to find last argument
889 	if(!str.empty() && k<32)	{	arg[k] = str;	k++;	}
890 	if(k<1) n = 0;
891 	else
892 	{	// fill arguments by its values
893 		mglArg *a = new mglArg[k+1];
894 		FillArg(gr, k, arg, a+1);	a[0].type=0;	a[0].d=&res;
895 		// alocate new arrays and execute the command itself
896 		int i;
897 		std::string kk;
898 		const char *id="dsn";
899 		for(i=0;i<k;i++)	kk += id[a[i].type];
900 		const mglCommand *rts=FindCommand(arg[0].c_str());
901 		if(!rts || rts->type!=4)	n = 2;
902 		else n = rts->exec(gr, k, a, kk.c_str(), 0);
903 		delete []a;
904 	}
905 	return n;
906 }
907 //-----------------------------------------------------------------------------
FlowExec(mglGraph *,const std::wstring & com,long m,mglArg * a)908 int mglParser::FlowExec(mglGraph *, const std::wstring &com, long m, mglArg *a)
909 {
910 	int n=-1;
911 	if(!ifskip() && !com.compare(L"once"))
912 	{
913 		if(a[0].type==2)
914 		{
915 			n = 0;
916 			if(a[0].v)	Skip = !Once;
917 			else	Skip = Once = false;
918 		}
919 		else n = 1;
920 	}
921 	else if(!Skip && !com.compare(L"if"))
922 	{
923 		bool cond=0;	n=1;
924 		if(m>2 && a[1].type==0 && !wcscmp(a[1].d->Name(),L"then"))
925 		{	n = -1;	a[1].d->temp=true;	}	// NOTE: ugly hack :(
926 		else if(a[0].type==2)
927 		{	n = 0;	cond = (a[0].v!=0);	}
928 		else	n = TestCond(m, a[0], a[1], cond);
929 		if(n==0)
930 		{	mglPosStack st(cond?MGL_ST_TRUE:MGL_ST_FALSE);	stack.push_back(st);	}
931 	}
932 	else if(!Skip && !com.compare(L"while"))
933 	{
934 		n=1;	if(stack.size())
935 		{
936 			mglPosStack &st = stack.back();
937 			if(st.state==MGL_ST_LOOP)
938 			{
939 				bool cond = false;
940 				n = TestCond(m, a[0], a[1], cond);
941 				if(cond)
942 				{
943 					if(st.ind<0)	n = -st.pos-1;	// do-while loop
944 					else if(st.ind<st.v.GetNN())	// next iteration
945 					{
946 						wchar_t buf[32];	mglprintf(buf,32,L"%g",st.v.a[st.ind]);
947 						AddParam(st.par, buf);	st.ind++;	n = -st.pos-1;
948 					}
949 					else	stack.pop_back();	// finish
950 				}
951 				else	stack.pop_back();
952 			}
953 			else if(st.state==MGL_ST_BREAK)
954 			{	stack.pop_back();	n=0;	}
955 		}
956 	}
957 	else if(!Skip && !com.compare(L"endif"))
958 	{
959 		if(stack.size() && stack.back().state<MGL_ST_LOOP)
960 		{	stack.pop_back();	n=0;	}
961 		else	n = 1;
962 	}
963 	else if(!Skip && !com.compare(L"else"))
964 	{
965 		n=1;	if(stack.size())
966 		{
967 			mglPosStack &st = stack.back();
968 			if(st.state<MGL_ST_LOOP)	n=0;
969 			if(st.state==MGL_ST_TRUE)	st.state = MGL_ST_DONE;
970 			if(st.state==MGL_ST_FALSE)	st.state = MGL_ST_TRUE;
971 		}
972 	}
973 	else if(!Skip && !com.compare(L"elseif"))
974 	{
975 		n=1;	if(stack.size())
976 		{
977 			mglPosStack &st = stack.back();
978 			if(st.state<MGL_ST_LOOP)	n=0;
979 			if(st.state==MGL_ST_TRUE)	st.state = MGL_ST_DONE;
980 			if(st.state==MGL_ST_FALSE)
981 			{
982 				bool cond=false;
983 				n = TestCond(m, a[0], a[1], cond);
984 				if(cond)	st.state = MGL_ST_TRUE;
985 			}
986 		}
987 	}
988 	else if(!ifskip() && !Skip && !com.compare(L"break"))
989 	{
990 		bool nf=true;
991 		size_t nn = stack.size();
992 		if(nn)	for(size_t i=nn;i>0;i--)
993 			if(stack[i-1].state==MGL_ST_LOOP)
994 			{	nf=false;	stack[i-1].state=MGL_ST_BREAK;	break;	}
995 		n = nf?1:0;
996 	}
997 	else if(!ifskip() && !Skip && !com.compare(L"next"))
998 	{
999 		n=1;
1000 		if(stack.size())
1001 		{
1002 			mglPosStack &st = stack.back();
1003 			if(st.state==MGL_ST_LOOP)
1004 			{
1005 				if(st.ind<0)	n = -st.pos-1;	// do-while loop
1006 				else if(st.ind<st.v.GetNN())	// next iteration
1007 				{
1008 					wchar_t buf[32];	mglprintf(buf,32,L"%g",st.v.a[st.ind]);
1009 					AddParam(st.par, buf);	st.ind++;	n = -st.pos-1;
1010 				}
1011 				else	{	stack.pop_back();	n=0;	}	// finish
1012 			}
1013 			else if(st.state==MGL_ST_BREAK)
1014 			{	stack.pop_back();	n=0;	}
1015 		}
1016 	}
1017 	else if(!ifskip() && !Skip && !com.compare(L"continue"))
1018 	{
1019 		bool nf=true;
1020 		size_t nn = stack.size();
1021 		if(nn)	for(size_t i=nn;i>0;i--)
1022 		{
1023 			mglPosStack &st = stack[i-1];
1024 			if(st.state==MGL_ST_LOOP)
1025 			{
1026 				if(st.ind<0)	n = -st.pos-1;	// do-while loop
1027 				else if(st.ind<st.v.GetNN())	// next iteration
1028 				{
1029 					wchar_t buf[32];	mglprintf(buf,32,L"%g",st.v.a[st.ind]);
1030 					AddParam(st.par, buf);	st.ind++;	n = -st.pos-1;
1031 				}
1032 				else	{	st.state = MGL_ST_BREAK;	n=0;	}	// finish
1033 				nf=false;	stack.resize(i);	break;
1034 			}
1035 		}
1036 		if(nf)	n=1;
1037 	}
1038 	else if(!skip() && !com.compare(L"return"))
1039 	{
1040 		if(fn_stack.size()<1)	return 2;
1041 		const mglFnStack &fn=fn_stack.back();
1042 		for(int i=0;i<10;i++)	par[i]=fn.par[i];
1043 		n = -fn.pos-1;	fn_stack.pop_back();
1044 	}
1045 	return n+1;
1046 }
1047 //-----------------------------------------------------------------------------
Execute(mglGraph * gr,FILE * fp,bool print)1048 void mglParser::Execute(mglGraph *gr, FILE *fp, bool print)
1049 {
1050 	if(gr==0 || fp==0)	return;
1051 	std::wstring str;
1052 	wchar_t ch;
1053 	while(!feof(fp) && size_t(ch=fgetwc(fp))!=WEOF)	str.push_back(ch);
1054 	Execute(gr,str.c_str());
1055 	if(print)	printf("%s\n",gr->Message());
1056 }
1057 //-----------------------------------------------------------------------------
Execute(mglGraph * gr,int n,const wchar_t ** text)1058 void mglParser::Execute(mglGraph *gr, int n, const wchar_t **text)
1059 {
1060 	if(n<1 || text==0)	return;
1061 	long res=0;
1062 	char buf[64];
1063 	Skip=false;	ScanFunc(0);	fn_stack.clear();	stack.clear();
1064 	for(long i=0;i<n;i++)	ScanFunc(text[i]);
1065 	for(long i=0;i<n;i++)
1066 	{
1067 		gr->SetWarn(-1, "");
1068 		gr->SetObjId(i+1+StarObhID);
1069 		long r = Parse(gr,text[i],i+1);
1070 		if(r<0)	{	i = -r-2;	continue;	}
1071 		if(r==1)		snprintf(buf,64,_("\nWrong argument(s) in line %ld"), i+1);
1072 		else if(r==2)	snprintf(buf,64,_("\nWrong command in line %ld"), i+1);
1073 		else if(r==3)	snprintf(buf,64,_("\nString too long in line %ld"), i+1);
1074 		else if(r==4)	snprintf(buf,64,_("\nUnbalanced ' in line %ld"), i+1);
1075 		else if(r==5)	snprintf(buf,64,_("\nChange temporary data in line %ld"), i+1);
1076 		else if(gr->GetWarn()>0)	snprintf(buf,64,_("in line %ld"), i+1);
1077 		else *buf=0;
1078 		buf[63] = 0;
1079 		if(*buf)	gr->SetWarn(-2,buf);
1080 		if(r>0 && r<5)	res=r;
1081 	}
1082 	int code[]={mglScrArg,	mglScrCmd,	mglScrLong,	mglScrStr, mglScrTemp};
1083 	if(res>0)	gr->SetWarn(code[res-1],_("MGL Parser"));
1084 }
1085 //-----------------------------------------------------------------------------
Execute(mglGraph * gr,const wchar_t * text)1086 void mglParser::Execute(mglGraph *gr, const wchar_t *text)
1087 {
1088 	size_t s = mgl_wcslen(text)+1, n=1;
1089 	wchar_t *wcs = new wchar_t[s];
1090 	const wchar_t **str;
1091 	for(size_t i=0;i<s;i++)	if(text[i]=='\n')	n++;
1092 	str = (const wchar_t **)malloc(n*sizeof(wchar_t *));
1093 	memcpy(wcs, text, s*sizeof(wchar_t));
1094 	str[0] = wcs;	n=1;
1095 	long next=0;
1096 	Stop = false;
1097 	for(size_t i=0;i<s;i++)
1098 	{
1099 		if(text[i]=='\\')	next = i;
1100 		else if(text[i]>' ')next = 0;
1101 		if(text[i]=='\n')
1102 		{	// if string need to be continued then I put ' ' instead of 0x0 and
1103 			// pointer next string to 0x0. Last one for keeping number of strings.
1104 			if(next)
1105 			{	for(size_t ii=next;ii<=i;ii++)	wcs[ii]='\b';	str[n] = wcs+s-1;	next=0;	}
1106 			else
1107 			{	wcs[i]=0;	str[n] = wcs+i+1;	}
1108 			n++;
1109 		}
1110 	}
1111 	Execute(gr, n, str);
1112 	delete []wcs;	free(str);
1113 }
1114 //-----------------------------------------------------------------------------
Execute(mglGraph * gr,const char * text)1115 void mglParser::Execute(mglGraph *gr, const char *text)
1116 {
1117 	MGL_TO_WCS(text, Execute(gr, wcs));
1118 }
1119 //-----------------------------------------------------------------------------
DeleteVar(const char * name)1120 void mglParser::DeleteVar(const char *name)
1121 {
1122 	MGL_TO_WCS(name,DeleteVar(wcs));
1123 }
1124 //-----------------------------------------------------------------------------
DeleteVar(const wchar_t * name)1125 void mglParser::DeleteVar(const wchar_t *name)
1126 {
1127 	for(size_t i=0;i<DataList.size();i++)
1128 		if(DataList[i] && !wcscmp(DataList[i]->Name(),name))
1129 		{	mglDataA *u=DataList[i];	DataList[i]=0;	delete u;	}
1130 }
1131 //-----------------------------------------------------------------------------
AddCommand(const mglCommand * cmd)1132 void mglParser::AddCommand(const mglCommand *cmd)
1133 {
1134 	// determine the number of symbols
1135 	size_t mp=0;	while(Cmd[mp].name[0])	mp++;
1136 	size_t mc=0;	while(cmd[mc].name[0])	mc++;
1137 	// copy all together
1138 	mglCommand *buf = new mglCommand[mp+mc+1];
1139 	memcpy(buf, cmd, mc*sizeof(mglCommand));
1140 	memcpy(buf+mc, Cmd, (mp+1)*sizeof(mglCommand));
1141 	qsort(buf, mp+mc, sizeof(mglCommand), mgl_cmd_cmp);	// sort it
1142 #pragma omp critical(cmd_parser)
1143 	{	if(Cmd!=BaseCmd)   delete []Cmd;	Cmd = buf;	}
1144 }
1145 //-----------------------------------------------------------------------------
mgl_create_parser()1146 HMPR MGL_EXPORT mgl_create_parser()		{	return new mglParser;	}
mgl_delete_parser(HMPR p)1147 void MGL_EXPORT mgl_delete_parser(HMPR p)	{	delete p;	}
mgl_parser_add_param(HMPR p,int id,const char * str)1148 void MGL_EXPORT mgl_parser_add_param(HMPR p, int id, const char *str)			{	p->AddParam(id,str);	}
mgl_parser_add_paramw(HMPR p,int id,const wchar_t * str)1149 void MGL_EXPORT mgl_parser_add_paramw(HMPR p, int id, const wchar_t *str)		{	p->AddParam(id,str);	}
mgl_parser_add_var(HMPR p,const char * name)1150 MGL_EXPORT mglDataA *mgl_parser_add_var(HMPR p, const char *name)	{	return p->AddVar(name);	}
mgl_parser_find_var(HMPR p,const char * name)1151 MGL_EXPORT_PURE mglDataA *mgl_parser_find_var(HMPR p, const char *name)	{	return p->FindVar(name);}
mgl_parser_del_var(HMPR p,const char * name)1152 void MGL_EXPORT mgl_parser_del_var(HMPR p, const char *name)	{	p->DeleteVar(name);	}
mgl_parser_add_varw(HMPR p,const wchar_t * name)1153 MGL_EXPORT mglDataA *mgl_parser_add_varw(HMPR p, const wchar_t *name)	{	return p->AddVar(name);	}
mgl_parser_find_varw(HMPR p,const wchar_t * name)1154 MGL_EXPORT_PURE mglDataA *mgl_parser_find_varw(HMPR p, const wchar_t *name)	{	return p->FindVar(name);}
mgl_parser_del_varw(HMPR p,const wchar_t * name)1155 void MGL_EXPORT mgl_parser_del_varw(HMPR p, const wchar_t *name)	{	p->DeleteVar(name);	}
mgl_parse_line(HMGL gr,HMPR p,const char * str,int pos)1156 int MGL_EXPORT mgl_parse_line(HMGL gr, HMPR p, const char *str, int pos)
1157 {	return p->Parse(gr, str, pos);	}
mgl_parse_linew(HMGL gr,HMPR p,const wchar_t * str,int pos)1158 int MGL_EXPORT mgl_parse_linew(HMGL gr, HMPR p, const wchar_t *str, int pos)
1159 {	return p->Parse(gr, str, pos);	}
mgl_parse_text(HMGL gr,HMPR p,const char * str)1160 void MGL_EXPORT mgl_parse_text(HMGL gr, HMPR p, const char *str)
1161 {	p->Execute(gr, str);	}
mgl_parse_textw(HMGL gr,HMPR p,const wchar_t * str)1162 void MGL_EXPORT mgl_parse_textw(HMGL gr, HMPR p, const wchar_t *str)
1163 {	p->Execute(gr, str);	}
mgl_parse_file(HMGL gr,HMPR p,FILE * fp,int print)1164 void MGL_EXPORT mgl_parse_file(HMGL gr, HMPR p, FILE *fp, int print)
1165 {	p->Execute(gr,fp,print);	}
mgl_parser_restore_once(HMPR p)1166 void MGL_EXPORT mgl_parser_restore_once(HMPR p)	{	p->RestoreOnce();	}
mgl_parser_stop(HMPR p)1167 void MGL_EXPORT mgl_parser_stop(HMPR p)	{	p->Stop = true;		}
mgl_parser_allow_setsize(HMPR p,int a)1168 void MGL_EXPORT mgl_parser_allow_setsize(HMPR p, int a)	{	p->AllowSetSize= a;	}
mgl_parser_allow_file_io(HMPR p,int a)1169 void MGL_EXPORT mgl_parser_allow_file_io(HMPR p, int a)	{	p->AllowFileIO = a;	}
mgl_parser_allow_dll_call(HMPR p,int a)1170 void MGL_EXPORT mgl_parser_allow_dll_call(HMPR p, int a){	p->AllowDllCall = a;	}
1171 //-----------------------------------------------------------------------------
1172 #define _PR_	((mglParser *)(*p))
mgl_create_parser_()1173 uintptr_t MGL_EXPORT mgl_create_parser_()	{	return uintptr_t(new mglParser);	}
mgl_delete_parser_(uintptr_t * p)1174 void MGL_EXPORT mgl_delete_parser_(uintptr_t* p)	{	delete _PR_;	}
mgl_parser_add_param_(uintptr_t * p,int * id,const char * str,int l)1175 void MGL_EXPORT mgl_parser_add_param_(uintptr_t* p, int *id, const char *str, int l)
1176 {	char *s=new char[l+1];		memcpy(s,str,l);	s[l]=0;
1177 	_PR_->AddParam(*id, s);		delete []s;	}
1178 /*===!!! NOTE !!! You must not delete obtained data arrays !!!===============*/
mgl_parser_add_var_(uintptr_t * p,const char * name,int l)1179 uintptr_t MGL_EXPORT mgl_parser_add_var_(uintptr_t* p, const char *name, int l)
1180 {	char *s=new char[l+1];		memcpy(s,name,l);	s[l]=0;
1181 	mglDataA *v=_PR_->AddVar(s);	delete []s;	return uintptr_t(v);	}
1182 /*===!!! NOTE !!! You must not delete obtained data arrays !!!===============*/
mgl_parser_find_var_(uintptr_t * p,const char * name,int l)1183 uintptr_t MGL_EXPORT mgl_parser_find_var_(uintptr_t* p, const char *name, int l)
1184 {	char *s=new char[l+1];		memcpy(s,name,l);	s[l]=0;
1185 	mglDataA *v=_PR_->FindVar(s);	delete []s;	return uintptr_t(v);	}
mgl_parser_del_var_(uintptr_t * p,const char * name,int l)1186 void MGL_EXPORT mgl_parser_del_var_(uintptr_t* p, const char *name, int l)
1187 {	char *s=new char[l+1];		memcpy(s,name,l);	s[l]=0;
1188 	_PR_->DeleteVar(s);	delete []s;	}
mgl_parse_line_(uintptr_t * gr,uintptr_t * p,const char * str,int * pos,int l)1189 int MGL_EXPORT mgl_parse_line_(uintptr_t* gr, uintptr_t* p, const char *str, int *pos, int l)
1190 {	char *s=new char[l+1];		memcpy(s,str,l);	s[l]=0;
1191 	int r = _PR_->Parse(_GR_, s, *pos);	delete []s;	return r;	}
mgl_parse_text_(uintptr_t * gr,uintptr_t * p,const char * str,int l)1192 void MGL_EXPORT mgl_parse_text_(uintptr_t* gr, uintptr_t* p, const char *str, int l)
1193 {	char *s=new char[l+1];		memcpy(s,str,l);	s[l]=0;
1194 	_PR_->Execute(_GR_, s);	delete []s;	}
mgl_parser_restore_once_(uintptr_t * p)1195 void MGL_EXPORT mgl_parser_restore_once_(uintptr_t* p)	{	_PR_->RestoreOnce();	}
mgl_parser_allow_setsize_(uintptr_t * p,int * a)1196 void MGL_EXPORT mgl_parser_allow_setsize_(uintptr_t* p, int *a)	{	_PR_->AllowSetSize= *a;	}
mgl_parser_allow_file_io_(uintptr_t * p,int * a)1197 void MGL_EXPORT mgl_parser_allow_file_io_(uintptr_t* p, int *a)	{	_PR_->AllowFileIO = *a;	}
mgl_parser_allow_dll_call_(uintptr_t * p,int * a)1198 void MGL_EXPORT mgl_parser_allow_dll_call_(uintptr_t* p, int *a){	_PR_->AllowDllCall= *a;	}
mgl_parser_stop_(uintptr_t * p)1199 void MGL_EXPORT mgl_parser_stop_(uintptr_t* p)	{	_PR_->Stop = true;	}
1200 //-----------------------------------------------------------------------------
mgl_use_parser(HMPR pr,int inc)1201 long MGL_EXPORT mgl_use_parser(HMPR pr, int inc)
1202 {	pr->InUse+=inc;	return pr->InUse;	}
mgl_use_parser_(uintptr_t * p,int * inc)1203 long MGL_EXPORT mgl_use_parser_(uintptr_t *p, int *inc)
1204 {	_PR_->InUse+=*inc;	return _PR_->InUse;	}
1205 //---------------------------------------------------------------------------
mgl_parser_get_var(HMPR p,unsigned long id)1206 MGL_EXPORT_PURE mglDataA *mgl_parser_get_var(HMPR p, unsigned long id)
1207 {	return id<p->DataList.size()?p->DataList[id]:0;	}
mgl_parser_get_var_(uintptr_t * p,unsigned long * id)1208 uintptr_t MGL_EXPORT_PURE mgl_parser_get_var_(uintptr_t* p, unsigned long *id)
1209 {	return uintptr_t(mgl_parser_get_var(_PR_,*id));	}
mgl_parser_num_var(HMPR p)1210 long MGL_EXPORT_PURE mgl_parser_num_var(HMPR p)
1211 {	return p->DataList.size();	}
mgl_parser_num_var_(uintptr_t * p)1212 long MGL_EXPORT_PURE mgl_parser_num_var_(uintptr_t* p)
1213 {	return mgl_parser_num_var(_PR_);	}
mgl_parser_num_const(HMPR p)1214 long MGL_EXPORT_PURE mgl_parser_num_const(HMPR p)
1215 {	return p->NumList.size();	}
mgl_parser_num_const_(uintptr_t * p)1216 long MGL_EXPORT_PURE mgl_parser_num_const_(uintptr_t* p)
1217 {	return mgl_parser_num_const(_PR_);	}
mgl_parser_get_const(HMPR p,unsigned long id)1218 MGL_EXPORT_PURE mglNum *mgl_parser_get_const(HMPR p, unsigned long id)
1219 {	return id<p->NumList.size()?p->NumList[id]:0;	}
mgl_parser_get_const_(uintptr_t * p,unsigned long * id)1220 uintptr_t MGL_EXPORT_PURE mgl_parser_get_const_(uintptr_t* p, unsigned long *id)
1221 {	return uintptr_t(mgl_parser_get_const(_PR_,*id));	}
1222 //---------------------------------------------------------------------------
mgl_parser_cmd_type(HMPR pr,const char * name)1223 int MGL_EXPORT_PURE mgl_parser_cmd_type(HMPR pr, const char *name)
1224 {
1225 	const mglCommand *cmd = pr->FindCommand(name);
1226 	return cmd ? cmd->type + 1 : 0;
1227 }
mgl_parser_cmd_type_(uintptr_t * p,const char * str,int l)1228 int MGL_EXPORT_PURE mgl_parser_cmd_type_(uintptr_t* p, const char *str, int l)
1229 {	char *s=new char[l+1];	memcpy(s,str,l);	s[l]=0;
1230 	l = mgl_parser_cmd_type(_PR_, s);	delete []s;	return l;	}
1231 //---------------------------------------------------------------------------
mgl_parser_cmd_desc(HMPR pr,const char * name)1232 MGL_EXPORT_PURE const char *mgl_parser_cmd_desc(HMPR pr, const char *name)
1233 {
1234 	const mglCommand *cmd = pr->FindCommand(name);
1235 	return cmd ? cmd->desc : 0;
1236 }
mgl_parser_cmd_frmt(HMPR pr,const char * name)1237 MGL_EXPORT_PURE const char *mgl_parser_cmd_frmt(HMPR pr, const char *name)
1238 {
1239 	const mglCommand *cmd = pr->FindCommand(name);
1240 	return cmd ? cmd->form : 0;
1241 }
1242 //---------------------------------------------------------------------------
mgl_parser_cmd_name(HMPR pr,long id)1243 MGL_EXPORT_PURE const char *mgl_parser_cmd_name(HMPR pr, long id)
1244 {	return (id<mgl_parser_cmd_num(pr) && id>=0) ? pr->Cmd[id].name:"";	}
mgl_parser_cmd_num(HMPR pr)1245 long MGL_EXPORT_PURE mgl_parser_cmd_num(HMPR pr)
1246 {	long i=0;	while(pr->Cmd[i].name[0])	i++; 	return i;	}
1247 //---------------------------------------------------------------------------
mgl_parser_calc(HMPR pr,const char * formula)1248 HMDT MGL_EXPORT mgl_parser_calc(HMPR pr, const char *formula)
1249 {	HMDT d=0;	MGL_TO_WCS(formula,d = mgl_parser_calcw(pr,wcs));	return d;	}
mgl_parser_calcw(HMPR pr,const wchar_t * formula)1250 HMDT MGL_EXPORT mgl_parser_calcw(HMPR pr, const wchar_t *formula)
1251 {	return mglFormulaCalc(formula,pr, pr->DataList);	}
mgl_parser_calc_(uintptr_t * p,const char * str,int l)1252 uintptr_t MGL_EXPORT mgl_parser_calc_(uintptr_t *p, const char *str,int l)
1253 {	char *s=new char[l+1];	memcpy(s,str,l);	s[l]=0;
1254 	uintptr_t d = (uintptr_t)mgl_parser_calc(_PR_, s);	delete []s;	return d;	}
1255 //---------------------------------------------------------------------------
mgl_parser_calc_complex(HMPR pr,const char * formula)1256 HADT MGL_EXPORT mgl_parser_calc_complex(HMPR pr, const char *formula)
1257 {	HADT d=0;	MGL_TO_WCS(formula,d = mgl_parser_calc_complexw(pr,wcs));	return d;	}
mgl_parser_calc_complexw(HMPR pr,const wchar_t * formula)1258 HADT MGL_EXPORT mgl_parser_calc_complexw(HMPR pr, const wchar_t *formula)
1259 {	return mglFormulaCalcC(formula,pr, pr->DataList);	}
mgl_parser_calc_complex_(uintptr_t * p,const char * str,int l)1260 uintptr_t MGL_EXPORT mgl_parser_calc_complex_(uintptr_t *p, const char *str,int l)
1261 {	char *s=new char[l+1];	memcpy(s,str,l);	s[l]=0;
1262 	uintptr_t d = (uintptr_t)mgl_parser_calc_complex(_PR_, s);	delete []s;	return d;	}
1263 //---------------------------------------------------------------------------
mgl_parser_del_all(HMPR p)1264 void MGL_EXPORT mgl_parser_del_all(HMPR p)	{	p->DeleteAll();	}
mgl_parser_del_all_(uintptr_t * p)1265 void MGL_EXPORT mgl_parser_del_all_(uintptr_t *p)	{	_PR_->DeleteAll();	}
1266 //---------------------------------------------------------------------------
mgl_parser_load(HMPR pr,const char * so_name)1267 void MGL_EXPORT mgl_parser_load(HMPR pr, const char *so_name)
1268 {
1269 	if(!pr->AllowDllCall)	return;
1270 #if MGL_HAVE_LTDL
1271 	lt_dlhandle so = lt_dlopen(so_name);
1272 	if(!so)	return;
1273 	const mglCommand *cmd = (const mglCommand *)lt_dlsym(so,"mgl_cmd_extra");
1274 	bool exist = true;
1275 	if(cmd)	for(size_t i=0;cmd[i].name[0];i++)
1276 		if(!pr->FindCommand(cmd[i].name))	exist=false;
1277 	if(exist)	{	lt_dlclose(so);	return;	}	// all commands already presents
1278 	else	pr->DllOpened.push_back(so);
1279 	pr->AddCommand(cmd);
1280 #endif
1281 }
mgl_parser_load_(uintptr_t * p,const char * dll_name,int l)1282 void MGL_EXPORT mgl_parser_load_(uintptr_t *p, const char *dll_name,int l)
1283 {	char *s=new char[l+1];	memcpy(s,dll_name,l);	s[l]=0;
1284 	mgl_parser_load(_PR_, s);	delete []s;	}
1285 //---------------------------------------------------------------------------
1286 struct mglRKdat
1287 {
1288 	mglDataA *v;
1289 	std::wstring e;
1290 	bool cmplx;
1291 	mglDataC cin,c1,c2,c3,c4, *cc;
1292 	mglData  din,d1,d2,d3,d4, *dd;
mglRKdatmglRKdat1293 	mglRKdat(mglDataA *var, std::wstring &eq):v(var), e(eq)
1294 	{	cmplx = dynamic_cast<mglDataC*>(var);	cc=0;	dd=0;	}
allocatemglRKdat1295 	void allocate()
1296 	{
1297 		if(cmplx)
1298 		{	cc = dynamic_cast<mglDataC*>(v);	cin.Set(v);	}
1299 		else
1300 		{	dd = dynamic_cast<mglData*>(v);		din.Set(v);	}
1301 	}
1302 };
mgl_rk_step_w(HMPR pr,const wchar_t * Eqs,const wchar_t * Vars,mreal dt)1303 void MGL_EXPORT mgl_rk_step_w(HMPR pr, const wchar_t *Eqs, const wchar_t *Vars, mreal dt)
1304 {
1305 	const std::wstring eqs(Eqs);
1306 	const std::wstring vars(Vars);
1307 	std::vector<mglRKdat> rkv;
1308 	size_t iv=0,jv=0,ie=0,je=0;
1309 	while(1)
1310 	{
1311 		iv = vars.find(';',jv);	ie = eqs.find(';',je);
1312 		mglDataA *vv=mgl_parser_find_varw(pr,vars.substr(jv,iv-jv).c_str());
1313 		std::wstring eq = eqs.substr(je,ie-je).c_str();
1314 		if(vv)	rkv.push_back(mglRKdat(vv, eq ));
1315 		jv = iv+1;	je = ie+1;
1316 		if(iv==std::wstring::npos || ie==std::wstring::npos)	break;
1317 	}
1318 	for(size_t i=0;i<rkv.size();i++)	rkv[i].allocate();
1319 	mreal hh = dt/2;
1320 	for(size_t i=0;i<rkv.size();i++)
1321 	{
1322 		mglRKdat &rk = rkv[i];
1323 		if(rk.cmplx)	rk.c1.Move(mglFormulaCalcC(rk.e, pr, pr->DataList));
1324 		else	rk.d1.Move(mglFormulaCalc(rk.e, pr, pr->DataList));
1325 	}
1326 	for(size_t i=0;i<rkv.size();i++)
1327 	{
1328 		mglRKdat &rk = rkv[i];
1329 		if(rk.cc)
1330 		{
1331 			long n = rk.cc->GetNN();	dual a = hh*rk.c1.a[0];
1332 			if(rk.c1.GetNN()==n)
1333 #pragma omp parallel for
1334 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + hh*rk.c1.a[j];
1335 			else
1336 #pragma omp parallel for
1337 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + a;
1338 		}
1339 		if(rk.dd)
1340 		{
1341 			long n = rk.dd->GetNN();	mreal a = hh*rk.d1.a[0];
1342 			if(rk.d1.GetNN()==n)
1343 #pragma omp parallel for
1344 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + hh*rk.d1.a[j];
1345 			else
1346 #pragma omp parallel for
1347 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + a;
1348 		}
1349 	}
1350 
1351 	for(size_t i=0;i<rkv.size();i++)
1352 	{
1353 		mglRKdat &rk = rkv[i];
1354 		if(rk.cmplx)	rk.c2.Move(mglFormulaCalcC(rk.e, pr, pr->DataList));
1355 		else	rk.d2.Move(mglFormulaCalc(rk.e, pr, pr->DataList));
1356 	}
1357 	for(size_t i=0;i<rkv.size();i++)
1358 	{
1359 		mglRKdat &rk = rkv[i];
1360 		if(rk.cc)
1361 		{
1362 			long n = rk.cc->GetNN();	dual a = hh*rk.c2.a[0];
1363 			if(rk.c2.GetNN()==n)
1364 #pragma omp parallel for
1365 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + hh*rk.c2.a[j];
1366 			else
1367 #pragma omp parallel for
1368 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + a;
1369 		}
1370 		if(rk.dd)
1371 		{
1372 			long n = rk.dd->GetNN();	mreal a = hh*rk.d2.a[0];
1373 			if(rk.d2.GetNN()==n)
1374 #pragma omp parallel for
1375 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + hh*rk.d2.a[j];
1376 			else
1377 #pragma omp parallel for
1378 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + a;
1379 		}
1380 	}
1381 
1382 	for(size_t i=0;i<rkv.size();i++)
1383 	{
1384 		mglRKdat &rk = rkv[i];
1385 		if(rk.cmplx)	rk.c3.Move(mglFormulaCalcC(rk.e, pr, pr->DataList));
1386 		else	rk.d3.Move(mglFormulaCalc(rk.e, pr, pr->DataList));
1387 	}
1388 	for(size_t i=0;i<rkv.size();i++)
1389 	{
1390 		mglRKdat &rk = rkv[i];
1391 		if(rk.cc)
1392 		{
1393 			long n = rk.cc->GetNN();	dual a = dt*rk.c3.a[0];
1394 			if(rk.c3.GetNN()==n)
1395 #pragma omp parallel for
1396 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + dt*rk.c3.a[j];
1397 			else
1398 #pragma omp parallel for
1399 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + a;
1400 		}
1401 		if(rk.dd)
1402 		{
1403 			long n = rk.dd->GetNN();	mreal a = dt*rk.d3.a[0];
1404 			if(rk.d3.GetNN()==n)
1405 #pragma omp parallel for
1406 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + dt*rk.d3.a[j];
1407 			else
1408 #pragma omp parallel for
1409 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + a;
1410 		}
1411 	}
1412 
1413 	for(size_t i=0;i<rkv.size();i++)
1414 	{
1415 		mglRKdat &rk = rkv[i];
1416 		if(rk.cmplx)	rk.c4.Move(mglFormulaCalcC(rk.e, pr, pr->DataList));
1417 		else	rk.d4.Move(mglFormulaCalc(rk.e, pr, pr->DataList));
1418 	}
1419 	for(size_t i=0;i<rkv.size();i++)
1420 	{
1421 		mglRKdat &rk = rkv[i];
1422 		if(rk.cc)
1423 		{
1424 			long n = rk.cc->GetNN();
1425 			dual a = (rk.c1.a[0]+rk.c2.a[0]+mreal(2)*(rk.c3.a[0]+rk.c4.a[0]))*(dt/6);
1426 			if(rk.c1.GetNN()==n)
1427 #pragma omp parallel for
1428 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + (rk.c1.a[j]+rk.c2.a[j]+mreal(2)*(rk.c3.a[j]+rk.c4.a[j]))*(dt/6);
1429 			else
1430 #pragma omp parallel for
1431 				for(long j=0;j<n;j++)	rk.cc->a[j] = rk.cin.a[j] + a;
1432 		}
1433 		if(rk.dd)
1434 		{
1435 			long n = rk.dd->GetNN();
1436 			mreal a = (rk.d1.a[0]+rk.d2.a[0]+2*(rk.d3.a[0]+rk.d4.a[0]))*(dt/6);
1437 			if(rk.d1.GetNN()==n)
1438 #pragma omp parallel for
1439 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + (rk.d1.a[j]+rk.d2.a[j]+2*(rk.d3.a[j]+rk.d4.a[j]))*(dt/6);
1440 			else
1441 #pragma omp parallel for
1442 				for(long j=0;j<n;j++)	rk.dd->a[j] = rk.din.a[j] + a;
1443 		}
1444 	}
1445 }
mgl_rk_step(HMPR pr,const char * Eqs,const char * Vars,mreal dt)1446 void MGL_EXPORT mgl_rk_step(HMPR pr, const char *Eqs, const char *Vars, mreal dt)
1447 {
1448 	if(Eqs && *Eqs && Vars && *Vars)
1449 	{
1450 		size_t s=mbstowcs(0,Eqs,0), w=mbstowcs(0,Vars,0);
1451 		wchar_t *eqs=new wchar_t[s+1];	mbstowcs(eqs,Eqs ,s);	eqs[s]=0;
1452 		wchar_t *wcs=new wchar_t[s+1];	mbstowcs(wcs,Vars,s);	wcs[w]=0;
1453 		mgl_rk_step_w(pr,eqs,wcs,dt);	delete []wcs;	delete []eqs;
1454 	}
1455 }
mgl_rk_step_(uintptr_t * p,const char * eqs,const char * vars,double * dt,int l,int m)1456 void MGL_EXPORT mgl_rk_step_(uintptr_t *p, const char *eqs, const char *vars, double *dt,int l,int m)
1457 {	char *e=new char[l+1];	memcpy(e,eqs,l);	e[l]=0;
1458 	char *s=new char[m+1];	memcpy(s,vars,m);	s[m]=0;
1459 	mgl_rk_step(_PR_,e,s,*dt);	delete []e;	delete []s;	}
1460 //---------------------------------------------------------------------------
mgl_parser_variant(HMPR p,int var)1461 void MGL_EXPORT mgl_parser_variant(HMPR p, int var)	{	p->SetVariant(var);	}
mgl_parser_variant_(uintptr_t * p,int * var)1462 void MGL_EXPORT mgl_parser_variant_(uintptr_t *p, int *var)	{	mgl_parser_variant(_PR_,*var);	}
1463 //---------------------------------------------------------------------------
mgl_parser_openhdf(HMPR p,const char * fname)1464 void MGL_EXPORT mgl_parser_openhdf(HMPR p, const char *fname)
1465 {
1466 	const char * const *res = mgl_datas_hdf_str(fname);
1467 	if(!res)	return;
1468 	for(size_t n=0;res[n][0];n++)
1469 	{
1470 		mglDataA *d = p->AddVar(res[n]);
1471 		mglData *dr = dynamic_cast<mglData*>(d);
1472 		mglDataC *dc = dynamic_cast<mglDataC*>(d);
1473 		if(dr)	dr->ReadHDF(fname,res[n]);
1474 		if(dc)	dc->ReadHDF(fname,res[n]);
1475 	}
1476 }
mgl_parser_openhdf_(uintptr_t * p,const char * fname,int l)1477 void MGL_EXPORT mgl_parser_openhdf_(uintptr_t *p, const char *fname,int l)
1478 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
1479 	mgl_parser_openhdf(_PR_,s);	delete []s;	}
1480 //---------------------------------------------------------------------------
mgl_parser_start_id(HMPR pr,int id)1481 void MGL_EXPORT mgl_parser_start_id(HMPR pr, int id)
1482 {	pr->StarObhID = id;	}
mgl_parser_start_id_(uintptr_t * p,int * id)1483 void MGL_EXPORT mgl_parser_start_id_(uintptr_t* p, int *id)
1484 {	mgl_parser_start_id(_PR_, *id);	}
1485 
1486 //---------------------------------------------------------------------------
1487 mglCommand mgls_prg_cmd[] = {
1488 	{"ask",_("Define parameter from user input"),"ask $N 'question'", 0, 6},
1489 	{"break",_("Break for-loop"),"break", 0, 6},
1490 	{"call",_("Execute script in external file"),"call 'name' [args]", 0, 6},
1491 	{"continue",_("Skip commands and iterate for-loop again"),"continue", 0, 6},
1492 	{"do",_("Begin of do-while loop"),"do", 0, 6},
1493 	{"defchr",_("Define parameter as character"),"defchr $N val", 0, 6},
1494 	{"define",_("Define constant or parameter"),"define $N sth | Var val", 0, 6},
1495 	{"defnum",_("Define parameter as numerical value"),"defnum $N val", 0, 6},
1496 //	{"defpal",_("Define parameter as palette color"),"defpal $N val", 0, 6},
1497 	{"else",_("Execute if condition is false"),"else", 0, 6},
1498 	{"elseif",_("Conditional operator"),"elseif val|Dat ['cond']", 0, 6},
1499 	{"endif",_("Finish if/else block"),"endif", 0, 6},
1500 	{"for",_("For loop"),"for $N v1 v2 [dv] | $N Dat", 0, 6},
1501 	{"func",_("Start function definition and stop execution of main script"),"func 'name' [narg]", 0, 6},
1502 	{"if",_("Conditional operator"),"if val|Dat ['cond']", 0, 6},
1503 	{"list",_("Creates new variable from list of numbers or data"),"list Var v1 ...|Var D1 ...", 0, 4},
1504 	{"next",_("Start next for-loop iteration"),"next", 0, 6},
1505 	{"once",_("Start/close commands which should executed only once"),"once val", 0, 6},
1506 	{"return",_("Return from function"),"return", 0, 6},
1507 	{"stop",_("Stop execution"),"stop", 0, 6},
1508 	{"while",_("Condition of do-while loop"),"while val|Dat ['cond']", 0, 6},
1509 {"","","",NULL,0}};
1510 //-----------------------------------------------------------------------------
1511