1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/libraries/libmbutil/parser.h,v 1.52 2017/01/12 14:44:05 masarati Exp $ */
2 /*
3 * MBDyn (C) is a multibody analysis code.
4 * http://www.mbdyn.org
5 *
6 * Copyright (C) 1996-2017
7 *
8 * Pierangelo Masarati <masarati@aero.polimi.it>
9 * Paolo Mantegazza <mantegazza@aero.polimi.it>
10 *
11 * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12 * via La Masa, 34 - 20156 Milano, Italy
13 * http://www.aero.polimi.it
14 *
15 * Changing this copyright notice is forbidden.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation (version 2 of the License).
20 *
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 */
31
32 /* Parser per l'ingresso dati - parte generale */
33
34 /* Si compone di tre diverse strutture di scansione,
35 * piu' le strutture di memorizzazione di stringhe e variabili.
36 *
37 * La prima struttura e' data dal LowParser, che riconosce gli elementi
38 * della sintassi. E' data da:
39 * <statement_list>::=
40 * <statement> ; <statement_list>
41 * epsilon
42 * <statement>::=
43 * <description>
44 * <description> : <arg_list>
45 * <arg_list>::=
46 * <arg>
47 * <arg> , <arg_list>
48 * <arg>::=
49 * <word>
50 * <number>
51 * ecc. ecc.
52 *
53 * La seconda struttura e' data dall'HighParser, che riconosce la sintassi
54 * vera e propria. In alternativa al LowParser, qualora sia atteso un valore
55 * numerico esprimibile mediante un'espressione regolare
56 * (espressione matematica), e' possibile invocare la terza struttura,
57 * il MathParser. Questo analizza espressioni anche complesse e multiple,
58 * se correttamente racchiuse tra parentesi.
59 *
60 * L'HighParser deve necessariamente riconoscere una parola chiave nel campo
61 * <description>, mentre puo' trovare parole qualsiasi nel campo <arg>
62 * qualora sia attesa una stringa.
63 *
64 * Le parole chiave vengono fornite all'HighParser attraverso la KeyTable,
65 * ovvero una lista di parole impaccate (senza spazi). L'uso consigliato e':
66 *
67 * const char sKeyWords[] = { "keyword0",
68 * "keyword1",
69 * "...",
70 * "keywordN"};
71 *
72 * enum KeyWords { KEYWORD0 = 0,
73 * KEYWORD1,
74 * ...,
75 * KEYWORDN,
76 * LASTKEYWORD};
77 *
78 * KeyTable K((int)LASTKEYWORD, sKeyWords);
79 *
80 * Il MathParser usa una tabella di simboli, ovvero nomi (dotati di tipo)
81 * a cui e' associato un valore. La tabella e' esterna e quindi puo' essere
82 * conservata ed utilizzata in seguito conservando in memoria i nomi
83 * definiti in precedenza.
84 *
85 * A questo punto si puo' generare la tabella dei simboli:
86 *
87 * int iSymbolTableInitialSize = 10;
88 * Table T(iSymbolTableInitialSize);
89 *
90 * Quindi si crea il MathParser:
91 *
92 * MathParser Math(T);
93 *
94 * Infine si genera l'HighParser:
95 *
96 * HighParser HP(Math, K, StreamIn);
97 *
98 * dove StreamIn e' l'istream da cui avviene la lettura.
99 */
100
101
102 #ifndef PARSER_H
103 #define PARSER_H
104
105 #include <iostream>
106 #include <fstream>
107 #include <limits>
108 #include <ac/f2c.h>
109
110 #include <string.h>
111 #include <ctype.h>
112
113 #include <cstdlib>
114 #include <unistd.h>
115 #include <typeinfo>
116
117 #include "myassert.h"
118 #include "input.h"
119 #include "mathp.h"
120 #include "matvec3.h"
121 #include "matvec3n.h"
122 #include "matvec6.h"
123 #include "mbsleep.h"
124 #include "ltstrcase.h"
125
126
127 /* Classi dichiarate */
128 class LowParser;
129 class KeyTable;
130 class HighParser;
131
132
133 const unsigned int iDefaultBufSize =
134 #ifdef BUFSIZ
135 BUFSIZ
136 #else /* ! BUFSIZ */
137 8192
138 #endif /* ! BUFSIZ */
139 ;
140
141
142 /* LowParser - begin */
143
144 class LowParser {
145 friend class HighParser;
146
147 public:
148 enum Token {
149 UNKNOWN,
150
151 WORD,
152 COMMA = ',',
153 COLON = ':',
154 SEMICOLON = ';',
155 NUMBER,
156 ENDOFFILE,
157
158 LASTTOKEN
159 };
160
161 private:
162 HighParser& HP;
163 enum Token CurrToken;
164 char *sCurrWordBuf;
165 unsigned iBufSize;
166 doublereal dCurrNumber;
167
168 void PackWords(InputStream& In);
169
170 public:
171 LowParser(HighParser& hp);
172 ~LowParser(void);
173 Token GetToken(InputStream& In);
174 doublereal dGetReal(void) const;
175 integer iGetInt(void) const;
176 char* sGetWord(void);
177 };
178
179 /* LowParser - end */
180
181
182 /* KeyTable - begin */
183
184 class KeyTable {
185 private:
186 char* const* sKeyWords;
187 const KeyTable *oldKey;
188 HighParser& HP;
189
190 public:
191 KeyTable(HighParser& hp, const char* const sTable[]);
192 virtual ~KeyTable(void);
193 int Find(const char* sToFind) const;
194 };
195
196 /* KeyTable - end */
197
198
199 /* DescRead - begin */
200
201 /* prototype of the functional object: reads a description */
202 struct DescRead {
203 public:
204 virtual ~DescRead(void);
205 virtual bool Read(HighParser& HP) = 0;
206 };
207
208 /* description registration function: call to register one */
209 extern bool
210 SetDescData(const std::string &s, DescRead *rf);
211
212 /* function that reads a description */
213 extern bool
214 ReadDescription(HighParser& HP, const std::string& desc);
215
216 /* DescRead - end */
217
218
219 /* HighParser - begin */
220
221 class HighParser {
222 public:
223 class ErrInvalidCallToGetDescription : public MBDynErrBase {
224 public:
ErrInvalidCallToGetDescription(MBDYN_EXCEPT_ARGS_DECL)225 ErrInvalidCallToGetDescription(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
226 };
227 class ErrKeyWordExpected : public MBDynErrBase {
228 public:
ErrKeyWordExpected(MBDYN_EXCEPT_ARGS_DECL)229 ErrKeyWordExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
230 };
231 class ErrSemicolonExpected : public MBDynErrBase {
232 public:
ErrSemicolonExpected(MBDYN_EXCEPT_ARGS_DECL)233 ErrSemicolonExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
234 };
235 class ErrColonExpected : public MBDynErrBase {
236 public:
ErrColonExpected(MBDYN_EXCEPT_ARGS_DECL)237 ErrColonExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
238 };
239 class ErrMissingSeparator : public MBDynErrBase {
240 public:
ErrMissingSeparator(MBDYN_EXCEPT_ARGS_DECL)241 ErrMissingSeparator(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
242 };
243 class ErrIntegerExpected : public MBDynErrBase {
244 public:
ErrIntegerExpected(MBDYN_EXCEPT_ARGS_DECL)245 ErrIntegerExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
246 };
247 class ErrRealExpected : public MBDynErrBase {
248 public:
ErrRealExpected(MBDYN_EXCEPT_ARGS_DECL)249 ErrRealExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
250 };
251 class ErrStringExpected : public MBDynErrBase {
252 public:
ErrStringExpected(MBDYN_EXCEPT_ARGS_DECL)253 ErrStringExpected(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
254 };
255 class ErrIllegalDelimiter : public MBDynErrBase {
256 public:
ErrIllegalDelimiter(MBDYN_EXCEPT_ARGS_DECL)257 ErrIllegalDelimiter(MBDYN_EXCEPT_ARGS_DECL) : MBDynErrBase(MBDYN_EXCEPT_ARGS_PASSTHRU) { NO_OP; };
258 };
259 template <class T>
260 class ErrValueOutOfRange : public MBDynErrBase {
261 protected:
262 T m_value;
263
264 public:
ErrValueOutOfRange(MBDYN_EXCEPT_ARGS_DECL_NOOPT,T value)265 ErrValueOutOfRange(MBDYN_EXCEPT_ARGS_DECL_NOOPT, T value) : MBDynErrBase(MBDYN_EXCEPT_ARGS_NOOPT_PASSTHRU, typeid(T).name()), m_value(value) { NO_OP; };
~ErrValueOutOfRange(void)266 virtual ~ErrValueOutOfRange(void) throw() { NO_OP; };
Get(void)267 T Get(void) const { return m_value; };
268 };
269
270 public:
271 enum Token {
272 UNKNOWN = -1,
273
274 DESCRIPTION,
275 MBDYN_FIRSTARG,
276 ARG,
277 LASTARG,
278 NOARGS,
279 WORD,
280 NUMBER,
281 STRING,
282 ENDOFFILE,
283
284 LASTITEM
285 };
286
287 enum Delims {
288 UNKNOWNDELIM = -1,
289
290 PLAINBRACKETS,
291 SQUAREBRACKETS,
292 CURLYBRACKETS,
293 SINGLEQUOTE,
294 DOUBLEQUOTE,
295 DEFAULTDELIM,
296
297 LASTDELIM
298 };
299
300 const char ESCAPE_CHAR;
301
302 public:
303 struct ErrOut {
304 const char* sFileName;
305 const char* sPathName;
306 unsigned int iLineNumber;
307 };
308
309 struct WordSet {
~WordSetWordSet310 virtual ~WordSet(void) { NO_OP; };
311 virtual bool IsWord(const std::string &s) const = 0;
312 };
313
314 enum {
315 NONE = 0x00U,
316 EATSPACES = 0x01U,
317 ESCAPE = 0x02U,
318 LOWER = 0x04U,
319 UPPER = 0x08U
320 };
321
322 template <class T>
323 struct range_base {
checkrange_base324 virtual bool check(const T& value) const { return false; };
325 };
326
327 template <class T>
328 struct range_any : public range_base<T> {
checkrange_any329 virtual bool check(const T& value) const { return true; };
330 };
331
332 template<class T>
333 struct range_ge : public range_base<T> {
334 T m_lower;
range_gerange_ge335 range_ge(const T& l) : m_lower(l) { NO_OP; };
336
checkrange_ge337 bool check(const T& value) const {
338 return (value >= m_lower);
339 };
340 };
341
342 template<class T>
343 struct range_gt : public range_base<T> {
344 T m_lower;
range_gtrange_gt345 range_gt(const T& l) : m_lower(l) { NO_OP; };
346
checkrange_gt347 bool check(const T& value) const {
348 return (value > m_lower);
349 };
350 };
351
352 template<class T>
353 struct range_le : public range_base<T> {
354 T m_upper;
range_lerange_le355 range_le(const T& u) : m_upper(u) { NO_OP; };
356
checkrange_le357 bool check(const T& value) const {
358 return (value <= m_upper);
359 };
360 };
361
362 template<class T>
363 struct range_lt : public range_base<T> {
364 T m_upper;
range_ltrange_lt365 range_lt(const T& u) : m_upper(u) { NO_OP; };
366
checkrange_lt367 bool check(const T& value) const {
368 return (value < m_upper);
369 };
370 };
371
372 template<class T>
373 struct range_2_base : public range_base<T> {
374 T m_lower, m_upper;
range_2_baserange_2_base375 range_2_base(const T& l, const T& u) : m_lower(l), m_upper(u) { NO_OP; };
376 };
377
378 template<class T>
379 struct range_ge_le : public range_2_base<T> {
range_ge_lerange_ge_le380 range_ge_le(const T& l, const T& u) : range_2_base<T>(l, u) { NO_OP; };
381
checkrange_ge_le382 bool check(const T& value) const {
383 return ((value >= range_2_base<T>::m_lower) && (value <= range_2_base<T>::m_upper));
384 };
385 };
386
387 template<class T>
388 struct range_gt_le : public range_2_base<T> {
range_gt_lerange_gt_le389 range_gt_le(const T& l, const T& u) : range_2_base<T>(l, u) { NO_OP; };
390
checkrange_gt_le391 bool check(const T& value) const {
392 return ((value > range_2_base<T>::m_lower) && (value <= range_2_base<T>::m_upper));
393 };
394 };
395
396 template<class T>
397 struct range_ge_lt : public range_2_base<T> {
range_ge_ltrange_ge_lt398 range_ge_lt(const T& l, const T& u) : range_2_base<T>(l, u) { NO_OP; };
399
checkrange_ge_lt400 bool check(const T& value) const {
401 return ((value >= range_2_base<T>::m_lower) && (value < range_2_base<T>::m_upper));
402 };
403 };
404
405 template<class T>
406 struct range_gt_lt : public range_2_base<T> {
range_gt_ltrange_gt_lt407 range_gt_lt(const T& l, const T& u) : range_2_base<T>(l, u) { NO_OP; };
408
checkrange_gt_lt409 bool check(const T& value) const {
410 return ((value > range_2_base<T>::m_lower) && (value < range_2_base<T>::m_upper));
411 };
412 };
413
414 protected:
415 /* Parser di basso livello, per semplice lettura dei tipi piu' comuni */
416 LowParser LowP;
417
418 /* Stream in ingresso */
419 InputStream* pIn;
420 std::ifstream* pf;
421
422 /* Buffer per le stringhe */
423 char sStringBuf[iDefaultBufSize];
424 char sStringBufWithSpaces[iDefaultBufSize];
425
426 /* Parser delle espressioni matematiche,
427 * usato per acquisire valori sicuramente numerici */
428 MathParser& MathP;
429
430 /* Tabella dei simboli da riconoscere; puo' essere cambiata */
431 const KeyTable* KeyT;
432
433 /* Token di basso ed alto livello */
434 LowParser::Token CurrLowToken;
435 Token CurrToken;
436
437 virtual HighParser::Token FirstToken(void);
438 virtual void NextToken(const char* sFuncName);
439
440 int iGetDescription_int(const char* const s);
441 virtual void Eof(void);
442
443 virtual void
444 SetDelims(enum Delims Del, char &cLdelim, char &cRdelim) const;
445
446 int ParseWord(unsigned flags = HighParser::NONE);
447 void PutbackWord(void);
448
449 public:
450 HighParser(MathParser& MP, InputStream& streamIn);
451 virtual ~HighParser(void);
452 /* Attacca una nuova KeyTable (e ritorna la vecchia) */
453 virtual const KeyTable* PutKeyTable(const KeyTable& KT);
454 /* Numero di linea corrente */
455 virtual int GetLineNumber(void) const;
456 /* Numero di nome file e linea corrente */
457 virtual HighParser::ErrOut GetLineData(void) const;
458 /* Restituisce il math parser */
459 virtual MathParser& GetMathParser(void);
460 /* "Chiude" i flussi */
461 virtual void Close(void);
462 /* verifica se il token successivo e' una description (ambiguo ...) */
463 bool IsDescription(void) const;
464 /* ha appena trovato una description */
465 Token GotDescription(void);
466 /* Legge una parola chiave */
467 int GetDescription(void);
468 /* si attende una descrizione */
469 virtual void ExpectDescription(void);
470 /* si attende una lista di argomenti */
471 virtual void ExpectArg(void);
472 /* 1 se trova la keyword sKeyWord */
473 virtual bool IsKeyWord(const char* sKeyWord);
474 /* numero della keyword trovata */
475 virtual int IsKeyWord(void);
476 /* 1 se e' atteso un argomento */
477 virtual bool IsArg(void);
478 /* 1 se e' atteso un argomento */
479 virtual bool IsStringWithDelims(enum Delims Del = DEFAULTDELIM);
480 /* se l'argomento successivo e' una parola in un WordSet, la ritorna */
481 virtual const char *IsWord(const HighParser::WordSet& ws);
482 /* Se ha letto un ";" lo rimette a posto */
483 virtual void PutBackSemicolon(void);
484 /* legge un booleano con il mathpar */
485 virtual bool GetBool(bool bDefval = false);
486 /* legge un "yes"/"no" */
487 virtual bool GetYesNo(bool& bRet);
488 /* legge un "yes"/"no" o booleano con il mathpar */
489 virtual bool GetYesNoOrBool(bool bDefval = false);
490 /* legge un intero con il mathpar */
491 virtual integer GetInt(integer iDefval = 0);
492 template <class Range>
493 integer GetInt(integer iDefval, Range r);
494 /* legge un reale con il mathpar */
495 virtual doublereal GetReal(const doublereal& dDefval = 0.0);
496 template <class Range>
497 doublereal GetReal(const doublereal& dDefval, Range r);
498 /* legge una string con il mathpar */
499 virtual std::string GetString(const std::string& sDefVal);
500 /* legge un valore tipizzato con il mathpar */
501 virtual TypedValue GetValue(const TypedValue& v);
502 template <class Range>
503 TypedValue GetValue(const TypedValue& v, Range r);
504 /* legge un timeout */
505 virtual mbsleep_t GetTimeout(const mbsleep_t& DefVal);
506 /* legge una keyword */
507 virtual int GetWord(void);
508 /* legge una stringa */
509 virtual const char* GetString(unsigned flags = HighParser::NONE);
510 /* stringa delimitata */
511 virtual const char* GetStringWithDelims(enum Delims Del = DEFAULTDELIM, bool escape = true);
512 };
513
514 /* Le funzioni:
515 * ExpectDescription()
516 * ExpectArg()
517 * informano il parser di cio' che e' atteso; di default il costruttore
518 * setta ExpectDescription().
519 *
520 * Le funzioni:
521 * GetDescription()
522 * IsKeyWord()
523 * GetWord()
524 * restituiscono un intero che corrisponde alla posizione occupata nella
525 * KeyTable dalle parole corrispondenti, oppure -1 se la parola non e'
526 * trovata. Si noti che IsKeyWord(), in caso di esito negativo, ripristina
527 * l'istream. Tutte preparano poi il parser per la lettura successiva.
528 *
529 * La funzione
530 * IsKeyWord(const char*)
531 * restituisce 0 se non trova la parola e ripristina l'istream, altrimenti
532 * restituisce 1 e prepara il parser alla lettura successiva.
533 *
534 * Le funzioni
535 * GetInt(),
536 * GetReal(),
537 * GetString(),
538 * GetStringWithDelims(enum Delims)
539 * restituiscono i valori attesi e preparano il prser alla lettura successiva.
540 */
541
542 /* HighParser - end */
543
544 extern std::ostream&
545 operator << (std::ostream& out, const HighParser::ErrOut& err);
546
547 extern HighParser::ErrOut
548 mbdyn_get_line_data(void);
549
550 extern std::ostream&
551 mbdyn_print_line_data(std::ostream& out);
552
553 template <class Range>
554 integer
GetInt(int iDefVal,Range range)555 HighParser::GetInt(int iDefVal, Range range)
556 {
557 TypedValue v(iDefVal);
558 v = GetValue(v);
559 integer val = v.GetInt();
560 if (!range.check(val)) {
561 throw ErrValueOutOfRange<integer>(MBDYN_EXCEPT_ARGS, val);
562 }
563 return val;
564 }
565
566
567 template <class Range>
568 doublereal
GetReal(const doublereal & dDefVal,Range range)569 HighParser::GetReal(const doublereal& dDefVal, Range range)
570 {
571 TypedValue v(dDefVal);
572 v = GetValue(v);
573 doublereal val = v.GetReal();
574 if (!range.check(val)) {
575 throw ErrValueOutOfRange<doublereal>(MBDYN_EXCEPT_ARGS, val);
576 }
577 return val;
578 }
579
580 template <class Range>
581 TypedValue
GetValue(const TypedValue & vDefVal,Range range)582 HighParser::GetValue(const TypedValue& vDefVal, Range range)
583 {
584 const char sFuncName[] = "HighParser::GetValue()";
585
586 if (CurrToken != HighParser::ARG) {
587 silent_cerr("Parser error in " << sFuncName << ", arg expected at line "
588 << GetLineData() << std::endl);
589 throw HighParser::ErrIntegerExpected(MBDYN_EXCEPT_ARGS);
590 }
591
592 TypedValue v(vDefVal);
593
594 try {
595 v = MathP.Get(*pIn, v);
596 }
597 catch (TypedValue::ErrWrongType& e) {
598 silent_cerr(sFuncName << ": " << e.what() << " at line "
599 << GetLineData() << std::endl);
600 throw e;
601 }
602 catch (MathParser::ErrGeneric& e) {
603 silent_cerr(sFuncName << ": error return from MathParser at line "
604 << GetLineData() << std::endl);
605 throw e;
606 }
607 catch (...) {
608 throw;
609 }
610
611 NextToken(sFuncName);
612
613 if (!range.check(v)) {
614 throw ErrValueOutOfRange<TypedValue>(MBDYN_EXCEPT_ARGS, v);
615 }
616
617 return v;
618 }
619
620 #endif /* PARSER_H */
621
622