1 /***************************************************************************
2  * parser.h 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 #ifndef _MGL_PARSER_H_
21 #define _MGL_PARSER_H_
22 
23 #ifdef __cplusplus
24 #include "mgl2/mgl.h"
25 #if MGL_HAVE_LTDL
26 #include <ltdl.h>
27 #endif
28 //-----------------------------------------------------------------------------
29 /// Structure for the command argument.
30 struct mglArg
31 {
32 	int type;		///< Type of argument {0-data,1-string,2-number}
33 	mglDataA *d;	///< Pointer to data (used if type==0)
34 	mglString s;	///< String with parameters
35 	mreal v;		///< Numerical value (used if type==2)
36 	dual c;			///< Numerical complex value (used if type==2)
mglArgmglArg37 	mglArg():type(-1),d(0),v(0),c(0.)	{}
38 };
39 //-----------------------------------------------------------------------------
40 /// Structure for MGL command
41 struct mglCommand
42 {
43 	const char *name;	///< Name of command
44 	const char *desc;	///< Short command description (can be NULL)
45 	const char *form;	///< Format of command arguments (can be NULL)
46 	/// Function for executing (plotting)
47 	int (*exec)(mglGraph *gr, long n, mglArg *a, const char *k, const char *opt);
48 	/// Type of command: 0 - special plot, 1 - other plot,
49 	///	2 - setup, 3 - data handle, 4 - data create, 5 - subplot, 6 - program
50 	///	7 - 1d plot, 8 - 2d plot, 9 - 3d plot, 10 - dd plot, 11 - vector plot
51 	///	12 - axis, 13 - primitives, 14 - axis setup, 15 - text/legend, 16 - data transform
52 	int type;
53 };
54 extern mglCommand mgls_prg_cmd[], mgls_dat_cmd[], mgls_grf_cmd[], mgls_set_cmd[], mgls_prm_cmd[], mgls_rnd_cmd[];
55 //-----------------------------------------------------------------------------
56 /// Structure for function name and position.
57 struct mglFunc
58 {
59 	long pos;
60 	int narg;
61 	mglString func;
62 	mglFunc(long p, const wchar_t *f);
mglFuncmglFunc63 	mglFunc(const mglFunc &f):pos(f.pos),narg(f.narg),func(f.func)	{}
mglFuncmglFunc64 	mglFunc():pos(-1),narg(-1)	{}
65 	const mglFunc &operator=(const mglFunc &f)
66 	{	pos=f.pos;	narg=f.narg;	func=f.func;	return f;	}
67 };
68 //-----------------------------------------------------------------------------
69 /// Structure for stack of functions and its arguments.
70 struct mglFnStack
71 {
72 	long pos;	///< position to return
73 	size_t stk;	///< stack at 'call'
74 	mglString par[10];	///< input parameters
mglFnStackmglFnStack75 	mglFnStack():pos(0),stk(0)	{}
76 };
77 //-----------------------------------------------------------------------------
78 /// Structure for stack of if|for|while.
79 #define MGL_ST_TRUE		0	// condition true
80 #define MGL_ST_FALSE	1	// condition false
81 #define MGL_ST_DONE		2	// condition done
82 #define MGL_ST_LOOP		4	// normal loop
83 #define MGL_ST_BREAK	8	// loop break
84 #define MGL_ST_STOP		(MGL_ST_FALSE|MGL_ST_DONE|MGL_ST_BREAK)
85 #define MGL_ST_SKIP		(MGL_ST_FALSE|MGL_ST_DONE)
86 struct mglPosStack
87 {
88 	int pos;	///< position to return
89 	mglData v;	///< data to iterate
90 	long ind;	///< index in data array
91 	int par;	///< for-parameter
92 	unsigned state;	///< state of stack item
93 	mglPosStack(int st=MGL_ST_LOOP):pos(-1),ind(0),par(-1),state(st)	{}
94 };
95 //-----------------------------------------------------------------------------
96 /// Function for asking question in console mode
97 void MGL_EXPORT mgl_ask_gets(const wchar_t *quest, wchar_t *res);
98 //-----------------------------------------------------------------------------
99 /// Structure for the command argument (see mglGraph::Exec()).
100 class mglParser
101 {
102 friend void mgl_export(wchar_t *out, const wchar_t *in, int type);
103 public:
104 #if MGL_HAVE_LTDL
105 	std::vector<lt_dlhandle> DllOpened;	///< Opened external DLL (keep )
106 #endif
107 	std::vector<mglDataA*> DataList;	///< List with data and its names
108 	std::vector<mglNum*> NumList;	///< List with numbers and its names
109 	bool AllowDllCall;	///< Allow calls from external dynamic libraries
110 	bool AllowSetSize;	///< Allow using setsize command
111 	bool AllowFileIO;	///< Allow reading/saving files
112 	volatile bool Stop;	///< Stop command was. Flag prevent further execution
113 	mglCommand *Cmd;	///< Table of MGL commands (can be changed by user). It MUST be sorted by 'name'!!!
114 	long InUse;			///< Smart pointer (number of users)
115 	HMGL curGr;			///< Current grapher
116 	int StarObhID;		///< staring object id
117 
118 	mglParser(bool setsize=false);
119 	virtual ~mglParser();
120 	/// Find the command by the keyword name
121 	const mglCommand *FindCommand(const char *name) const MGL_FUNC_PURE;
122 	const mglCommand *FindCommand(const wchar_t *name) const MGL_FUNC_PURE;
123 	/// Parse and execute the string of MGL script
124 	inline int Parse(HMGL gr, const char *str, long pos=0)
125 	{	mglGraph GR(gr);	return Parse(&GR,str,pos);	}
126 	int Parse(mglGraph *gr, const char *str, long pos=0);
127 	/// Parse and execute the unicode string of MGL script
128 	inline int Parse(HMGL gr, const wchar_t *str, long pos=0)
129 	{	mglGraph GR(gr);	return Parse(&GR,str,pos);	}
130 	int Parse(mglGraph *gr, std::wstring str, long pos=0);
131 	/// Execute MGL script file fname
132 	inline void Execute(HMGL gr, FILE *fp, bool print=false)
133 	{	mglGraph GR(gr);	Execute(&GR,fp,print);	}
134 	void Execute(mglGraph *gr, FILE *fp, bool print=false);
135 	/// Execute MGL script from array of lines
Execute(HMGL gr,int num,const wchar_t ** text)136 	inline void Execute(HMGL gr, int num, const wchar_t **text)
137 	{	mglGraph GR(gr);	Execute(&GR,num,text);	}
138 	void Execute(mglGraph *gr, int num, const wchar_t **text);
139 	/// Execute MGL script text with '\n' separated lines
Execute(HMGL gr,const wchar_t * text)140 	inline void Execute(HMGL gr, const wchar_t *text)
141 	{	mglGraph GR(gr);	Execute(&GR,text);	}
142 	void Execute(mglGraph *gr, const wchar_t *text);
143 	/// Execute MGL script text with '\n' separated lines
Execute(HMGL gr,const char * text)144 	inline void Execute(HMGL gr, const char *text)
145 	{	mglGraph GR(gr);	Execute(&GR,text);	}
146 	void Execute(mglGraph *gr, const char *text);
147 	/// Scan for functions (use NULL for reset)
148 	void ScanFunc(const wchar_t *line);
149 	/// Check if name is function and return its address (or 0 if no)
150 	long IsFunc(const wchar_t *name, int *narg=0);
151 	/// Find variable or return 0 if absent
152 	mglDataA *FindVar(const char *name) MGL_FUNC_PURE;
153 	mglDataA *FindVar(const wchar_t *name) MGL_FUNC_PURE;
154 	/// Find variable or create it if absent
155 	mglDataA *AddVar(const char *name);
156 	mglDataA *AddVar(const wchar_t *name);
157 	/// Find number or return 0 if absent
158 	mglNum *FindNum(const char *name) MGL_FUNC_PURE;
159 	mglNum *FindNum(const wchar_t *name) MGL_FUNC_PURE;
160 	/// Find number or create it if absent
161 	mglNum *AddNum(const char *name);
162 	mglNum *AddNum(const wchar_t *name);
163 	/// Add string for parameter $1, ..., $9
164 	void AddParam(int n, const char *str);
165 	void AddParam(int n, const wchar_t *str);
166 	/// Add new MGL command(s) (last command MUST HAVE name[0]=0 !!!)
167 	void AddCommand(const mglCommand *cmd);
168 	/// Restore Once flag
RestoreOnce()169 	inline void RestoreOnce()	{	Once = true;	}
170 	/// Delete variable by its name
171 	void DeleteVar(const char *name);
172 	void DeleteVar(const wchar_t *name);
173 	/// Delete all data variables
174 	void DeleteAll();
175 	/// Delete temporary data arrays
DeleteTemp()176 	inline void DeleteTemp()
177 	{	for(size_t i=0;i<DataList.size();i++)	if(DataList[i] && DataList[i]->temp)
178 		{	mglDataA *u=DataList[i];	DataList[i]=0;	delete u;	}	}
179 	/// Set variant of argument(s) separated by '?' to be used
180 	inline void SetVariant(int var=0)	{	Variant = var<=0?0:var;	}
181 protected:
182 	static mglCommand *BaseCmd;	///< Base table of MGL commands. It MUST be sorted by 'name'!!!
183 	static void FillBaseCmd();	///< Fill BaseCmd at initialization stage
184 
185 	///< Test if condition is not-valid (n=1) or false (0) or true (1)
TestCond(long m,const mglArg & a0,mglArg & a1,bool & cond)186 	int TestCond(long m, const mglArg &a0, mglArg &a1, bool &cond)
187 	{
188 		int n = 1;
189 		if(a0.type==2)	{	cond = a0.v!=0;	n=0;	}
190 		else if(a0.type==0)
191 		{	n=0;	cond = a0.d->FindAny((m>1 && a1.type==1) ? a1.s.s:"u");	}
192 		return n;
193 	}
194 private:
195 //	long parlen;		///< Length of parameter strings
196 	mglString par[40];	///< Parameter for substituting instead of $1, ..., $9
197 	bool Once;			///< Flag for command which should be executed only once
198 	bool Skip;			///< Flag that commands should be skiped (inside 'once' block)
199 	std::vector<mglPosStack> stack;	///< Stack of if|for|while commands
200 	std::vector<mglFunc> func;	///< function names and position
201 	std::vector<mglFnStack> fn_stack;	///< function calls stack
202 	unsigned Variant;	///< Select variant of argument(s) separated by '?'
203 
204 	/// Parse command
205 	int Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const std::wstring &var, const wchar_t *opt);
206 	/// Fill arguments a from strings
207 	void FillArg(mglGraph *gr, int n, std::wstring *arg, mglArg *a);
208 	/// PreExecute stage -- parse some commands and create variables
209 	int PreExec(mglGraph *gr, long n, std::wstring *arg, mglArg *a);
210 	/// Execute program-flow control commands
211 	int FlowExec(mglGraph *gr, const std::wstring &com, long n, mglArg *a);
212 	/// Parse and execute the unicode string of MGL script
213 	int ParseDat(mglGraph *gr, std::wstring str, mglData &res);
214 	/// Define '$' parameters or start for loop
215 	int ParseDef(std::wstring &str);
216 	/// Parse $N arguments
217 	void PutArg(std::wstring &str, bool def);
218 	/// In skip mode
ifskip()219 	bool inline ifskip()
220 	{	return ( stack.size() && (stack.back().state & MGL_ST_SKIP) );	}
skip()221 	bool inline skip()
222 	{	return (Skip || (stack.size() && (stack.back().state & MGL_ST_STOP) ));	}
223 	bool CheckForName(const std::wstring &s);	// check if name is valid for new data
224 };
225 //-----------------------------------------------------------------------------
226 #endif
227 #endif
228