Xmipp  v3.23.11-Nereus
argsparser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: J.M de la Rosa Trevin (jmdelarosa@cnb.csic.es)
3  *
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your param) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include <algorithm>
27 #include <sstream>
28 #include "argsparser.h"
29 #include "xmipp_error.h"
30 
31 //------------------- LEXER IMPLEMENTATIONS --------------------------------
32 
34 {
35  switch (type)
36  {
37  case TOK_ID: //identifier
38  return "ID";
39  case TOK_OPT: // -ID or --ID
40  return "OPTION";
41  case TOK_INT: //integer number
42  return "INT";
43  case TOK_FLOAT: //float number
44  return "FLOAT";
45  case TOK_STR: //string value
46  return "STRING";
47  case TOK_MINUS: // - or --
48  return "MINUS";
49  case TOK_EQ: // =
50  return "EQUAL";
51  case TOK_COMM: // Comment: from : until end of line
52  return "COMMENT";
53  case TOK_LAN: // <
54  return "<";
55  case TOK_RAN: // >
56  return ">";
57  case TOK_LBRA: // [
58  return "[";
59  case TOK_RBRA: // ]
60  return "]";
61  case TOK_END: // end of input
62  return "EOF";
64  case TOK_WHERE: // 'WHERE' keyword
65  return "WHERE";
66  case TOK_ALIAS: // 'ALIAS' keyword
67  return "ALIAS";
68  case TOK_SECTION:
69  return "SECTION";
70  case TOK_SEMI:
71  return ";";
72  case TOK_COMMA:
73  return ",";
74  case TOK_PLUS:
75  return "+";
76  default:
77  return "UKNOWN";
78  };
79 }
80 
82 {
83  line = 0;
84  pos = 0;
85  pToken = new ArgToken();
86  //Initialize reserved words dictionary
87  reservedWords["WHERE"] = TOK_WHERE;
88  reservedWords["ALIAS"] = TOK_ALIAS;
89  reservedWords["OR"] = TOK_OR;
90  reservedWords["REQUIRES"] = TOK_REQUIRES;
91 }
92 
94 {
95  delete pToken;
96 }
97 
98 //#define DEBUG
100 {
101  input.push_back(line + " ");
102 #ifdef DEBUG
103  std::cout << input.size() << ": " << line << std::endl;
104 #endif
105 }
106 
107 inline void ArgLexer::nextLine()
108 {
109  ++line;
110  pos = 0;
111 }
112 
113 void ArgLexer::setupToken(ArgTokenType type)
114 {
115  pToken->type = type;
116  if (type != TOK_END)
117  {
118  pToken->line = line;
119  pToken->start = pos;
120  pToken->end = pos + offset - 1;
121  pToken->lexeme = input[line].substr(pos, offset);
122 
123  if (type == TOK_ID)
124  {
125  String s = pToken->lexeme;
126  std::transform(s.begin(), s.end(), s.begin(),
127  ::toupper);
128  std::map<String, ArgTokenType>::iterator it;
129  it = reservedWords.find(s);
130  if (it != reservedWords.end())
131  {
132  pToken->lexeme = it->first;
133  pToken->type = it->second;
134  }
135 
136  }
137  else if (type == TOK_STR)
138  ++offset;
139  pos += offset;
140  offset = 1;
141  }
142  else
143  pToken->lexeme = "EOF";
144 }
145 
146 void ArgLexer::checkVisibility()
147 {
148  while (input[line][pos] == '+')
149  {
150  ++(pToken->visibility);
151  ++pos;
152  }
153 }
154 
155 void ArgLexer::checkIndependent()
156 {
157  if (input[line][pos]== '*')
158  {
159  pToken->starred = true;
160  ++pos;
161  }
162 }
163 
165 {
166  //make it visible by default
167  pToken->visibility = 0;
168  pToken->starred = false;
169 
170  if (line == input.size())
171  {
172  setupToken(TOK_END);
173  return false;
174  }
175 
176  char c = input[line][pos];
177 
178  //Skip all white spaces
179  while (line < input.size() && pos < input[line].length() && isspace(c
180  = input[line][pos]))
181  {
182  ++pos;
183  if (c == '\0' || c == '\n' || pos == input[line].length()) //Next line
184  {
185  nextLine();
186  }
187  }
188 
189  if (line == input.size())
190  setupToken(TOK_END);
191  else if (isalpha(c) || c == '_')
192  {
193  offset = 0;
194  while (isalnum(c) || c == '_')
195  {
196  ++offset;
197  c = input[line][pos + offset];
198  }
199  setupToken(TOK_ID);
200  }
201  else if (isalnum(c) || (c == '-' && isdigit(input[line][pos + 1])))
202  {
203  offset = 1;
204  ArgTokenType t = TOK_INT;
205  while (isdigit(input[line][pos + offset]))
206  ++offset;
207  if (input[line][pos + offset] == '.')
208  {
209  ++offset;
210  while (isdigit(input[line][pos + offset]))
211  ++offset;
212  t = TOK_FLOAT;
213  }
214  if (input[line][pos + offset] == 'e')
215  {
216  ++offset;
217  if (input[line][pos + offset] != '+' && input[line][pos + offset]
218  != '-')
219  {
220  std::cerr << "ERROR: expected '+' or '-' " << std::endl
221  << "at line: " << line + 1 << " pos: " << offset + 1
222  << std::endl;
223  exit(1);
224  }
225  ++offset;
226  while (isdigit(input[line][pos + offset]))
227  ++offset;
228  t = TOK_FLOAT;
229 
230  }
231  setupToken(t);
232  }
233  else
234  {
235  offset = 1;
236  bool empty;
237  switch (c)
238  {
239  case '<':
240  setupToken(TOK_LAN);
241  break;
242  case '>':
243  setupToken(TOK_RAN);
244  break;
245  case '=':
246  if (input[line][pos + offset] == '=')
247  {
248  pos = input[line].find_first_not_of('=', pos + 1);
249  checkVisibility();
250  offset = input[line].find_first_of('=', pos + 1);
251  offset -= pos;
252  setupToken(TOK_SECTION);
253  nextLine();
254  }
255  else
256  //simple equal sign '='
257  setupToken(TOK_EQ);
258  break;
259  case '[':
260  setupToken(TOK_LBRA);
261  break;
262  case ']':
263  setupToken(TOK_RBRA);
264  break;
265  case ';':
266  setupToken(TOK_SEMI);
267  break;
268  case ',':
269  setupToken(TOK_COMMA);
270  break;
271  case '+':
272  setupToken(TOK_PLUS);
273  break;
274  case '.':
275  if (input[line][pos + offset] == '.' &&
276  input[line][pos + offset + 1] == '.')
277  {
278  offset += 2;
279  setupToken(TOK_ETC);
280  }
281  break;
282  case ':':
283  ++pos;
284 
285  checkVisibility();
286 
287  offset = input[line].find_first_of("\n\r", pos);
288  offset -= pos;
289  setupToken(TOK_COMM);
290  nextLine();
291  break;
292  case '-':
293  if (input[line][pos + offset] == '-')
294  ++offset;
295  empty = true;
296  c = input[line][pos + offset];
297  if (isalpha(c) || c == '_') //should start with letter or _
298  {
299  while (isalnum(c) || c == '_')
300  {
301  empty = false;
302  ++offset;
303  c = input[line][pos + offset];
304  }
305  }
306  if (empty)
307  {
308  std::cerr << "ERROR: Params should be of the form -ID or --ID"
309  << std::endl;
310  exit(1);
311  }
312  setupToken(TOK_OPT);
313  checkVisibility();
314  checkIndependent();
315  break;
316  case '"':
317  offset = input[line].find_first_of('"', pos + 1);
318  ++pos;
319  offset -= pos;
320  setupToken(TOK_STR);
321  break;
322  default:
323  std::cerr << "ERROR: Unexpected character '" << c << "'"
324  << std::endl << "at line: " << line + 1 << " pos: " << pos
325  + 1 << std::endl;
326  std::cerr << "WRONG LINE: " << input[line] << std::endl;
327  exit(1);
328  }
329  }
330 
331  //ConsolePrinter * cp = new ConsolePrinter();
332  //cp->printToken(pToken);
333 
334  return true;
335 }
336 
338 {
339  return pToken;
340 }
342 {
343  return pToken->type;
344 }
345 
346 
347 //------------------- PARSER IMPLEMENTATIONS --------------------------------
348 
350 {
351  pLexer = lexer;
352  visible = 0;
353  this->parent = parent;
354 }
355 
357 {
358  return pLexer->lookahead();
359 }
360 
362 {
363  return pLexer->lookahead() == type;
364 }
365 
367 {
368  return pLexer->currentToken();
369 }
370 
372 {
373  pLexer->nextToken();
374 }
375 
377 {
378  ArgTokenType t = lookahead();
379  if (t != type)
380  unexpectedToken();
381  //Store consumed token
382  if (currentToken() != NULL)
383  token = *currentToken();
384  else
385  REPORT_ERROR(ERR_MEM_NULLPOINTER, "current token is null");
386 
387  //Ask for new token
388  nextToken();
389  return true;
390 }
391 
393 {
394  comments.clear();
395  //Comment List (CL)
396  //CL -> comment CL | e
397  while (lookahead(TOK_COMM))
398  {
399  consume(TOK_COMM);
400  comments.addComment(token.lexeme, token.visibility);
401  }
402 
403  return true;
404 }
405 
407 {
408  std::cerr << ">>> ERROR: " << msg << std::endl << " at line "
409  << token.line + 1 << " column " << token.start + 1 << std::endl;
410  exit(1);
411 }
412 
414 {
415  token = *currentToken();
416  error(formatString("Unexpected token '%s' (%s) \n %s",
417  token.lexeme.c_str(), ArgToken::typeString(token.type), msg.c_str()));
418 
419 }
420 
422  ASTNode(lexer, parent)
423 {
424  isList = false;
425  hasDefault = false;
426 }
427 
429 {
430  for (size_t i = 0; i < subParams.size(); ++i)
431  delete subParams[i];
432 }
433 
435 {
436  // A -> < ID DEF > | <...>
437  // DEF -> = VALUE | e
438  // VALUE -> INT | FLOAT | STRING
439  consume(TOK_LAN);
440  if (lookahead(TOK_ID))
441  {
442  consume(TOK_ID);
443  name = token.lexeme;
444  if (lookahead(TOK_EQ))
445  {
446  consume(TOK_EQ);
447  //Consume a value, that can be int, float or string
448  ArgTokenType t = lookahead();
449 
450  if (t == TOK_INT || t == TOK_FLOAT || t == TOK_STR || t == TOK_ID)
451  consume(t);
452  else
453  unexpectedToken(" expecting INT, FLOAT, STRING or ID.");
454 
455  hasDefault = true;
457  }
458  }
459  else
460  {
461  consume(TOK_ETC);
462  name = token.lexeme;
463  isList = true;
464  }
465  consume(TOK_RAN);
466  return true;
467 }
468 
469 bool ArgumentDef::acceptArguments(std::stringstream &errors, size_t & index, std::vector<const char *> &cmdArguments)
470 {
472  if (index == cmdArguments.size())
473  {
474  if (hasDefault)
475  {
476  cmdArguments.push_back(argDefault.c_str());
477  }
478  else
479  {
480  errors << "Not enough arguments, <" << name << "> has not default. ";
481  return false;
482  }
483  }
484 
485  if (isList)
486  return true;
487 
488  if (!subParams.empty())
489  {
490  bool found = false;
491  String optionValue = (String)cmdArguments[index];
492  for (size_t i = 0; i < subParams.size(); ++i)
493  {
494  if (subParams[i]->name == optionValue)
495  {
496  found = true;
497  ++index;
498 
499  if (!subParams[i]->checkRequires(errors, prog))
500  return false;
501 
502  for (size_t j = 0; j < subParams[i]->arguments.size(); ++j)
503  if (!subParams[i]->arguments[j]->acceptArguments(errors, index, cmdArguments))
504  return false;
505  break;
506  }
507  }
508  if (!found)
509  {
510  errors << optionValue << " is not a valid option for <" << name <<"> ";
511  return false;
512  }
513  return true;//not increment index when found subparams, already incremented
514  }
515 
516  //if not list increment index
517  ++index;
518 
519  return true;
520 }
521 
523  ASTNode(lexer, parent)
524 {
525  exclusiveGroup = NULL;
526  orBefore = false;
527 }
528 
530 {
531  for (size_t i = 0; i < arguments.size(); ++i)
532  delete arguments[i];
533  if (!orBefore)
534  delete exclusiveGroup;
535 }
536 
537 bool ParamDef::containsArgument(const String & argName)
538 {
539  return findArgument(argName) == NULL;
540 }
541 
543 {
544  for (size_t i = 0; i < arguments.size(); ++i)
545  if (argName == arguments[i]->name)
546  return arguments[i];
547  return NULL;
548 }
549 
550 bool ParamDef::containsAlias(const String & alias)
551 {
552  for (size_t i = 0; i < aliases.size(); ++i)
553  if (alias == aliases[i])
554  return true;
555  return false;
556 }
557 
559 {
561  notOptional = true;
562  orBefore = false;
563  independent = false;
564  counter = 0;
565 
566  //Param Definition(OD)
567  //OD -> OH CL
568  //Param Header(OH)
569  //OH -> O | [O] | OR O
570  //Param(O)
571  //O -> param AL
573  {
574  consume(TOK_LBRA);
575  notOptional = false;
576  }
577  else if (lookahead(TOK_OR))
578  {
579  consume(TOK_OR);
580  orBefore = true;
581  }
582  prog->addParamExclusiveGroup(this);
583 
584  consume(TOK_OPT);
585  name = token.lexeme;
588 
589  prog->addParamName(name, this);
590 
591  //Parse argument list
593 
594  if (notOptional == false)
595  consume(TOK_RBRA);
596 
597  //Parse comment list
599 
600  //WHERE section
601  while (lookahead(TOK_WHERE))
602  {
604  while (lookahead(TOK_LAN))
605  {
606  consume(TOK_LAN);
607  consume(TOK_ID);
609  if (pArg == NULL)
610  {
611  std::cerr << "ERROR; on WHERE definition.\n Param '" << name
612  << "' not contains argument '" << token.lexeme << "'"
613  << std::endl;
614  exit(1);
615  }
616  consume(TOK_RAN);
617 
618  while (lookahead(TOK_ID))
619  {
620  ParamDef * pOpt = new ParamDef(pLexer, this);
621  pOpt->consume(TOK_ID);
622 
623  pOpt->name = pOpt->token.lexeme;
624  pOpt->parseArgumentList();
625  pOpt->parseCommentList(pOpt->comments);
626  pOpt->parseParamList(TOK_REQUIRES, prog, pOpt->requires, false);
627  pArg->subParams.push_back(pOpt);
628  }
629 
630  }
631  }
632 
633  //ALIAS section
634  parseParamList(TOK_ALIAS, prog, aliases, true);
635 
636  //REQUIRES section
637  parseParamList(TOK_REQUIRES, prog, requires, false);
638 
639  return true;
640 }
641 
643 {
644  bool previousList = false; // to check only one list and at end of arguments
645  bool previousDefault = false; // to check that default values only can be at end
646  //Argument List (AL)
647  //AL -> argument AL | e
648  while (lookahead(TOK_LAN))
649  {
650  ArgumentDef * arg = new ArgumentDef(pLexer, this);
651  arg->parse();
652  token = arg->token;
653 
654  if (previousList)
655  error("A list <...> has found not at the end of argument list");
656 
657  if (previousDefault && !arg->hasDefault)
658  error("A non default argument was found before a default one");
659 
660  previousList = arg->isList;
661  previousDefault = arg->hasDefault;
662 
663  arguments.push_back(arg);
664  }
665  return true;
666 }
667 
669  bool isAlias)
670 {
671  paramList.clear();
672  if (lookahead(startToken))
673  {
674  consume(startToken);
675  consume(TOK_OPT);
676  paramList.push_back(token.lexeme);
677 
678  if (isAlias)
679  prog->addParamName(token.lexeme, this);
680  else
682 
683  while (lookahead(TOK_COMMA))
684  {
686  consume(TOK_OPT);
687  paramList.push_back(token.lexeme);
688  if (isAlias)
689  prog->addParamName(token.lexeme, this);
690  else
692  }
693  consume(TOK_SEMI);
694  }
695 
696  return true;
697 }
698 
699 bool ParamDef::checkRequires(std::stringstream & errors, ProgramDef * prog)
700 {
701  ParamDef * param;
702  bool correct = true;
703  for (size_t i = 0; i < requires.size(); ++i)
704  {
705  param = prog->findParam(requires[i]);
706  if (param->counter < 1)
707  {
708  errors << "Parameter " << name << " requires " << requires[i] << std::endl;
709  correct = false;
710  }
711  }
712  return correct;
713 }
714 
715 void ParamDef::check(std::stringstream & errors)
716 {
717  String aaa = name;
718 
720  if (counter > 1 )
721  {
722  errors << "Duplicated parameter: " << name << " (check alias)" << std::endl;
723  return;
724  }
725 
726  if (counter == 1)
727  {
728  //Check requires restrictions
729  checkRequires(errors, prog);
730 
731  //Check the number of arguments
732  if (arguments.empty()) //if not arguments
733  {
734  if (!cmdArguments.empty())
735  errors << "Parameter " << name << " doesn't take any argument, "
736  << cmdArguments.size() << " provided." << std::endl;
737  }
738  else
739  {
740  size_t argIndex = 0;
741 
742  for (size_t i = 0; i < arguments.size(); ++i)
743  if (!arguments[i]->acceptArguments(errors, argIndex, cmdArguments))
744  {
745  errors << " parameter: " << name << std::endl;
746  return;
747  }
748 
749  if (argIndex < cmdArguments.size() && !arguments[arguments.size()-1]->isList)
750  errors << "Too many arguments for parameter " << name << std::endl;
751  }
752  }
753  else
754  {
755  //Fill default arguments
756  for (size_t i = 0; i < arguments.size(); ++i)
757  if (arguments[i]->hasDefault)
758  cmdArguments.push_back(arguments[i]->argDefault.c_str());
759  }
760 }
761 
763 {
765  if (prog->findParam(param->name) == NULL)
766  {
767  prog->addParamName(param->name, param);
768  param->parent = this;
769  params.push_back(param);
770  }
771 }
772 
774  ASTNode(lexer, parent)
775 {}
776 
778 {
779  for (size_t i = 0; i < params.size(); ++i)
780  delete params[i];
781 }
782 
784 {
785  if (lookahead(TOK_SECTION))
786  {
788  name = token.lexeme;
791  }
792 
793  //OL -> params OD ODL | SD ODL | e
794  ArgTokenType t = lookahead();
795 
796  if (!(t == TOK_OPT || t == TOK_OR || t == TOK_LBRA))
797  unexpectedToken("parsing section, expecting param definition");
798 
799  while (t == TOK_OPT || t == TOK_OR || t == TOK_LBRA)
800  {
801  ParamDef * param = new ParamDef(pLexer, this);
802  param->parse();
803  params.push_back(param);
804  t = lookahead();
805  }
806 
807  return true;
808 }
809 
811  ASTNode()
812 {
813  pLexer = new ArgLexer();
814  singleOption = false;
815  exclusiveGroup = NULL;
816 }
817 
819 {
820  delete pLexer;
821  for (size_t i = 0; i < sections.size(); ++i)
822  delete sections[i];
823 }
826 {
827 
828  // P -> ID CL OL
829  //consume(TOK_ID);
830  //name = token.lexeme;
831  //Usage comments
832  //parseCommentList(usageComments);
833 
834  //Ask for first token
835  pLexer->nextToken();
836 
837  while (!lookahead(TOK_END))
838  {
839  SectionDef * s = new SectionDef(pLexer, this);
840  s->parse();
841  String name = s->name;
842  sections.push_back(s);
843  }
844  consume(TOK_END);
845 
846  return true;
847 }
848 
849 void addOcurrence(std::map<String, int> &map, const String &name)
850 {
851  if (map.find(name) != map.end())
852  map[name]++;
853  else
854  map[name] = 1;
855 }
856 
857 void reportExclusiveErrors(std::stringstream & errors, std::vector<ParamDef*> &exclusive)
858 {
859  if (exclusive.empty())
860  return;
861 
862  std::vector<ParamDef*> exclusive2;
863  for (size_t i = 0; i < exclusive.size(); ++i)
864  if (exclusive[i]->counter == 1)
865  exclusive2.push_back(exclusive[i]);
866  if (exclusive2.size() > 1)
867  {
868  errors << "Parameters ";
869  for (size_t i = 0; i < exclusive.size() - 1; ++i)
870  errors << exclusive[i]->name << " ";
871  errors << "and " << exclusive[exclusive.size()-1]->name << " are mutually exclusive (check alias)" << std::endl;
872  }
873  else if (exclusive2.empty() && exclusive[0]->notOptional)
874  {
875  errors << "You should provide parameter " << exclusive[0]->name;
876  for (size_t i = 1; i < exclusive.size(); ++i)
877  errors << " or " << exclusive[i]->name;
878  errors << std::endl;
879  }
880  exclusive.clear();
881 }
882 
883 void ProgramDef::check(std::stringstream & errors)
884 {
885  std::vector<ParamDef*> exclusive;
886  SectionDef * section;
887  ParamDef * param;
888 
889  for (size_t i = 0; i < sections.size(); ++i)
890  {
891  section = sections[i];
892  for (size_t j = 0; j < section->params.size(); ++j)
893  {
894  param = section->params[j];
895  //Doesn't check for alias, for doesn't repeat error messages
896  param->check(errors);
897  if (!param->orBefore)
898  reportExclusiveErrors(errors, exclusive);
899  exclusive.push_back(param);
900  }
901  }
902  reportExclusiveErrors(errors, exclusive);
903 }
904 
906 {
907  if (paramsMap.find(name) != paramsMap.end())
908  return paramsMap[name];
909  return NULL;
910 }
911 
913 {
914  if (paramsMap.find(name) != paramsMap.end())
915  error((String) "The param '" + name + "' is repeated.");
916  else
917  paramsMap[name] = param;
918 }
919 
921 {
922  pendingRequires.push_back(name);
923 }
924 
926 {
927  if (exclusiveGroup == NULL || param->orBefore == false)
928  exclusiveGroup = new std::vector<ParamDef*>();
929  exclusiveGroup->push_back(param);
930  param->exclusiveGroup = exclusiveGroup;
931 }
932 
934 {
935 
936  SectionDef * section;
937  ParamDef * param;
938 
939  for (size_t i = 0; i < sections.size(); ++i)
940  {
941  section = sections[i];
942  for (size_t j = 0; j < section->params.size(); ++j)
943  {
944  param = section->params[j];
945  param->counter = 0;
946  param->cmdArguments.clear();
947  }
948  }
949 }
950 
951 void ProgramDef::read(int argc, const char ** argv, bool reportErrors)
952 {
953  clear();
954  std::stringstream errors;
955  //Set the name with the first argument
956  name = argv[0];
957  singleOption = false;
958 
959  ParamDef * param = NULL;
960 
961  //We assume that all options start with -
962  if (argc > 1 && argv[1][0] != '-')
963  {
964  //Assume if the first is missing, treat as -i
965  if ((param = findParam("-i")) == NULL) //-i is not allowed, report error
966  REPORT_ERROR(ERR_ARG_INCORRECT, "Parameters should start with a -");
967  else
968  {
969  ++(param->counter);
970  if (param->independent)
971  singleOption = true;
972  }
973  //Assume if the first is missing, treat as -i
974  }
975 
976  //Read command line params and arguments
977  for (int i = 1; i < argc; ++i)
978  {
979 
980  if (argv[i][0] == '-' && !isdigit(argv[i][1]))
981  {
982  param = findParam(argv[i]);
983  if (param == NULL)
984  errors << "Unrecognized parameter: " << argv[i] << std::endl;
985  else
986  {
987  ++(param->counter);
988  if (param->independent)
989  singleOption = true;
990  }
991  }
992  else if (param != NULL)
993  param->cmdArguments.push_back(argv[i]);
994  }
995 
996  if (!singleOption)
997  check(errors);
998 
999  //Report errors found
1000  if (reportErrors && errors.str().length() > 0)
1001  {
1002  //Unrecognized parameters
1003  //for (size_t i = 0; i < unrecognized.size(); ++i)
1004  // std::cerr << "Unrecognized parameter: " << unrecognized[i] << std::endl;
1005  REPORT_ERROR(ERR_ARG_BADCMDLINE, errors.str().c_str());
1006  }
1007 }
1008 
1009 SectionDef * ProgramDef::addSection(String sectionName, int visibility)
1010 {
1011  SectionDef * section = new SectionDef(NULL, this);
1012  section->name = sectionName;
1013  section->visible = visibility;
1014  sections.push_back(section);
1015  return section;
1016 }
1017 
1019 {
1020  ParamDef * paramDef = findParam(param);
1021  if (paramDef == NULL)
1022  REPORT_ERROR(ERR_ARG_INCORRECT, formatString("Doesn't exists param: %s", param.c_str()));
1024  //if (paramDef->counter == 1)
1025  // return paramDef;
1026  std::stringstream errors;
1027  size_t argIndex = 0;
1028  for (size_t i = 0; i < paramDef->arguments.size(); ++i)
1029  if (!paramDef->arguments[i]->acceptArguments(errors, argIndex, paramDef->cmdArguments))
1030  {
1031  errors << " parameter: " << paramDef->name << std::endl;
1032  REPORT_ERROR(ERR_ARG_INCORRECT, errors.str());
1033  }
1034  return paramDef;
1035 }
1036 
1037 const char * ProgramDef::getParam(const char * paramName, size_t argNumber)
1038 {
1039  ParamDef * param = findAndFillParam(paramName);
1040  if (param == NULL)
1041  REPORT_ERROR(ERR_ARG_INCORRECT, formatString("Doesn't exists param: %s", paramName));
1042  if (argNumber < 0 || argNumber >= param->cmdArguments.size())
1043  REPORT_ERROR(ERR_ARG_INCORRECT, formatString("Argument index %d in param %s out of bounds.", argNumber, paramName));
1044  return param->cmdArguments.at(argNumber);
1045 }
1046 
1047 const char * ProgramDef::getParam(const char * paramName, const char * subParam, size_t argNumber)
1048 {
1049  ParamDef * param = findAndFillParam(paramName);
1050 
1051  size_t i = 0;
1052  for (i = 0; i < param->cmdArguments.size(); ++i)
1053  if (strcmp(param->cmdArguments[i], subParam) == 0)
1054  break;
1055 
1056  if (i == param->cmdArguments.size())
1057  REPORT_ERROR(ERR_ARG_INCORRECT, formatString("Sub-param %s was not supplied in command line.", subParam));
1058 
1059  return param->cmdArguments.at(i + 1 + argNumber);
1060 }
Errors on command line parameters.
Definition: xmipp_error.h:112
void nextToken()
Definition: argsparser.cpp:371
void addParamRequires(const String &name)
Definition: argsparser.cpp:920
ArgTokenType type
Type of the token.
Definition: argsparser.h:75
ArgTokenType lookahead() const
Definition: argsparser.cpp:341
virtual bool consume(ArgTokenType type)
Definition: argsparser.cpp:376
Reserved words.
Definition: argsparser.h:62
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
std::vector< ParamDef * > * exclusiveGroup
Definition: argsparser.h:200
String name
Definition: argsparser.h:152
ParamDef * findAndFillParam(const String &param)
doublereal * c
bool acceptArguments(std::stringstream &errors, size_t &argIndex, std::vector< const char *> &cmdArguments)
This function will take an index and check if there are enougth arguments.
Definition: argsparser.cpp:469
bool parseCommentList(CommentList &comments)
Definition: argsparser.cpp:392
virtual void check(std::stringstream &errors)
Definition: argsparser.cpp:715
void clear()
clear read arguments
Definition: argsparser.cpp:933
bool notOptional
Definition: argsparser.h:195
CommentList comments
Definition: argsparser.h:223
ParamDef * findParam(const String &param)
Definition: argsparser.cpp:905
Null pointer passed as parameter.
Definition: xmipp_error.h:168
ASTNode * parent
Definition: argsparser.h:147
int visibility
Definition: argsparser.h:83
bool checkRequires(std::stringstream &errors, ProgramDef *prog)
Definition: argsparser.cpp:699
bool hasDefault
Definition: argsparser.h:176
bool singleOption
Definition: argsparser.h:250
CommentList comments
Definition: argsparser.h:203
SectionDef(ArgLexer *lexer, ASTNode *parent)
Definition: argsparser.cpp:773
std::vector< SectionDef * > sections
Definition: argsparser.h:241
static const char * typeString(ArgTokenType type)
Definition: argsparser.cpp:33
std::vector< String > StringVector
Definition: xmipp_strings.h:35
#define i
void read(int argc, const char **argv, bool reportErrors=true)
Read and validate commmand line.
Definition: argsparser.cpp:951
bool starred
Some special mark to tokens.
Definition: argsparser.h:85
StringVector requires
Definition: argsparser.h:205
ProgTransformDimRed * prog
void addParamName(const String &name, ParamDef *param)
Definition: argsparser.cpp:912
ArgLexer * pLexer
Definition: argsparser.h:150
ASTNode(ArgLexer *lexer=NULL, ASTNode *parent=NULL)
Definition: argsparser.cpp:349
ArgTokenType
Definition: argsparser.h:43
void addParamDef(ParamDef *param)
Add a param to the section.
Definition: argsparser.cpp:762
ArgToken * currentToken() const
Definition: argsparser.cpp:337
int visible
Definition: argsparser.h:153
if(fabs(c[*nmax+ *nmax *c_dim1])==0.e0)
viol index
viol type
Incorrect argument received.
Definition: xmipp_error.h:113
ParamDef(ArgLexer *lexer, ASTNode *parent)
Definition: argsparser.cpp:522
std::vector< ParamDef * > subParams
Definition: argsparser.h:175
bool nextToken()
Definition: argsparser.cpp:164
virtual void check(std::stringstream &errors)
Definition: argsparser.cpp:883
void error(String msg)
Definition: argsparser.cpp:406
__host__ __device__ float length(float2 v)
virtual bool parse()
Definition: argsparser.cpp:558
std::vector< const char * > cmdArguments
Definition: argsparser.h:199
std::vector< ArgumentDef * > arguments
Definition: argsparser.h:198
StringVector pendingRequires
This is for checking that requires names exists.
Definition: argsparser.h:245
bool independent
Definition: argsparser.h:197
bool parseParamList(ArgTokenType startToken, ProgramDef *prog, StringVector &paramList, bool addName)
Definition: argsparser.cpp:668
void addOcurrence(std::map< String, int > &map, const String &name)
Definition: argsparser.cpp:849
#define j
ArgToken * currentToken() const
Definition: argsparser.cpp:366
String argDefault
Definition: argsparser.h:172
struct _parameter * param
void error(char *s)
Definition: tools.cpp:107
std::vector< ParamDef * > params
All params defined for the program.
Definition: argsparser.h:224
virtual bool parse()
Definition: argsparser.cpp:434
virtual bool parse()
Definition: argsparser.cpp:825
std::string String
Definition: xmipp_strings.h:34
void addParamExclusiveGroup(ParamDef *param)
Definition: argsparser.cpp:925
void reportExclusiveErrors(std::stringstream &errors, std::vector< ParamDef *> &exclusive)
Definition: argsparser.cpp:857
String formatString(const char *format,...)
bool containsArgument(const String &argName)
Definition: argsparser.cpp:537
ArgumentDef(ArgLexer *lexer, ASTNode *parent)
Definition: argsparser.cpp:421
const char * getParam(const char *paramName, size_t paramNumber=0)
int line
line where token was found
Definition: argsparser.h:77
virtual bool parse()
Definition: argsparser.cpp:783
ArgToken token
Definition: argsparser.h:151
ArgumentDef * findArgument(const String &argName)
Definition: argsparser.cpp:542
void addComment(const String &comment, int visible=0, bool wikiVerbatim=false)
SectionDef * addSection(String sectionName, int visibility=0)
int counter
for count the number of times it appears in command line
Definition: argsparser.h:201
void unexpectedToken(String msg="")
Definition: argsparser.cpp:413
String nextToken(const String &str, size_t &i)
void addLine(const String &line)
Definition: argsparser.cpp:99
bool orBefore
Definition: argsparser.h:196
String lexeme
the string literal value of the token
Definition: argsparser.h:76
bool parseArgumentList()
Definition: argsparser.cpp:642
ArgTokenType lookahead() const
Definition: argsparser.cpp:356
std::map< String, ParamDef * > paramsMap
Dictionary with all params and alias names.
Definition: argsparser.h:244
bool containsAlias(const String &alias)
Definition: argsparser.cpp:550
StringVector aliases
Definition: argsparser.h:204