1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/libraries/libmbutil/parser.cc,v 1.90 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 */
33
34 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
35
36 #include <cstring>
37 #include <stdlib.h>
38 #include <stack>
39 #include <map>
40
41 #include "mathtyp.h"
42 #include "parser.h"
43 #include "filename.h"
44 #include "Rot.hh"
45
46 /* LowParser - begin */
47
48 static int
skip_remarks(HighParser & HP,InputStream & In,char & cIn)49 skip_remarks(HighParser& HP, InputStream& In, char &cIn)
50 {
51 skip_again:;
52 for (cIn = In.get(); isspace(cIn); cIn = In.get()) {
53 // this is here in case in some implementation isspace returns success for EOF
54 if (In.eof()) {
55 return -1;
56 }
57 }
58
59 if (In.eof()) {
60 return -1;
61 }
62
63 switch (cIn) {
64 case -1: // should be EOF!
65 return -1;
66
67 case MathParser::ONE_LINE_REMARK:
68 for (cIn = In.get(); cIn != '\n'; cIn = In.get()) {
69 if (cIn == '\\') {
70 cIn = In.get();
71 if (In.eof()) {
72 return -1;
73 }
74 if (cIn == '\r') {
75 /* if input file was prepared
76 * under DOS/Windows */
77 cIn = In.get();
78 if (In.eof()) {
79 return -1;
80 }
81 }
82 }
83 if (In.eof()) {
84 return -1;
85 }
86 }
87 goto skip_again;
88
89 case '/':
90 cIn = In.get();
91 if (In.eof()) {
92 return -1;
93
94 } else if (cIn == '*') {
95 for (cIn = In.get(); !In.eof(); cIn = In.get()) {
96 if (cIn == '*') {
97 end_of_comment:;
98 cIn = In.get();
99 if (In.eof()) {
100 return -1;
101 }
102 if (cIn == '/') {
103 goto skip_again;
104 }
105
106 } else if (cIn == '/') {
107 cIn = In.get();
108 if (In.eof()) {
109 return -1;
110 }
111 if (cIn == '*') {
112 silent_cerr("warning: '/*' inside a comment "
113 "at line " << HP.GetLineData()
114 << std::endl);
115 goto end_of_comment;
116 }
117 }
118 }
119 if (In.eof()) {
120 return -1;
121 }
122
123 } else {
124 In.putback(cIn);
125 return 0;
126 }
127 }
128
129 return 0;
130 }
131
LowParser(HighParser & hp)132 LowParser::LowParser(HighParser& hp)
133 : HP(hp), sCurrWordBuf(0), iBufSize(iDefaultBufSize)
134 {
135 SAFENEWARR(sCurrWordBuf, char, iBufSize);
136 }
137
~LowParser(void)138 LowParser::~LowParser(void)
139 {
140 if (sCurrWordBuf) {
141 SAFEDELETEARR(sCurrWordBuf);
142 }
143 }
144
145 void
PackWords(InputStream & In)146 LowParser::PackWords(InputStream& In)
147 {
148 unsigned iCur = 0;
149 char cIn;
150
151 /* note: no remarks allowed inside words */
152 for (cIn = In.get(); !In.eof(); cIn = In.get()) {
153 switch (cIn) {
154 case COLON:
155 case COMMA:
156 case SEMICOLON:
157 goto end_of_word;
158
159 default:
160 if (!isspace(cIn)) {
161 sCurrWordBuf[iCur] = cIn;
162 iCur++;
163 if (iCur == iBufSize - 1) {
164 char *s = NULL;
165 unsigned i = 2*iBufSize;
166
167 /* FIXME: no limit on max size? */
168
169 SAFENEWARR(s, char, i);
170 memcpy(s, sCurrWordBuf, iBufSize);
171 SAFEDELETEARR(sCurrWordBuf);
172 sCurrWordBuf = s;
173 iBufSize = i;
174 }
175 }
176 }
177 }
178
179 throw EndOfFile(MBDYN_EXCEPT_ARGS);
180
181 end_of_word:;
182
183 sCurrWordBuf[iCur] = '\0';
184 In.putback(cIn);
185 }
186
187
188 LowParser::Token
GetToken(InputStream & In)189 LowParser::GetToken(InputStream& In)
190 {
191 /* toglie gli spazi iniziali e tutti i commenti */
192 char cIn;
193 if (skip_remarks(HP, In, cIn)) {
194 return CurrToken = LowParser::ENDOFFILE;
195 }
196
197 if (isalpha(cIn) || cIn == '_') {
198 PackWords(In.putback(cIn));
199 return CurrToken = LowParser::WORD;
200 }
201
202 switch (cIn) {
203 case ',':
204 return CurrToken = LowParser::COMMA;
205
206 case ':':
207 return CurrToken = LowParser::COLON;
208
209 case ';':
210 return CurrToken = LowParser::SEMICOLON;
211
212 case '.':
213 case '-':
214 case '+':
215 is_digit:;
216 In.putback(cIn) >> dCurrNumber;
217 return CurrToken = LowParser::NUMBER;
218
219 default:
220 if (isdigit(cIn)) {
221 goto is_digit;
222 }
223 In.putback(cIn);
224 return CurrToken = LowParser::UNKNOWN;
225 }
226 }
227
228
229 doublereal
dGetReal(void) const230 LowParser::dGetReal(void) const
231 {
232 return dCurrNumber;
233 }
234
235
236 integer
iGetInt(void) const237 LowParser::iGetInt(void) const
238 {
239 return integer(dCurrNumber);
240 }
241
242
243 char*
sGetWord(void)244 LowParser::sGetWord(void)
245 {
246 return sCurrWordBuf;
247 }
248
249 /* LowParser - end */
250
251
252 /* KeyTable - begin */
253
KeyTable(HighParser & hp,const char * const sTable[])254 KeyTable::KeyTable(HighParser& hp, const char* const sTable[])
255 : sKeyWords(0), oldKey(0), HP(hp)
256 {
257 sKeyWords = (char* const*)sTable;
258 oldKey = HP.PutKeyTable(*this);
259 }
260
261
~KeyTable(void)262 KeyTable::~KeyTable(void)
263 {
264 if (oldKey) {
265 (void)HP.PutKeyTable(*oldKey);
266 }
267 }
268
269
270 int
Find(const char * sToFind) const271 KeyTable::Find(const char* sToFind) const
272 {
273 for (int iCnt = 0; sKeyWords[iCnt]; iCnt++) {
274 if (strcasecmp(sKeyWords[iCnt], sToFind) == 0) {
275 return iCnt;
276 }
277 }
278
279 return -1;
280 }
281
282 /* KeyTable - end */
283
284
285 /* DescRead - begin */
286
287 /* bag that contains functions to parse descriptions */
288
289 typedef std::map<std::string, DescRead *, ltstrcase> DescFuncMapType;
290 static DescFuncMapType DescFuncMap;
291
292 struct DescWordSetType : public HighParser::WordSet {
IsWordDescWordSetType293 bool IsWord(const std::string& s) const {
294 return DescFuncMap.find(s) != DescFuncMap.end();
295 };
296 };
297
298 static DescWordSetType DescWordSet;
299
300 bool
SetDescData(const std::string & name,DescRead * rf)301 SetDescData(const std::string& name, DescRead *rf)
302 {
303 pedantic_cout("registering description \"" << name << "\"" << std::endl);
304 return DescFuncMap.insert(DescFuncMapType::value_type(name, rf)).second;
305 }
306
307 /* Reads descriptions */
308
309 bool
ReadDescription(HighParser & HP,const std::string & desc)310 ReadDescription(HighParser& HP, const std::string& desc)
311 {
312 DEBUGCOUTFNAME("ReadDescription()");
313
314 bool bRC(false);
315 DescFuncMapType::iterator func = DescFuncMap.find(desc);
316 if (func != DescFuncMap.end()) {
317 HP.GotDescription();
318 if (!HP.IsArg() && !HP.IsDescription()) {
319 silent_cerr("Parser error in ReadDescription(),"
320 " colon or semicolon expected after description at line "
321 << HP.GetLineData() << std::endl);
322 throw HighParser::ErrColonExpected(MBDYN_EXCEPT_ARGS);
323 }
324
325 bRC = func->second->Read(HP);
326
327 if (HP.IsArg()) {
328 silent_cerr("semicolon expected at line " << HP.GetLineData() << std::endl);
329 throw HighParser::ErrSemicolonExpected(MBDYN_EXCEPT_ARGS);
330 }
331 }
332
333 return bRC;
334 }
335
~DescRead(void)336 DescRead::~DescRead(void)
337 {
338 NO_OP;
339 }
340
341 struct RemarkDR : public DescRead {
342 public:
343 bool Read(HighParser& HP);
344 };
345
346 bool
Read(HighParser & HP)347 RemarkDR::Read(HighParser& HP)
348 {
349 silent_cout("line " << HP.GetLineData());
350
351 char prefix = ':';
352 while (HP.IsArg()) {
353 TypedValue v;
354 v = HP.GetValue(v);
355 silent_cout(prefix << ' ' << v);
356
357 if (prefix == ':') {
358 prefix = ',';
359 }
360 }
361
362 silent_cout(std::endl);
363
364 return true;
365 }
366
367 struct PrintSymbolTableDR : public DescRead {
368 public:
369 bool Read(HighParser& HP);
370 };
371
372 bool
Read(HighParser & HP)373 PrintSymbolTableDR::Read(HighParser& HP)
374 {
375 if (!HP.IsArg()) {
376 silent_cout( "math parser symbol table at line "
377 << HP.GetLineData() << ":" << std::endl
378 << HP.GetMathParser().GetSymbolTable() << std::endl);
379 return true;
380 }
381
382 if (HP.IsKeyWord("all")) {
383 const MathParser::NameSpaceMap& ns = HP.GetMathParser().GetNameSpaceMap();
384 for (MathParser::NameSpaceMap::const_iterator i = ns.begin(); i != ns.end(); ++i) {
385 const std::string& sName = i->second->sGetName();
386 const Table *pT = i->second->GetTable();
387 if (pT != 0) {
388 silent_cout( "namespace \"" << sName << "\" symbol table at line "
389 << HP.GetLineData() << ":" << std::endl
390 << *pT << std::endl);
391 }
392 }
393
394 return true;
395 }
396
397 while (HP.IsArg()) {
398 const char *sName = HP.GetString();
399 MathParser::NameSpace *pN = HP.GetMathParser().GetNameSpace(sName);
400 if (pN == 0) {
401 silent_cerr("PrintSymbolTableDR::Read(): warning, unable to find namespace \"" << sName << "\" at line "
402 << HP.GetLineData() << std::endl);
403
404 } else {
405 Table *pT = pN->GetTable();
406 if (pT == 0) {
407 silent_cerr("PrintSymbolTableDR::Read(): warning, namespace \"" << sName << "\" "
408 "has no symbol table at line " << HP.GetLineData() << std::endl);
409
410 } else {
411 silent_cout( "namespace \"" << sName << "\" symbol table at line "
412 << HP.GetLineData() << ":" << std::endl
413 << *pT << std::endl);
414 }
415 }
416 }
417
418 return true;
419 }
420
421 struct SetDR : public DescRead {
422 public:
423 bool Read(HighParser& HP);
424 };
425
426 bool
Read(HighParser & HP)427 SetDR::Read(HighParser& HP)
428 {
429 if (!HP.IsArg()) {
430 silent_cerr("Parser error in SetDR::Read(), "
431 "arg expected at line "
432 << HP.GetLineData() << std::endl);
433 throw HighParser::ErrColonExpected(MBDYN_EXCEPT_ARGS);
434 }
435
436 TypedValue v;
437 HP.GetValue(v);
438
439 return true;
440 }
441
442 struct SetEnvDR : public DescRead {
443 public:
444 bool Read(HighParser& HP);
445 };
446
447 bool
Read(HighParser & HP)448 SetEnvDR::Read(HighParser& HP)
449 {
450 #ifdef HAVE_SETENV
451 if (!HP.IsArg()) {
452 silent_cerr("Parser error in SetEnvDR::Read(), "
453 "arg(s) expected at line "
454 << HP.GetLineData() << std::endl);
455 throw HighParser::ErrColonExpected(MBDYN_EXCEPT_ARGS);
456 }
457
458 int overwrite = 0;
459 if (HP.IsKeyWord("overwrite")) {
460 bool b = HP.GetYesNoOrBool();
461 overwrite = b ? 1 : 0;
462 }
463
464 const char *ava = HP.GetStringWithDelims();
465 if (ava == NULL) {
466 silent_cerr("unable to get AVA for \"setenv\" at line "
467 << HP.GetLineData() << std::endl);
468 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
469 }
470
471 char *avasep = std::strchr(const_cast<char *>(ava), '=');
472 if (avasep == NULL) {
473 #ifdef HAVE_UNSETENV
474 unsetenv(ava);
475 #elif defined(HAVE_PUTENV)
476 if (putenv(ava)) {
477 silent_cerr("unable to unset the environment variable "
478 "\"" << ava << "\" at line "
479 << HP.GetLineData() << std::endl);
480 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
481 }
482 #endif /* !HAVE_UNSETENV && !HAVE_PUTENV */
483
484 } else {
485 if (avasep == ava) {
486 silent_cerr("illegal AVA \"" << ava
487 << "\" at line "
488 << HP.GetLineData() << std::endl);
489 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
490 }
491
492 avasep[0] = '\0';
493 avasep++;
494 bool bPresent(getenv(ava) != NULL);
495 int rc = setenv(ava, avasep, overwrite);
496 if (rc) {
497 silent_cerr("unable to set the environment variable \""
498 << ava << "\" to \"" << avasep
499 << "\" at line " << HP.GetLineData()
500 << std::endl);
501 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
502 }
503
504 if (bPresent && overwrite == 0) {
505 silent_cout("Environment variable \"" << ava
506 << "\" _not_ overwritten with \"" << avasep
507 << "\" (current value is \"" << getenv(ava)
508 << "\") at line " << HP.GetLineData()
509 << std::endl);
510
511 } else if (!bPresent) {
512 silent_cout("Environment variable \"" << ava
513 << "\" set to \"" << avasep
514 << "\" at line " << HP.GetLineData()
515 << std::endl);
516
517 } else {
518 silent_cout("Environment variable \"" << ava
519 << "\" overwritten to \"" << avasep
520 << "\" at line " << HP.GetLineData()
521 << std::endl);
522 }
523 }
524 #else // ! HAVE_SETENV
525 silent_cerr("SetEnvDR::Read(): warning, setenv() not available; ignored at line "
526 << HP.GetLineData() << std::endl);
527 #endif // !HAVE_SETENV
528 return true;
529 }
530
531 struct ExitDR : public DescRead {
532 public:
533 bool Read(HighParser& HP);
534 };
535
536 bool
Read(HighParser & HP)537 ExitDR::Read(HighParser& HP)
538 {
539 if (!HP.IsDescription()) {
540 silent_cerr("Parser error in ExitDR::Read(),"
541 " semicolon expected at line "
542 << HP.GetLineData() << std::endl);
543 throw HighParser::ErrSemicolonExpected(MBDYN_EXCEPT_ARGS);
544 }
545
546 /* exits with no error */
547 throw NoErr(MBDYN_EXCEPT_ARGS);
548 }
549
550 static unsigned desc_done;
551
552 static void
InitDescData(void)553 InitDescData(void)
554 {
555 if (::desc_done++ > 0) {
556 return;
557 }
558
559 SetDescData("remark", new RemarkDR);
560 SetDescData("print" "symbol" "table", new PrintSymbolTableDR);
561 SetDescData("set", new SetDR);
562 SetDescData("setenv", new SetEnvDR);
563 SetDescData("exit", new ExitDR);
564
565 /* NOTE: add here initialization of new built-in descriptions;
566 * alternative ways to register new custom descriptions are:
567 * - call SetDescData() from anywhere in the code
568 * - write a module that calls SetDescData() from inside a function
569 * called module_init(), and run-time load it using "module load"
570 * in the input file.
571 */
572 }
573
574 static void
DestroyDescData(void)575 DestroyDescData(void)
576 {
577 if (::desc_done == 0) {
578 silent_cerr("DestroyDescData() called once too many" << std::endl);
579 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
580 }
581
582 if (--::desc_done > 0) {
583 return;
584 }
585
586 /* free stuff */
587 for (DescFuncMapType::iterator i = DescFuncMap.begin(); i != DescFuncMap.end(); ++i) {
588 delete i->second;
589 }
590 DescFuncMap.clear();
591 }
592
593 /* DescRead - end */
594
595
596 /* HighParser - begin */
597
598 static std::stack<const HighParser *> pHP;
599
600 static const HighParser::ErrOut unknownErr = { "(unknown)", "(unknown)", 0 };
601
602 HighParser::ErrOut
mbdyn_get_line_data(void)603 mbdyn_get_line_data(void)
604 {
605 if (!pHP.empty()) {
606 return pHP.top()->GetLineData();
607 }
608
609 return unknownErr;
610 }
611
612 std::ostream&
mbdyn_print_line_data(std::ostream & out)613 mbdyn_print_line_data(std::ostream& out)
614 {
615 if (!pHP.empty()) {
616 out << pHP.top()->GetLineData();
617 }
618
619 return out;
620 }
621
HighParser(MathParser & MP,InputStream & streamIn)622 HighParser::HighParser(MathParser& MP, InputStream& streamIn)
623 : ESCAPE_CHAR('\\'),
624 LowP(*this),
625 pIn(&streamIn),
626 pf(NULL),
627 MathP(MP),
628 KeyT(0)
629 {
630 DEBUGCOUTFNAME("HighParser::HighParser");
631 CurrToken = HighParser::DESCRIPTION;
632
633 InitDescData();
634
635 pHP.push(this);
636 }
637
638
~HighParser(void)639 HighParser::~HighParser(void)
640 {
641 DEBUGCOUTFNAME("HighParser::~HighParser");
642 Close();
643 ASSERT(pHP.top() == this);
644 pHP.pop();
645
646 DestroyDescData();
647 }
648
649
650 void
Close(void)651 HighParser::Close(void)
652 {
653 NO_OP;
654 }
655
656
657 const KeyTable*
PutKeyTable(const KeyTable & KT)658 HighParser::PutKeyTable(const KeyTable& KT)
659 {
660 const KeyTable* oldKey = KeyT;
661
662 KeyT = &KT;
663
664 return oldKey;
665 }
666
667 MathParser&
GetMathParser(void)668 HighParser::GetMathParser(void)
669 {
670 return MathP;
671 }
672
673 int
GetLineNumber(void) const674 HighParser::GetLineNumber(void) const
675 {
676 return const_cast<InputStream *>(pIn)->GetLineNumber();
677 }
678
679
680 HighParser::ErrOut
GetLineData(void) const681 HighParser::GetLineData(void) const
682 {
683 ErrOut LineData;
684 LineData.iLineNumber = GetLineNumber();
685 LineData.sFileName = NULL;
686 LineData.sPathName = NULL;
687 return LineData;
688 }
689
690
691 bool
IsDescription(void) const692 HighParser::IsDescription(void) const
693 {
694 return (CurrToken == HighParser::DESCRIPTION);
695 }
696
697 HighParser::Token
GotDescription(void)698 HighParser::GotDescription(void)
699 {
700 return FirstToken();
701 }
702
703 int
iGetDescription_int(const char * const s)704 HighParser::iGetDescription_int(const char* const s)
705 {
706 int i = -1;
707
708 if (KeyT) {
709 i = KeyT->Find(s);
710 }
711
712 if (FirstToken() == HighParser::UNKNOWN) {
713 silent_cerr("Parser error in HighParser::iGetDescription_int(), "
714 "semicolon expected at line "
715 << GetLineData() << std::endl);
716 throw HighParser::ErrSemicolonExpected(MBDYN_EXCEPT_ARGS);
717 }
718
719 return i;
720 }
721
722
723 void
Eof(void)724 HighParser::Eof(void)
725 {
726 throw EndOfFile(MBDYN_EXCEPT_ARGS);
727 }
728
729 int
GetDescription(void)730 HighParser::GetDescription(void)
731 {
732 /* Checks if current token is a description */
733 if (!IsDescription()) {
734 silent_cerr("Parser error in HighParser::GetDescription, "
735 "invalid call to GetDescription at line "
736 << GetLineData() << std::endl);
737 throw HighParser::ErrInvalidCallToGetDescription(MBDYN_EXCEPT_ARGS);
738 }
739
740 restart_parsing:;
741
742 CurrLowToken = LowP.GetToken(*pIn);
743 if (CurrLowToken != LowParser::WORD) {
744 if (pIn->eof()) {
745 Eof();
746 goto restart_parsing;
747 }
748
749 silent_cerr("Parser error in HighParser::GetDescription, "
750 << "keyword expected at line "
751 << GetLineData() << std::endl);
752 throw HighParser::ErrKeyWordExpected(MBDYN_EXCEPT_ARGS);
753 }
754
755 /* Description corrente */
756 char* s = LowP.sGetWord();
757
758 if (ReadDescription(*this, s)) {
759 goto restart_parsing;
760 }
761
762 return iGetDescription_int(s);
763 }
764
765
766 HighParser::Token
FirstToken(void)767 HighParser::FirstToken(void)
768 {
769 CurrLowToken = LowP.GetToken(*pIn);
770
771 switch (CurrLowToken) {
772 case LowParser::COLON:
773 CurrToken = HighParser::ARG;
774 break;
775
776 case LowParser::SEMICOLON:
777 CurrToken = HighParser::DESCRIPTION;
778 break;
779
780 default:
781 CurrToken = HighParser::UNKNOWN;
782 break;
783 }
784
785 return CurrToken;
786 }
787
788 void
ExpectDescription(void)789 HighParser::ExpectDescription(void)
790 {
791 /* forces the next expected token to be a "description"
792 * e.g. a keyword followed by a colon (deprecated) */
793 CurrToken = HighParser::DESCRIPTION;
794 }
795
796
797 void
ExpectArg(void)798 HighParser::ExpectArg(void)
799 {
800 /* forces the next expected token to be an argument
801 * e.g. a keyword followed by a separator (deprecated) */
802 CurrToken = HighParser::ARG;
803 }
804
805
806 bool
IsArg(void)807 HighParser::IsArg(void)
808 {
809 return (CurrToken == ARG);
810 }
811
812 void
PutBackSemicolon(void)813 HighParser::PutBackSemicolon(void)
814 {
815 if (CurrLowToken == LowParser::SEMICOLON) {
816 pIn->putback(';');
817 }
818 }
819
820
821 void
NextToken(const char * sFuncName)822 HighParser::NextToken(const char* sFuncName)
823 {
824 CurrLowToken = LowP.GetToken(*pIn);
825 switch (CurrLowToken) {
826 case LowParser::COMMA:
827 CurrToken = HighParser::ARG;
828 break;
829
830 case LowParser::SEMICOLON:
831 CurrToken = HighParser::DESCRIPTION;
832 break;
833
834 default:
835 silent_cerr("Parser error in "
836 << sFuncName << ", missing separator at line "
837 << GetLineData() << std::endl);
838 throw HighParser::ErrMissingSeparator(MBDYN_EXCEPT_ARGS);
839 }
840 }
841
842 int
ParseWord(unsigned flags)843 HighParser::ParseWord(unsigned flags)
844 {
845 char* sBuf = sStringBuf;
846 char* sBufWithSpaces = sStringBufWithSpaces;
847
848 char cIn;
849 if (skip_remarks(*this, *pIn, cIn)) {
850 return CurrToken = HighParser::ENDOFFILE;
851 }
852
853 if (!isalpha(cIn) && cIn != '_') {
854 pIn->putback(cIn);
855 return -1;
856 }
857
858 *sBufWithSpaces++ = cIn;
859
860 if (flags & LOWER) {
861 *sBuf++ = tolower(cIn);
862
863 } else if (flags & UPPER) {
864 *sBuf++ = toupper(cIn);
865
866 } else {
867 *sBuf++ = cIn;
868 }
869
870 for (cIn = pIn->get(); isalnum(cIn) || cIn == '_' || isspace(cIn); cIn = pIn->get()) {
871 *sBufWithSpaces++ = cIn;
872 if (sBufWithSpaces >= sStringBufWithSpaces + iDefaultBufSize - 1) {
873 break;
874 }
875
876 if (isspace(cIn)) {
877 continue;
878 }
879
880 if (flags & LOWER) {
881 *sBuf++ = tolower(cIn);
882
883 } else if (flags & UPPER) {
884 *sBuf++ = toupper(cIn);
885
886 } else {
887 *sBuf++ = cIn;
888 }
889 }
890 pIn->putback(cIn);
891
892 *sBuf = '\0';
893 *sBufWithSpaces = '\0';
894
895 return 0;
896 }
897
898 void
PutbackWord(void)899 HighParser::PutbackWord(void)
900 {
901 char* sBufWithSpaces = sStringBufWithSpaces + strlen(sStringBufWithSpaces);
902
903
904 while (sBufWithSpaces > sStringBufWithSpaces) {
905 pIn->putback(*--sBufWithSpaces);
906 }
907 }
908
909 bool
IsKeyWord(const char * sKeyWord)910 HighParser::IsKeyWord(const char* sKeyWord)
911 {
912 const char sFuncName[] = "HighParser::IsKeyWord()";
913
914 if (CurrToken != HighParser::ARG) {
915 return false;
916 }
917
918 switch (ParseWord()) {
919 case 0:
920 break;
921
922 case HighParser::ENDOFFILE:
923 return true;
924
925 default:
926 return false;
927 }
928
929 if (!strcasecmp(sStringBuf, sKeyWord)) {
930 NextToken(sFuncName);
931 return true;
932 }
933
934 PutbackWord();
935
936 return false;
937 }
938
939 int
IsKeyWord(void)940 HighParser::IsKeyWord(void)
941 {
942 const char sFuncName[] = "HighParser::IsKeyWord()";
943
944 if (CurrToken != HighParser::ARG) {
945 return -1;
946 }
947
948 switch (ParseWord()) {
949 case 0:
950 break;
951
952 case HighParser::ENDOFFILE:
953 return HighParser::ENDOFFILE;
954
955 default:
956 return -1;
957 }
958
959 int iKW = -1;
960
961 if (KeyT) {
962 iKW = KeyT->Find(sStringBuf);
963 }
964
965 if (iKW >= 0) {
966 NextToken(sFuncName);
967 return iKW;
968 }
969
970 PutbackWord();
971
972 return -1;
973 }
974
975 /* 1 se l'argomento successivo e' una parola in un WordSet */
976 const char *
IsWord(const HighParser::WordSet & ws)977 HighParser::IsWord(const HighParser::WordSet& ws)
978 {
979 const char sFuncName[] = "HighParser::IsWord()";
980
981 if (CurrToken != HighParser::ARG) {
982 return 0;
983 }
984
985 switch (ParseWord()) {
986 case 0:
987 break;
988
989 default:
990 return 0;
991 }
992
993 if (ws.IsWord(std::string(sStringBuf))) {
994 NextToken(sFuncName);
995 return sStringBuf;
996 }
997
998 PutbackWord();
999
1000 return 0;
1001 }
1002
1003 TypedValue
GetValue(const TypedValue & vDefVal)1004 HighParser::GetValue(const TypedValue& vDefVal)
1005 {
1006 return GetValue<range_any<TypedValue> >(vDefVal, range_any<TypedValue>());
1007 }
1008
1009 bool
GetBool(bool bDefVal)1010 HighParser::GetBool(bool bDefVal)
1011 {
1012 TypedValue v(bDefVal);
1013 v = GetValue(v);
1014 return v.GetBool();
1015 }
1016
1017 /*
1018 * Read a boolean as "yes" or "no" and put the result in bRet
1019 * return true in case of success, false otherwise (bRet undefined)
1020 */
1021 bool
GetYesNo(bool & bRet)1022 HighParser::GetYesNo(bool& bRet)
1023 {
1024 if (IsKeyWord("yes")) {
1025 bRet = true;
1026
1027 } else if (IsKeyWord("no")) {
1028 bRet = false;
1029
1030 } else {
1031 return false;
1032 }
1033
1034 return true;
1035 }
1036
1037 bool
GetYesNoOrBool(bool bDefval)1038 HighParser::GetYesNoOrBool(bool bDefval)
1039 {
1040 bool bRet;
1041
1042 if (!GetYesNo(bRet)) {
1043 bRet = GetBool(bDefval);
1044 }
1045
1046 return bRet;
1047 }
1048
1049 integer
GetInt(integer iDefVal)1050 HighParser::GetInt(integer iDefVal)
1051 {
1052 return GetInt<range_any<integer> >(iDefVal, range_any<integer>());
1053 }
1054
1055 doublereal
GetReal(const doublereal & dDefVal)1056 HighParser::GetReal(const doublereal& dDefVal)
1057 {
1058 return GetReal<range_any<doublereal> >(dDefVal, range_any<doublereal>());
1059 }
1060
1061 mbsleep_t
GetTimeout(const mbsleep_t & DefVal)1062 HighParser::GetTimeout(const mbsleep_t& DefVal)
1063 {
1064 doublereal d;
1065 mbsleep_sleep2real(&DefVal, &d);
1066 TypedValue v(d);
1067 v = GetValue(v);
1068 mbsleep_t newval;
1069 mbsleep_real2sleep(v.GetReal(), &newval);
1070 return newval;
1071 }
1072
1073 std::string
GetString(const std::string & sDefVal)1074 HighParser::GetString(const std::string& sDefVal)
1075 {
1076 TypedValue v(sDefVal);
1077 v = GetValue(v);
1078 return v.GetString();
1079 }
1080
1081
1082 int
GetWord(void)1083 HighParser::GetWord(void)
1084 {
1085 const char sFuncName[] = "HighParser::GetWord()";
1086
1087 if (CurrToken != HighParser::ARG) {
1088 silent_cerr("Parser error in "
1089 << sFuncName << ", keyword arg expected at line "
1090 << GetLineData() << std::endl);
1091 throw HighParser::ErrKeyWordExpected(MBDYN_EXCEPT_ARGS);
1092 }
1093
1094 CurrLowToken = LowP.GetToken(*pIn);
1095 if (CurrLowToken != LowParser::WORD) {
1096 silent_cerr("Parser error in "
1097 << sFuncName << ", keyword expected at line "
1098 << GetLineData() << std::endl);
1099 throw HighParser::ErrKeyWordExpected(MBDYN_EXCEPT_ARGS);
1100 }
1101
1102 int i = -1;
1103 if (KeyT) {
1104 i = KeyT->Find(LowP.sGetWord());
1105 }
1106
1107 NextToken(sFuncName);
1108
1109 return i;
1110 }
1111
1112 const char*
GetString(unsigned flags)1113 HighParser::GetString(unsigned flags)
1114 {
1115 const char sFuncName[] = "HighParser::GetString()";
1116
1117 pedantic_cout("use of deprecated method \"GetString\" at line"
1118 << GetLineData() << std::endl);
1119
1120 if (CurrToken != HighParser::ARG) {
1121 silent_cerr("Parser error in "
1122 << sFuncName << ", string arg expected at line "
1123 << GetLineData() << std::endl);
1124 throw HighParser::ErrStringExpected(MBDYN_EXCEPT_ARGS);
1125 }
1126
1127 char* s = sStringBuf;
1128 char* sTmp = s;
1129
1130 char cIn = '\0';
1131
1132 while (isspace(cIn = pIn->get())) {
1133 NO_OP;
1134 }
1135
1136 if (pIn->eof()) {
1137 CurrToken = HighParser::ENDOFFILE;
1138 return NULL;
1139 }
1140
1141 pIn->putback(cIn);
1142 for (cIn = pIn->get(); cIn != ',' && cIn != ';'; cIn = pIn->get()) {
1143 /* Attenzione! cosi' la legge tutta,
1144 * ma ne tiene solo iBufSize-1 caratteri */
1145 if (pIn->eof()) {
1146 CurrToken = HighParser::ENDOFFILE;
1147 *sTmp = '\0';
1148 return s;
1149
1150 } else if (sTmp < s + iDefaultBufSize - 1) {
1151 if (!(flags & HighParser::EATSPACES) || !isspace(cIn)) {
1152 if (flags & HighParser::LOWER) {
1153 cIn = tolower(cIn);
1154
1155 } else if (flags & HighParser::UPPER) {
1156 cIn = toupper(cIn);
1157 }
1158
1159 *sTmp++ = cIn;
1160 }
1161 }
1162 }
1163
1164 pIn->putback(cIn);
1165 *sTmp = '\0';
1166
1167 NextToken(sFuncName);
1168
1169 return s;
1170 }
1171
1172 void
SetDelims(enum Delims Del,char & cLdelim,char & cRdelim) const1173 HighParser::SetDelims(enum Delims Del, char &cLdelim, char &cRdelim) const
1174 {
1175 cLdelim = '\0';
1176 cRdelim = '\0';
1177
1178 switch (Del) {
1179 case PLAINBRACKETS:
1180 cLdelim = '(';
1181 cRdelim = ')';
1182 break;
1183
1184 case SQUAREBRACKETS:
1185 cLdelim = '[';
1186 cRdelim = ']';
1187 break;
1188
1189 case CURLYBRACKETS:
1190 cLdelim = '{';
1191 cRdelim = '}';
1192 break;
1193
1194 case SINGLEQUOTE:
1195 cLdelim = '`';
1196 cRdelim = '\'';
1197 break;
1198
1199 default:
1200 case UNKNOWNDELIM:
1201 case DEFAULTDELIM:
1202 case DOUBLEQUOTE:
1203 cLdelim = '"';
1204 cRdelim = '"';
1205 break;
1206 }
1207 }
1208
1209 bool
IsStringWithDelims(enum Delims Del)1210 HighParser::IsStringWithDelims(enum Delims Del)
1211 {
1212 char cLdelim, cRdelim;
1213 SetDelims(Del, cLdelim, cRdelim);
1214
1215 char cIn;
1216 if (skip_remarks(*this, *pIn, cIn)) {
1217 return false;
1218 }
1219
1220 /* put back the first non-remark char */
1221 pIn->putback(cIn);
1222
1223 /* if the left delimiter is found, true */
1224 return (cIn == cLdelim);
1225 }
1226
1227 const char*
GetStringWithDelims(enum Delims Del,bool escape)1228 HighParser::GetStringWithDelims(enum Delims Del, bool escape)
1229 {
1230 const char sFuncName[] = "HighParser::GetStringWithDelims()";
1231
1232 if (CurrToken != HighParser::ARG) {
1233 silent_cerr("Parser error in "
1234 << sFuncName << ", string arg expected at line "
1235 << GetLineData() << std::endl);
1236 throw HighParser::ErrStringExpected(MBDYN_EXCEPT_ARGS);
1237 }
1238
1239 char* s = sStringBuf;
1240 char* sTmp = s;
1241
1242 char cLdelim, cRdelim;
1243 SetDelims(Del, cLdelim, cRdelim);
1244
1245 char cIn;
1246 if (skip_remarks(*this, *pIn, cIn)) {
1247 return NULL;
1248 }
1249
1250 /* Se trova il delimitatore sinistro, legge la stringa */
1251 if (cIn == cLdelim) {
1252 for (cIn = pIn->get(); cIn != cRdelim; cIn = pIn->get()) {
1253 /* Attenzione! cosi' la legge tutta,
1254 * ma ne tiene solo iBufSize-1 caratteri */
1255 if (pIn->eof()) {
1256 /* FIXME: this should be an error ... */
1257 sTmp[0] = '\0';
1258 return s;
1259
1260 } else if (sTmp < s + iDefaultBufSize - 1) {
1261 if (cIn == ESCAPE_CHAR) {
1262 cIn = pIn->get();
1263 if (cIn == '\n') {
1264
1265 /*
1266 * eat the newline as well, so that
1267
1268 "first line\
1269 second line"
1270
1271 * actually results in "first linesecond line"
1272 */
1273
1274 cIn = pIn->get();
1275
1276 } else if (cIn == '\r') {
1277 cIn = pIn->get();
1278 if (cIn != '\n') {
1279 pIn->putback(cIn);
1280 goto escaped_generic;
1281 }
1282 cIn = pIn->get();
1283
1284 } else if ((cIn == ESCAPE_CHAR) || (cIn == cRdelim)) {
1285 if (!escape) {
1286 sTmp[0] = ESCAPE_CHAR;
1287 ++sTmp;
1288 }
1289
1290 } else {
1291 escaped_generic:;
1292 if (escape) {
1293 int i, c = 0;
1294 char hex[3];
1295
1296 /*
1297 * allow non-printable chars in the form "\<hexpair>",
1298 * so that "\78" is equivalent to "x";
1299 * "\<non-hexpair>" is treated as an error.
1300 */
1301
1302 hex[0] = cIn;
1303 hex[1] = pIn->get();
1304 hex[2] = '\0';
1305
1306 for (i = 0; i < 2; i++) {
1307 int shift = 4*(1 - i), h = 0;
1308
1309 /* NOTE: this conversion relies
1310 * on 0-9, a-f, A-F being consecutive,
1311 * which is true for ASCII, but might
1312 * not be for other encodings;
1313 * bah, not critical right now */
1314 if (hex[i] >= '0' && hex[i] <= '9') {
1315 h = hex[i] - '0';
1316 } else if (hex[i] >= 'a' && hex[i] <= 'f') {
1317 h = hex[i] - 'a';
1318 } else if (hex[i] >= 'A' && hex[i] <= 'F') {
1319 h = hex[i] - 'A';
1320 } else {
1321 silent_cerr("invalid escape sequence "
1322 "\"\\" << hex << "\" "
1323 "at line " << GetLineData()
1324 << std::endl);
1325 throw ErrGeneric(MBDYN_EXCEPT_ARGS);
1326 }
1327
1328 c += (h << shift);
1329 }
1330 cIn = c;
1331
1332 } else {
1333 sTmp[0] = ESCAPE_CHAR;
1334 ++sTmp;
1335 }
1336 }
1337 }
1338 sTmp[0] = cIn;
1339 ++sTmp;
1340 }
1341 }
1342
1343 /* Se trova una virgola o un punto e virgola, le rimette nello stream
1344 * e passa oltre, restituendo un puntatore nullo. Il chiamante deve
1345 * occuparsi della gestione del valore di default */
1346 } else if (cIn == ',' || cIn == ';') {
1347 pIn->putback(cIn);
1348 goto nullstring;
1349
1350 /* Altrimenti c'e' qualcosa senza delimitatore. Adesso da' errore,
1351 * forse e' piu' corretto fargli ritornare lo stream intatto */
1352 } else {
1353 silent_cerr("Parser error in "
1354 << sFuncName << std::endl
1355 << "first non-blank char at line "
1356 << GetLineData() << " isn't a valid left-delimiter"
1357 << std::endl);
1358 throw HighParser::ErrIllegalDelimiter(MBDYN_EXCEPT_ARGS);
1359 }
1360
1361 /* Mette zero al termine della stringa */
1362 *sTmp = '\0';
1363
1364 nullstring:;
1365 NextToken(sFuncName);
1366 return s;
1367 }
1368
1369 /* HighParser - end */
1370
1371 std::ostream&
operator <<(std::ostream & out,const HighParser::ErrOut & err)1372 operator << (std::ostream& out, const HighParser::ErrOut& err)
1373 {
1374 out << err.iLineNumber;
1375
1376 if (err.sFileName != 0) {
1377 out << ", file <";
1378 if (err.sPathName != 0) {
1379 out << err.sPathName << DIR_SEP;
1380 }
1381 out << err.sFileName << '>';
1382 }
1383
1384 return out;
1385 }
1386
1387 /* HighParser - end */
1388
1389