1 #ifndef CORELIB___EXPR__HPP
2 #define CORELIB___EXPR__HPP
3
4
5 /* $Id: expr.hpp 574926 2018-11-20 20:23:54Z ucko $
6 * ===========================================================================
7 *
8 * PUBLIC DOMAIN NOTICE
9 * National Center for Biotechnology Information
10 *
11 * This software/database is a "United States Government Work" under the
12 * terms of the United States Copyright Act. It was written as part of
13 * the author's official duties as a United States Government employee and
14 * thus cannot be copyrighted. This software/database is freely available
15 * to the public for use. The National Library of Medicine and the U.S.
16 * Government have not placed any restriction on its use or reproduction.
17 *
18 * Although all reasonable efforts have been taken to ensure the accuracy
19 * and reliability of the software and data, the NLM and the U.S.
20 * Government do not and cannot warrant the performance or results that
21 * may be obtained by using this software or data. The NLM and the U.S.
22 * Government disclaim all warranties, express or implied, including
23 * warranties of performance, merchantability or fitness for any particular
24 * purpose.
25 *
26 * Please cite the author in any work or product based on this material.
27 *
28 * ===========================================================================
29 *
30 * Author: Sergey Sikorskiy, Mikhail Zakharov
31 *
32 * File Description:
33 * Expression parsing and evaluation.
34 *
35 * ===========================================================================
36 */
37
38 #include <corelib/ncbistd.hpp>
39
40 BEGIN_NCBI_SCOPE
41
42
43
44 ////////////////////////////////////////////////////////////////////////////////
45 class CExprSymbol;
46
47 class NCBI_XNCBI_EXPORT CExprValue
48 {
49 public:
50 CExprValue(void);
CExprValue(VT * value)51 template <typename VT> CExprValue(VT* value)
52 {
53 // If you got here, you are using wrong data type.
54 value->please_use_Int8_double_bool_instead();
55 }
56 CExprValue(Uint4 value);
57 CExprValue(Int4 value);
58 CExprValue(Uint8 value);
59 CExprValue(Int8 value);
60 CExprValue(double value);
61 CExprValue(bool value);
62 CExprValue(string value);
63 CExprValue(const CExprValue& value);
64
65 public:
66 /// Value type.
67 enum EValue {
68 eINT,
69 eFLOAT,
70 eBOOL,
71 eSTRING
72 };
73
74 public:
GetType(void) const75 EValue GetType(void) const
76 {
77 return m_Tag;
78 }
SetType(EValue type)79 void SetType(EValue type)
80 {
81 m_Tag = type;
82 }
83
GetString(void) const84 string GetString(void) const
85 {
86 string str;
87
88 switch (m_Tag) {
89 case eINT:
90 NStr::NumericToString(str, ival);
91 return str;
92 case eBOOL:
93 return bval ? "true" : "false";
94 case eSTRING:
95 return m_sval;
96 default:
97 break;
98 }
99
100 return NStr::DoubleToString(fval);
101 }
102
GetDouble(void) const103 double GetDouble(void) const
104 {
105 switch (m_Tag) {
106 case eINT:
107 return static_cast<double>(ival);
108 case eBOOL:
109 return bval ? 1.0 : 0.0;
110 case eSTRING:
111 return 0;
112 default:
113 break;
114 }
115
116 return fval;
117 }
118
GetInt(void) const119 Int8 GetInt(void) const
120 {
121 switch (m_Tag) {
122 case eFLOAT:
123 return static_cast<Int8>(fval);
124 case eBOOL:
125 return bval ? 1 : 0;
126 case eSTRING:
127 return 0;
128 default:
129 break;
130 }
131
132 return ival;
133 }
134
GetBool(void) const135 bool GetBool(void) const
136 {
137 switch (m_Tag) {
138 case eINT:
139 return ival != 0;
140 case eFLOAT:
141 return fval != 0.0;
142 case eSTRING:
143 return false;
144 default:
145 break;
146 }
147
148 return bval;
149 }
150
151 public:
152 union {
153 Int8 ival;
154 double fval;
155 bool bval;
156 };
157 string m_sval;
158
159 CExprSymbol* m_Var;
160 int m_Pos;
161
162 private:
163 EValue m_Tag;
164 };
165
166 ////////////////////////////////////////////////////////////////////////////////
167 class NCBI_XNCBI_EXPORT CExprSymbol
168 {
169 public:
170 typedef Int8 (*FIntFunc1) (Int8);
171 typedef Int8 (*FIntFunc2) (Int8,Int8);
172 typedef double (*FFloatFunc1) (double);
173 typedef double (*FFloatFunc2) (double, double);
174 typedef bool (*FBoolFunc1) (bool);
175 typedef bool (*FBoolFunc2) (bool, bool);
176 typedef bool (*FStringFunc1) (const string&);
177
178 CExprSymbol(void);
CExprSymbol(const char * name,VT * value)179 template <typename VT> CExprSymbol(const char* name, VT* value)
180 {
181 // If you got here, you are using wrong data type.
182 value->please_use_Int8_double_bool_instead();
183 }
184 CExprSymbol(const char* name, Uint4 value);
185 CExprSymbol(const char* name, Int4 value);
186 CExprSymbol(const char* name, Uint8 value);
187 CExprSymbol(const char* name, Int8 value);
188 CExprSymbol(const char* name, bool value);
189 CExprSymbol(const char* name, double value);
190 CExprSymbol(const char* name, string value);
191 CExprSymbol(const char* name, FIntFunc1 value);
192 CExprSymbol(const char* name, FIntFunc2 value);
193 CExprSymbol(const char* name, FFloatFunc1 value);
194 CExprSymbol(const char* name, FFloatFunc2 value);
195 CExprSymbol(const char* name, FBoolFunc1 value);
196 CExprSymbol(const char* name, FBoolFunc2 value);
197 CExprSymbol(const char* name, FStringFunc1 value);
198
199 ~CExprSymbol(void);
200
201
202 public:
203 enum ESymbol {
204 eVARIABLE,
205 eIFUNC1,
206 eIFUNC2,
207 eFFUNC1,
208 eFFUNC2,
209 eBFUNC1,
210 eBFUNC2,
211 eSFUNC1
212 };
213
214 public:
215 ESymbol m_Tag;
216 union {
217 FIntFunc1 m_IntFunc1;
218 FIntFunc2 m_IntFunc2;
219 FFloatFunc1 m_FloatFunc1;
220 FFloatFunc2 m_FloatFunc2;
221 FBoolFunc1 m_BoolFunc1;
222 FBoolFunc2 m_BoolFunc2;
223 FStringFunc1 m_StringFunc1;
224 };
225 CExprValue m_Val;
226 string m_Name;
227 CExprSymbol* m_Next;
228 };
229
230 ////////////////////////////////////////////////////////////////////////////////
231 class NCBI_XNCBI_EXPORT CExprParserException : EXCEPTION_VIRTUAL_BASE public CException
232 {
233 public:
234 enum EErrCode {
235 eParseError,
236 eTypeConversionError
237 };
238
239
240 CExprParserException(
241 const CDiagCompileInfo& info,
242 const CException* prev_exception, EErrCode err_code,
243 const string& message, int pos,
244 EDiagSev severity = eDiag_Error)
245 : CException(info, prev_exception, message, severity)
246 , m_Pos(pos)
247 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(CExprParserException, CException);
248
249 virtual const char* GetErrCodeString(void) const override;
250
251 virtual void ReportExtra(ostream& out) const override;
252
253 public:
GetPos(void) const254 int GetPos(void) const
255 {
256 return m_Pos;
257 }
258
259 protected:
260 virtual void x_Assign(const CException& src) override;
261
262 private:
263 int m_Pos;
264 };
265
266 ////////////////////////////////////////////////////////////////////////////////
267 class NCBI_XNCBI_EXPORT CExprParser
268 {
269 public:
270 /// Parser flags
271 enum EAutoVar {
272 fAllowAutoVar = 0, //< create variables without previous declaration
273 fDenyAutoVar = (1 << 0), //< call AddSymbol() to register a variable
274 fLogicalOnly = (1 << 1), //< '/','.','[0-9]' is interpreted as a part of a symbol (to allow directories)
275
276 // Legacy
277 eAllowAutoVar = fAllowAutoVar,
278 eDenyAutoVar = fDenyAutoVar
279 };
280
281 typedef int TParserFlags;
282
283 CExprParser(TParserFlags auto_var = 0);
284 ~CExprParser(void);
285
286 public:
287 void Parse(const char* str);
288
GetResult(void) const289 const CExprValue& GetResult(void) const
290 {
291 if (m_v_sp != 1) {
292 ReportError("Result is not available");
293 }
294
295 return m_VStack[0];
296 }
297
298 template <typename VT>
299 CExprSymbol* AddSymbol(const char* name, VT value);
300
301 private:
302 enum EOperator {
303 eBEGIN, eOPERAND, eERROR, eEND,
304 eLPAR, eRPAR, eFUNC, ePOSTINC, ePOSTDEC,
305 ePREINC, ePREDEC, ePLUS, eMINUS, eNOT, eCOM,
306 ePOW,
307 eMUL, eDIV, eMOD,
308 eADD, eSUB,
309 eASL, eASR, eLSR,
310 eGT, eGE, eLT, eLE,
311 eEQ, eNE,
312 eAND,
313 eXOR,
314 eOR,
315 eSET, eSETADD, eSETSUB, eSETMUL, eSETDIV, eSETMOD, eSETASL, eSETASR, eSETLSR,
316 eSETAND, eSETXOR, eSETOR, eSETPOW,
317 eCOMMA,
318 eTERMINALS
319 };
320
321 private:
322 EOperator Scan(bool operand);
323 bool Assign(void);
324 CExprSymbol* GetSymbol(const char* name) const;
325
ReportError(int pos,const string & msg)326 static void ReportError(int pos, const string& msg)
327 {
328 NCBI_THROW2(CExprParserException, eParseError, msg, pos);
329 }
ReportError(const string & msg) const330 void ReportError(const string& msg) const { ReportError(m_Pos - 1, msg); }
331
332 EOperator IfChar(
333 char c, EOperator val,
334 EOperator val_def);
335 EOperator IfElseChar(
336 char c1, EOperator val1,
337 char c2, EOperator val2,
338 EOperator val_def);
339 EOperator IfLongest2ElseChar(
340 char c1, char c2,
341 EOperator val_true_longest,
342 EOperator val_true,
343 EOperator val_false,
344 EOperator val_def);
345
AutoCreateVariable(void) const346 TParserFlags AutoCreateVariable(void) const
347 {
348 return m_ParserFlags & fDenyAutoVar;
349 }
350
LogicalOnly(void) const351 bool LogicalOnly(void) const { return (m_ParserFlags & fLogicalOnly) != 0;}
352
353 private:
354 enum {hash_table_size = 1013};
355 CExprSymbol* hash_table[hash_table_size];
356
357 enum {max_stack_size = 256};
358 enum {max_expression_length = 1024};
359
360 static int sm_lpr[eTERMINALS];
361 static int sm_rpr[eTERMINALS];
362
363 CExprValue m_VStack[max_stack_size];
364 int m_v_sp;
365 EOperator m_OStack[max_stack_size];
366 int m_o_sp;
367 const char* m_Buf;
368 int m_Pos;
369 int m_TmpVarCount;
370 TParserFlags m_ParserFlags;
371 };
372
373
374 ////////////////////////////////////////////////////////////////////////////////
375 // Inline methods.
376 //
377
378 NCBI_XNCBI_EXPORT
379 unsigned string_hash_function(const char* p);
380
381 template <typename VT>
382 inline
AddSymbol(const char * name,VT value)383 CExprSymbol* CExprParser::AddSymbol(const char* name, VT value)
384 {
385 CExprSymbol* sp = GetSymbol(name);
386
387 if (!sp) {
388 // Add ...
389 sp = new CExprSymbol(name, value);
390
391 unsigned h = string_hash_function(name) % hash_table_size;
392 sp->m_Next = hash_table[h];
393 hash_table[h] = sp;
394 }
395
396 return sp;
397 }
398
399 inline
400 CExprParser::EOperator
IfChar(char c,EOperator val,EOperator val_def)401 CExprParser::IfChar(
402 char c, EOperator val,
403 EOperator val_def)
404 {
405 if (m_Buf[m_Pos] == c) {
406 m_Pos += 1;
407 return val;
408 }
409
410 return val_def;
411 }
412
413 inline
414 CExprParser::EOperator
IfElseChar(char c1,EOperator val1,char c2,EOperator val2,EOperator val_def)415 CExprParser::IfElseChar(
416 char c1, EOperator val1,
417 char c2, EOperator val2,
418 EOperator val_def)
419 {
420 if (m_Buf[m_Pos] == c1) {
421 m_Pos += 1;
422 return val1;
423 } else if (m_Buf[m_Pos] == c2) {
424 m_Pos += 1;
425 return val2;
426 }
427
428 return val_def;
429 }
430
431 inline
432 CExprParser::EOperator
IfLongest2ElseChar(char c1,char c2,EOperator val_true_longest,EOperator val_true,EOperator val_false,EOperator val_def)433 CExprParser::IfLongest2ElseChar(
434 char c1, char c2,
435 EOperator val_true_longest,
436 EOperator val_true,
437 EOperator val_false,
438 EOperator val_def)
439 {
440 if (m_Buf[m_Pos] == c1) {
441 m_Pos += 1;
442 return IfChar(c2, val_true_longest, val_true);
443 } else if (m_Buf[m_Pos] == c2) {
444 m_Pos += 1;
445 return val_false;
446 }
447
448 return val_def;
449 }
450
451 END_NCBI_SCOPE
452
453 #endif /* CORELIB___EXPR__HPP */
454
455