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