ARTS  2.0.49
parser.cc
Go to the documentation of this file.
1 /* Copyright (C) 2008 Oliver Lemke <olemke@core-dump.info>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA. */
17 
18 #include <iostream>
19 #include "parser.h"
20 #include "arts.h"
21 #include "exceptions.h"
22 #include "file.h"
23 #include "methods.h"
24 #include "parameters.h"
25 #include "wsv_aux.h"
26 #include "workspace_ng.h"
27 
28 
36 ArtsParser::ArtsParser(Agenda& tasklist, String controlfile, const Verbosity& rverbosity)
37  : mtasklist (tasklist), mcfile (controlfile), mcfile_version (1), verbosity (rverbosity)
38 {
40 }
41 
42 
48 {
49  parse_main ();
50 }
51 
52 
59 {
62 
63  try
64  {
65  extern const Array<MdRecord> md_data;
66 
67  // For method ids:
68  Index id;
69  // Output workspace variables (for generic methods):
70  ArrayOfIndex output;
71  // Input workspace variables (for generic methods):
72  ArrayOfIndex input;
73  // For include statements, holding the include file's name
74  String include_file;
75 
76  ArrayOfIndex auto_vars;
77  Array<TokVal> auto_vars_values;
78 
79  out3 << "\nParsing control text:\n";
80 
81  msource.Init();
83 
84  parse_method(id,output,input,mtasklist,auto_vars,auto_vars_values,
85  include_file,true);
86 
87  if ( "Arts" != md_data[id].Name() && "Arts2" != md_data[id].Name() )
88  {
89  out0 << "The outermost agenda must be Arts2!\n"
90  << "(But it seems to be " << md_data[id].Name() << ".)\n";
91  arts_exit ();
92  }
93 
94  try {
96  if (!msource.reachedEot()) throw UnexpectedChar("",
97  msource.File(),
98  msource.Line(),
99  msource.Column() );
100  }
101  catch (const Eot&)
102  {
103  // It's ok to reach the end of the file here,
104  // that's actually what we want.
105  }
106  catch (const UnexpectedChar& x)
107  {
108  out0 << "Unexpected character(s) at the end of the control file\n";
109  out0 << "after the main agenda was already closed.\n";
110  out0 << "File: " << x.file() << '\n';
111  out0 << "Line: " << x.line() << '\n';
112  out0 << "Column: " << x.column() << '\n';
113  arts_exit ();
114  }
115  }
116  catch (const Eot& x)
117  {
118  // Unexpected end of the source text:
119  out0 << "Unexpected end of control script.\n";
120  out0 << "File: " << x.file() << '\n';
121  out0 << "Line: " << x.line() << '\n';
122  arts_exit ();
123  }
124  catch (const UnexpectedChar& x)
125  {
126  // Unexpected Character:
127  out0 << "Unexpected character:\n";
128  out0 << x.what() << '\n';
129  out0 << "File: " << x.file() << '\n';
130  out0 << "Line: " << x.line() << '\n';
131  out0 << "Column: " << x.column() << '\n';
132  arts_exit ();
133  }
134  catch (const IllegalLinebreak& x)
135  {
136  // A line break in an illegal position:
137  out0 << "Illegal Line break:\n";
138  out0 << x.what() << '\n';
139  out0 << "File: " << x.file() << '\n';
140  out0 << "Line: " << x.line() << '\n';
141  arts_exit ();
142  }
143  catch (const UnknownMethod& x)
144  {
145  // Method unknown:
146  // [**This should give a hint on how to obtain a list of allowed
147  // methods.]
148  out0 << "Unknown Method:\n";
149  out0 << x.what() << '\n';
150  out0 << "File: " << x.file() << '\n';
151  out0 << "Line: " << x.line() << '\n';
152  out0 << "Column: " << x.column() << '\n';
153  arts_exit ();
154  }
155  catch (const UnknownWsv& x)
156  {
157  // Workspace variable unknown:
158  // [**This should give a hint on how to obtain a list of allowed
159  // Wsvs.]
160  out0 << "Unknown workspace variable:\n";
161  out0 << x.what() << '\n';
162  out0 << "File: " << x.file() << '\n';
163  out0 << "Line: " << x.line() << '\n';
164  out0 << "Column: " << x.column() << '\n';
165  arts_exit ();
166  }
167  catch (const WsvAlreadyExists& x)
168  {
169  // Trying to create the same variable twice:
170  out0 << "Attempt to create a workspace variable that already exists:\n";
171  out0 << x.what() << '\n';
172  out0 << "File: " << x.file() << '\n';
173  out0 << "Line: " << x.line() << '\n';
174  out0 << "Column: " << x.column() << '\n';
175  arts_exit ();
176  }
177  catch (const WrongWsvGroup& x)
178  {
179  // Workspace variable unknown:
180  // [**This should give a hint on how to obtain a list of Wsvs in
181  // this group.
182  out0 << "Workspace variable belongs to the wrong group:\n";
183  out0 << x.what() << '\n';
184  out0 << "File: " << x.file() << '\n';
185  out0 << "Line: " << x.line() << '\n';
186  out0 << "Column: " << x.column() << '\n';
187  arts_exit ();
188  }
189  catch (const ParseError& x)
190  {
191  // General Parse Error (parent of all the above):
192  out0 << "Parse error:\n";
193  out0 << x.what() << '\n';
194  out0 << "File: " << x.file() << '\n';
195  out0 << "Line: " << x.line() << '\n';
196  out0 << "Column: " << x.column() << '\n';
197  arts_exit ();
198  }
199 }
200 
201 
216 {
219 
220  extern const Array<MdRecord> md_data;
221 
222  // For method ids:
223  Index id;
224  // Output workspace variables:
225  ArrayOfIndex output;
226  // Input workspace variables:
227  ArrayOfIndex input;
228  // For Agenda, if there is any:
229  Agenda tasks;
230  // For include statements, holding the include file's name
231  String include_file;
232 
233  ArrayOfIndex auto_vars;
234  Array<TokVal> auto_vars_values;
235 
236  eat_whitespace();
237 
238  while ( '}' != msource.Current() )
239  {
240  parse_method(id,output,input,tasks,
241  auto_vars,auto_vars_values,include_file);
242 
243  // If parse_method found an include statement it returnes -1 for the
244  // method id
245  if (id == -1)
246  {
247  // Command line parameters which give us the include search path.
248  extern const Parameters parameters;
249 
250  if (!find_file (include_file, ".arts"))
251  {
252  ostringstream os;
253  os << "Cannot find include file " << include_file
254  << ".\n";
255  os << "File: " << msource.File() << '\n';
256  os << "Search path was: . " << parameters.includepath
257  << "\n";
258  throw runtime_error (os.str());
259  }
260 
261  out2 << "- Including control file " << include_file << "\n";
262 
263  ArtsParser include_parser (tasks, include_file, verbosity);
264  include_parser.parse_tasklist();
265 
266  for (Index i = 0; i < tasks.nelem(); i++)
267  tasklist.push_back (tasks.Methods()[i]);
268  }
269  else
270  {
271  if (md_data[id].SetMethod())
272  {
273  // Append task to task list:
274  tasklist.push_back(MRecord(id,output,input,
275  auto_vars_values[0],tasks));
276  }
277  else
278  {
279  tasklist_insert_set_delete(auto_vars, auto_vars_values,
280  0, tasklist);
281 
282  // Append task to task list:
283  tasklist.push_back(MRecord(id,output,input,TokVal(),tasks));
284 
285  tasklist_insert_set_delete(auto_vars, auto_vars_values,
286  1, tasklist);
287  }
288 
289  {
290  // Everything in this block is just to generate some
291  // informative output.
292 
293  out3 << "- " << md_data[id].Name() << "\n";
294 
295  // Output workspace variables for generic methods:
296  if ( 0 < md_data[id].GOutType().nelem()
297  + md_data[id].GInType().nelem() )
298  {
299  out3 << " Output: ";
300  for ( Index j=0 ; j<output.nelem() ; ++j )
301  {
302  out3 << Workspace::wsv_data[output[j]].Name() << " ";
303  }
304  out3 << "\n";
305 
306  out3 << " Input: ";
307  for ( Index j=0 ; j<input.nelem() ; ++j )
308  {
309  out3 << Workspace::wsv_data[input[j]].Name() << " ";
310  }
311  out3 << "\n";
312  }
313  }
314  }
315 
316  eat_whitespace();
317  }
318 }
319 
320 
353  ArrayOfIndex& output,
354  ArrayOfIndex& input,
355  Agenda& tasks,
356  ArrayOfIndex& auto_vars,
357  Array<TokVal>& auto_vars_values,
358  String& include_file,
359  bool no_eot)
360 {
362 
363  String methodname; // We need this out here, since it is
364  // set once and later modified.
365 
366  const MdRecord* mdd; // Handle on the method record. Needed here,
367  // because it is modified.
368 
369  bool found_curly_brace = false;
370 
371  // Clear all output variables:
372  id = 0;
373  output.resize( 0 );
374  input.resize( 0 );
375  tasks.resize( 0 );
376  auto_vars.resize( 0 );
377  auto_vars_values.resize( 0 );
378  include_file = "";
379 
380  read_name(methodname);
381 
382  if (methodname == "INCLUDE")
383  {
384  eat_whitespace ();
385  parse_String (include_file);
386 
387  id = -1;
388 
389  return;
390  }
391  else
392  {
393  if (methodname == "Arts2")
394  {
395  mcfile_version = 2;
396  }
397  else if (methodname == "Arts")
398  {
399  throw runtime_error("Arts version 1 controlfiles are no longer supported.");
400  }
401 
402  eat_whitespace();
403 
404  parse_method_args(mdd, id, methodname, output, input,
405  auto_vars, auto_vars_values);
406 
407  eat_whitespace();
408 
409  // Now look for the curly braces:
410  if (msource.Current() == '{')
411  {
413  eat_whitespace();
414  found_curly_brace = true;
415  }
416 
417  // There are two kind of methods, agenda methods, which have other
418  // methods in the body, and normal methods, expecting keywords and
419  // values. Let's take the agenda case first...
420  if ( mdd->AgendaMethod() )
421  {
422  out3 << "- " << mdd->Name() << "\n";
423  out3 << "{\n";
424  parse_agenda(tasks);
425  out3 << "}\n";
426  }
427 
428  // Curly braces in non-agenda methods are not valid in v2 controlfiles
429  if (mcfile_version == 2 && !mdd->AgendaMethod() && found_curly_brace)
430  {
431  ostringstream os;
432  os << "Expected method name , but got `" << msource.Current() << "'.";
433  throw UnexpectedChar( os.str(),
434  msource.File(),
435  msource.Line(),
436  msource.Column() );os << "" << endl;
437  }
438  }
439 
440  // Now look for the closing curly braces. We have to catch Eot,
441  // because after a method description may be a good place to end
442  // the control file.
443  if (found_curly_brace)
444  {
445  try
446  {
447  assertain_character('}');
448  }
449  catch (const Eot x)
450  {
451  // Re-throw the error if the no_eot flag is not set:
452  if (!no_eot) throw Eot(x);
453  }
454  }
455 }
456 
457 
459 
474  ArrayOfIndex& auto_vars,
475  Array<TokVal>& auto_vars_values,
476  Index gin_index)
477 {
478  String name;
479 
480  if (mdd->GInDefault()[gin_index] != NODEF)
481  {
482  TokVal tv;
483  // Now parse the key value. This can be:
484  // String, Index, Numeric, ArrayOfString, ArrayOfIndex, Vector
485  bool failed = false;
486  if (mdd->GInType()[gin_index] == get_wsv_group_id ("String"))
487  {
488  tv = mdd->GInDefault()[gin_index];
489  }
490  else if (mdd->GInType()[gin_index] == get_wsv_group_id ("Index"))
491  {
492  Index n;
493  istringstream is(mdd->GInDefault()[gin_index]);
494  is >> n;
495  tv = n;
496  if (is.bad () || is.fail ())
497  failed = true;
498  }
499  else if (mdd->GInType()[gin_index] == get_wsv_group_id ("Numeric"))
500  {
501  Numeric n;
502  istringstream is(mdd->GInDefault()[gin_index]);
503  is >> n;
504  tv = n;
505  if (is.bad () || is.fail ())
506  failed = true;
507  }
508  else if (mdd->GInType()[gin_index] == get_wsv_group_id ("ArrayOfString"))
509  {
510  ArrayOfString v;
511  String s = mdd->GInDefault()[gin_index];
513  {
514  failed = true;
515  }
516  tv = v;
517  }
518  else if (mdd->GInType()[gin_index] == get_wsv_group_id ("Vector"))
519  {
520  Vector v;
521  String s = mdd->GInDefault()[gin_index];
522  if (!parse_numvector_from_string(v, s))
523  {
524  failed = true;
525  }
526  tv = v;
527  }
528  else
529  {
530  extern const ArrayOfString wsv_group_names;
531  ostringstream os;
532  os
533  << "Default values for generic inputs with type "
534  << wsv_group_names[mdd->GInType()[gin_index]] << " are not supported.\n"
535  << "Either remove the default value for generic input '"
536  << mdd->GIn()[gin_index] << "' in workspace method\n"
537  << "*" << mdd->Name() << "* in methods.cc or discuss this "
538  << "issue on the arts-dev mailing list.\n";
539  throw ParseError (os.str(),
540  msource.File(),
541  msource.Line(),
542  msource.Column());
543  }
544 
545  Index wsvid;
546 
547  {
548  ostringstream os;
549  os << gin_index;
550 
551  name = "auto_" + mdd->Name() + "_" + "gin" + os.str() + "_"
552  + mdd->GIn()[gin_index];
553  }
554 
555  map<String, Index>::const_iterator wsvit =
556  Workspace::WsvMap.find(name);
557  if (wsvit == Workspace::WsvMap.end())
558  {
559  wsvid = Workspace::add_wsv(
560  WsvRecord(name.c_str(),
561  "Automatically allocated variable.",
562  mdd->GInType()[gin_index],
563  true));
564  }
565  else
566  {
567  wsvid = wsvit->second;
568  }
569 
570  auto_vars.push_back(wsvid);
571  auto_vars_values.push_back(tv);
572 
573  if (failed)
574  {
575  ostringstream os;
576  os << "Failed to assign default value for generic '"
577  << mdd->GIn()[gin_index] << "'.\n"
578  << "Check the documentation of workspace method *"
579  << mdd->Name() << "*.\n";
580  throw ParseError (os.str(),
581  msource.File(),
582  msource.Line(),
583  msource.Column());
584  }
585  }
586  else
587  {
588  ostringstream os;
589  os << "Generic input '" << mdd->GIn()[gin_index]
590  << "' omitted but no default value found.\n"
591  << "Check the documentation of workspace method *"
592  << mdd->Name() << "*.\n";
593  throw ParseError (os.str(),
594  msource.File(),
595  msource.Line(),
596  msource.Column());
597  }
598 
599  return name;
600 }
601 
602 
604 
618  Index& id,
619  String& methodname,
620  ArrayOfIndex& output,
621  ArrayOfIndex& input,
622  ArrayOfIndex& auto_vars,
623  Array<TokVal>& auto_vars_values)
624 {
625  extern const map<String, Index> MdRawMap;
626  extern const Array<MdRecord> md_data;
627  extern const Array<MdRecord> md_data_raw;
628  extern const map<String, Index> MdMap;
629 
630  bool still_supergeneric=true; // Flag that our MdRecord still is
631  // from md_data_raw, not from
632  // md_data.
633 
634  // Find method raw id in raw map:
635  const map<String, Index>::const_iterator i = MdRawMap.find(methodname);
636  if ( i == MdRawMap.end() )
637  throw UnknownMethod(methodname,
638  msource.File(),
639  msource.Line(),
640  msource.Column());
641 
642  id = i->second;
643 
644  // Get a convenient handle on the data record for this method. We
645  // have to use a pointer here, not a reference, because we later
646  // want to change where mdd is pointing!
647  mdd = &md_data_raw[id];
648 
649  // Is this a supergeneric method? If not, take the record in
650  // md_data, rather than in md_data_raw:
651  if ( !mdd->Supergeneric() )
652  {
653  // Find explicit method id in MdMap:
654  const map<String, Index>::const_iterator i2 = MdMap.find(methodname);
655  assert ( i2 != MdMap.end() );
656  id = i2->second;
657 
658  mdd = &md_data[id];
659 
660  still_supergeneric = false;
661  }
662 
663  if (msource.Current() == '(')
664  {
665  bool first = true; // To skip the first comma.
666  String supergeneric_args;
667  Index supergeneric_index = -1;
668 
670  eat_whitespace();
671 
672  parse_specific_output(mdd, output, first);
673 
674  parse_generic_output(mdd, id, methodname, output,
675  first, still_supergeneric, supergeneric_args,
676  supergeneric_index);
677 
678  parse_specific_input(mdd, input, auto_vars, auto_vars_values, first);
679 
680  parse_generic_input(mdd, id, methodname, input,
681  auto_vars, auto_vars_values,
682  first, still_supergeneric, supergeneric_args,
683  supergeneric_index);
684 
685  assert(!still_supergeneric);
686  assertain_character(')');
687  }
688  else
689  {
690  // If the parenthesis were omitted we still have to add the implicit
691  // outputs and inputs to the methods input and output variable lists
692  ArrayOfIndex vo=mdd->Out();
693  for (ArrayOfIndex::const_iterator outs=vo.begin();
694  outs<vo.end(); ++outs)
695  {
696  output.push_back (*outs);
697  }
698 
699  const ArrayOfIndex &vi = mdd->InOnly();
700  for (ArrayOfIndex::const_iterator ins=vi.begin(); ins<vi.end(); ++ins)
701  {
702  input.push_back (*ins);
703  }
704 
705  {
706  // Make sure all keywords have default values, otherwise the
707  // user has to specify them in the controlfile.
708  bool all_gin_have_defaults = true;
709  for (Index gin = 0;
710  all_gin_have_defaults && gin < mdd->GIn().nelem();
711  ++gin)
712  {
713  Index wsvid; // Workspace variable id, is used to
714  // access data in wsv_data.
715 
716  if (mdd->GInDefault()[gin] == NODEF)
717  all_gin_have_defaults = false;
718  else
719  {
720  String wsvname;
721  wsvname = set_gin_to_default(mdd, auto_vars,
722  auto_vars_values, gin);
723  {
724  // Find Wsv id:
725  const map<String, Index>::const_iterator wsvit =
726  Workspace::WsvMap.find(wsvname);
727  if ( wsvit == Workspace::WsvMap.end() )
728  {
729  throw UnknownWsv( wsvname,
730  msource.File(),
731  msource.Line(),
732  msource.Column() );
733  }
734 
735  wsvid = wsvit->second;
736  }
737  input.push_back(wsvid);
738  }
739  }
740 
741  if (!all_gin_have_defaults)
742  {
743  ostringstream os;
744  os << "Not all generic inputs of this method have default "
745  << "values, you have to specify them!";
746  throw UnexpectedChar( os.str(),
747  msource.File(),
748  msource.Line(),
749  msource.Column() );
750  }
751  }
752  }
753 }
754 
755 
773  Index& id,
774  String& methodname,
775  ArrayOfIndex& input,
776  ArrayOfIndex& auto_vars,
777  Array<TokVal>& auto_vars_values,
778  bool& first,
779  bool& still_supergeneric,
780  String& supergeneric_args,
781  Index& supergeneric_index _U_)
782 {
783  String wsvname;
784  Index wsvid;
785  extern const ArrayOfString wsv_group_names;
786  extern const Array<MdRecord> md_data;
787  extern const map<String, Index> MdMap;
788 
789  // Then parse all generic input variables
790  for ( Index j=0 ; j<mdd->GInType().nelem() ; ++j )
791  {
792  if (first)
793  first = false;
794  else
795  {
796  if (msource.Current() != ')')
797  {
798  assertain_character(',');
799  eat_whitespace();
800  }
801  }
802 
803  // If there is a comma or a closing brace means no value was
804  // specified and we use the default value instead (if there is one)
805  if (msource.Current() == ',' || msource.Current() == ')')
806  {
807  wsvname = set_gin_to_default(mdd, auto_vars, auto_vars_values, j);
808  }
809  else
810  {
811  ostringstream os;
812  os << j;
813  if (read_name_or_value(wsvname, auto_vars, auto_vars_values,
814  "generic" + os.str(),
815  mdd, mdd->GInType()[j]) == -1
816  && mdd->SetMethod())
817  {
818  throw ParseError("Only constants can be passed to Set methods.\n"
819  "You might want to use the *Copy* here.",
820  msource.File(),
821  msource.Line(),
822  msource.Column() );
823  }
824  }
825 
826  {
827  // Find Wsv id:
828  const map<String, Index>::const_iterator wsvit =
829  Workspace::WsvMap.find(wsvname);
830  if ( wsvit == Workspace::WsvMap.end() )
831  {
832  throw UnknownWsv( wsvname,
833  msource.File(),
834  msource.Line(),
835  msource.Column() );
836  }
837 
838  wsvid = wsvit->second;
839  }
840 
841  // Is the method data record still supergeneric? This could
842  // be the case if there are no output arguments, only input
843  // arguments. In that case, let's find out the actual group!
844  if ( still_supergeneric )
845  {
846  ostringstream os;
847  if (wsv_group_names[mdd->GInType()[j]] == "Any")
848  supergeneric_args +=
849  wsv_group_names[Workspace::wsv_data[wsvid].Group()];
850  os << mdd->Name() << "_sg_" << supergeneric_args;
851  methodname = os.str();
852 
853  // Find explicit method id in MdMap:
854  const map<String, Index>::const_iterator mdit =
855  MdMap.find(methodname);
856  if (mdit != MdMap.end())
857  {
858  id = mdit->second;
859 
860  mdd = &md_data[id];
861 
862  still_supergeneric = false;
863  }
864  }
865 
866  // Now we have explicitly the method record for the right
867  // group. From now on no special treatment of supergeneric
868  // methods should be necessary.
869 
870  // Check that this Wsv belongs to the correct group:
871  if (mdd->GInType()[j] == get_wsv_group_id ("Any")
872  && mdd->GInSpecType()[j].nelem() )
873  {
874  if (supergeneric_index == -1)
875  {
876  bool wrong_group_id = true;
877  for (Index i = 0; wrong_group_id && i < mdd->GInSpecType()[j].nelem(); i++)
878  {
879  if (Workspace::wsv_data[wsvid].Group()
880  == mdd->GInSpecType()[j][i])
881  {
882  wrong_group_id = false;
883  supergeneric_index = i;
884  }
885  }
886 
887  if (wrong_group_id)
888  {
889  ostringstream os;
890  bool firsttype = true;
891  for (Index i = 0; i < mdd->GInSpecType()[j].nelem(); i++)
892  {
893  if (!firsttype) os << ", "; else firsttype = false;
894  os << wsv_group_names[mdd->GInSpecType()[j][i]];
895  }
896 
897  throw WrongWsvGroup( "*" + mdd->Name()+"* is not defined for "
898  +wsv_group_names[Workspace::wsv_data[wsvid].Group()]
899  +" input. Check the online docs.",
900  msource.File(),
901  msource.Line(),
902  msource.Column() );
903  }
904  }
905  else
906  {
907  if (Workspace::wsv_data[wsvid].Group()
908  != mdd->GInSpecType()[j][supergeneric_index])
909  {
910  throw WrongWsvGroup( wsvname+" is not "+
911  wsv_group_names[mdd->GInSpecType()[j][supergeneric_index]]
912  +", it is "+
913  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
914  msource.File(),
915  msource.Line(),
916  msource.Column());
917  }
918  }
919  }
920  else if (Workspace::wsv_data[wsvid].Group() != mdd->GInType()[j])
921  {
922  throw WrongWsvGroup( wsvname+" is not "+
923  wsv_group_names[mdd->GInType()[j]]+", it is "+
924  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
925  msource.File(),
926  msource.Line(),
927  msource.Column() );
928  }
929 
930  // Add this one to the list of input variables:
931  input.push_back(wsvid);
932 
933  eat_whitespace();
934  }
935 
936 }
937 
938 
954  Index& id,
955  String& methodname,
956  ArrayOfIndex& output,
957  bool& first,
958  bool& still_supergeneric,
959  String& supergeneric_args,
960  Index& supergeneric_index)
961 {
962  String wsvname;
963  Index wsvid;
964  extern const ArrayOfString wsv_group_names;
965  extern const Array<MdRecord> md_data;
966  extern const map<String, Index> MdMap;
967 
968  // Parse all generic output variables
969  for ( Index j=0 ; j<mdd->GOut().nelem() ; ++j )
970  {
971  if (first)
972  first = false;
973  else
974  {
975  assertain_character(',');
976  eat_whitespace();
977  }
978 
979  read_name(wsvname);
980 
981  {
982  wsvid = -1;
983  // Find Wsv id:
984  map<String, Index>::const_iterator wsvit =
985  Workspace::WsvMap.find(wsvname);
986  if ( wsvit == Workspace::WsvMap.end() )
987  {
988  if (still_supergeneric)
989  {
990  ostringstream os;
991  os << "This might be either a typo or you have to create "
992  << "the variable\nby calling TYPECreate(" << wsvname
993  << ") first. Replace TYPE with the\n"
994  << "WSV group your variable should belong to.";
995 
996  throw UnknownWsv( os.str(),
997  msource.File(),
998  msource.Line(),
999  msource.Column() );
1000  }
1001  else
1002  {
1003  if (mdd->Name().length() > 6
1004  && mdd->Name().substr (mdd->Name().length() - 6)
1005  != "Create")
1006  {
1007  ostringstream os;
1008  os << "This might be either a typo or you have to create "
1009  << "the variable\nby calling "
1010  << wsv_group_names[mdd->GOutType()[j]]
1011  << "Create( " << wsvname
1012  << " ) first.\n";
1013 
1014  throw UnknownWsv( os.str(),
1015  msource.File(),
1016  msource.Line(),
1017  msource.Column() );
1018  }
1019  else
1020  {
1021  wsvid = Workspace::add_wsv(
1022  WsvRecord(wsvname.c_str(),
1023  "Automatically allocated variable.",
1024  mdd->GOutType()[j],
1025  true));
1026  }
1027  }
1028  }
1029 
1030  if (wsvid == -1)
1031  {
1032  if (mdd->Name().length() > 6 &&
1033  mdd->Name().find ("Create") == mdd->Name().length() - 6)
1034  {
1035  ostringstream os;
1036  os << wsvname << " already exists. A variable can only be created once.\n";
1037  throw WsvAlreadyExists( os.str(),
1038  msource.File(),
1039  msource.Line(),
1040  msource.Column() );
1041  }
1042  wsvid = wsvit->second;
1043  }
1044  }
1045 
1046  // If this is a supergeneric method, now is the time to find
1047  // out the actual group of the argument(s)!
1048  // If the method also has supergeneric input arguments, we'll
1049  // look for a match later again.
1050  if ( still_supergeneric )
1051  {
1052  ostringstream os;
1053  if (wsv_group_names[mdd->GOutType()[j]] == "Any")
1054  supergeneric_args +=
1055  wsv_group_names[Workspace::wsv_data[wsvid].Group()];
1056  os << mdd->Name() << "_sg_" << supergeneric_args;
1057  methodname = os.str();
1058 
1059  // Find explicit method id in MdMap:
1060  const map<String, Index>::const_iterator mdit = MdMap.find(methodname);
1061  if (mdit != MdMap.end() )
1062  {
1063  id = mdit->second;
1064 
1065  mdd = &md_data[id];
1066 
1067  still_supergeneric = false;
1068  }
1069  }
1070 
1071  // Now we have explicitly the method record for the right
1072  // group. From now on no special treatment of supergeneric
1073  // methods should be necessary.
1074 
1075  // Check that this Wsv belongs to the correct group:
1076  if (mdd->GOutType()[j] == get_wsv_group_id ("Any")
1077  && mdd->GOutSpecType()[j].nelem() )
1078  {
1079  if (supergeneric_index == -1)
1080  {
1081  bool wrong_group_id = true;
1082  for (Index i = 0; wrong_group_id && i < mdd->GOutSpecType()[j].nelem(); i++)
1083  {
1084  if (Workspace::wsv_data[wsvid].Group()
1085  == mdd->GOutSpecType()[j][i])
1086  {
1087  wrong_group_id = false;
1088  supergeneric_index = i;
1089  }
1090  }
1091 
1092  if (wrong_group_id)
1093  {
1094  ostringstream os;
1095  bool firsttype = true;
1096  for (Index i = 0; i < mdd->GOutSpecType()[j].nelem(); i++)
1097  {
1098  if (!firsttype) os << ", "; else firsttype = false;
1099  os << wsv_group_names[mdd->GOutSpecType()[j][i]];
1100  }
1101 
1102  throw WrongWsvGroup( "*" + mdd->Name() + "* is not defined for "
1103  +wsv_group_names[Workspace::wsv_data[wsvid].Group()]
1104  +" output. Check the online docs.",
1105  msource.File(),
1106  msource.Line(),
1107  msource.Column() );
1108  }
1109  }
1110  else
1111  {
1112  if (Workspace::wsv_data[wsvid].Group()
1113  != mdd->GOutSpecType()[j][supergeneric_index])
1114  {
1115  throw WrongWsvGroup( wsvname+" is not "+
1116  wsv_group_names[mdd->GOutSpecType()[j][supergeneric_index]]
1117  +", it is "+
1118  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
1119  msource.File(),
1120  msource.Line(),
1121  msource.Column());
1122  }
1123  }
1124  }
1125  else if ( Workspace::wsv_data[wsvid].Group() != mdd->GOutType()[j] )
1126  {
1127  throw WrongWsvGroup( wsvname+" is not "+
1128  wsv_group_names[mdd->GOutType()[j]]+", it is "+
1129  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
1130  msource.File(),
1131  msource.Line(),
1132  msource.Column() );
1133  }
1134 
1135  // Add this one to the list of output workspace variables:
1136  output.push_back(wsvid);
1137 
1138  eat_whitespace();
1139  }
1140 }
1141 
1142 
1156  ArrayOfIndex& input,
1157  ArrayOfIndex& auto_vars,
1158  Array<TokVal>& auto_vars_values,
1159  bool& first)
1160 {
1161  extern const ArrayOfString wsv_group_names;
1162 
1163  // There are two lists of parameters that we have to read.
1164  ArrayOfIndex vo=mdd->Out(); // Output
1165  const ArrayOfIndex &vi = mdd->InOnly(); // Input
1166 
1167  Index wsvid; // Workspace variable id, is used to
1168  // access data in wsv_data.
1169 
1170  for (ArrayOfIndex::const_iterator ins=vi.begin(); ins<vi.end(); ++ins)
1171  {
1172  String wsvname;
1173 
1174  if (first)
1175  first = false;
1176  else
1177  {
1178  try
1179  {
1180  assertain_character(',');
1181  }
1182  catch (UnexpectedChar)
1183  {
1184  ostringstream os;
1185  os << "Expected input WSV *" << Workspace::wsv_data[*ins].Name() << "*";
1186  }
1187  eat_whitespace();
1188  }
1189 
1190  read_name_or_value(wsvname, auto_vars, auto_vars_values,
1191  Workspace::wsv_data[*ins].Name(),
1192  mdd, Workspace::wsv_data[*ins].Group());
1193 
1194  {
1195  // Find Wsv id:
1196  const map<String, Index>::const_iterator wsvit =
1197  Workspace::WsvMap.find(wsvname);
1198  if ( wsvit == Workspace::WsvMap.end() )
1199  throw UnknownWsv( wsvname,
1200  msource.File(),
1201  msource.Line(),
1202  msource.Column() );
1203 
1204  wsvid = wsvit->second;
1205  }
1206 
1207  // Check that this Wsv belongs to the correct group:
1208  if ( Workspace::wsv_data[wsvid].Group() != Workspace::wsv_data[*ins].Group() )
1209  {
1210  throw WrongWsvGroup( wsvname+" is not "+
1211  wsv_group_names[Workspace::wsv_data[*ins].Group()]+", it is "+
1212  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
1213  msource.File(),
1214  msource.Line(),
1215  msource.Column() );
1216  }
1217 
1218  input.push_back(wsvid);
1219  }
1220 
1221  eat_whitespace();
1222 }
1223 
1224 
1236  ArrayOfIndex& output,
1237  bool& first)
1238 {
1239  extern const ArrayOfString wsv_group_names;
1240 
1241  ArrayOfIndex vo=mdd->Out();
1242 
1243  Index wsvid; // Workspace variable id, is used to
1244  // access data in wsv_data.
1245 
1246  for (ArrayOfIndex::const_iterator outs=vo.begin(); outs<vo.end(); ++outs)
1247  {
1248  String wsvname;
1249 
1250  if (first)
1251  first = false;
1252  else
1253  {
1254  try
1255  {
1256  assertain_character(',');
1257  }
1258  catch (UnexpectedChar)
1259  {
1260  ostringstream os;
1261  os << "Expected output WSV *" << Workspace::wsv_data[*outs].Name() << "*";
1262  throw ParseError( os.str(),
1263  msource.File(),
1264  msource.Line(),
1265  msource.Column() );
1266  }
1267  eat_whitespace();
1268  }
1269 
1270  read_name(wsvname);
1271 
1272  {
1273  wsvid = -1;
1274  // Find Wsv id:
1275  map<String, Index>::const_iterator wsvit =
1276  Workspace::WsvMap.find(wsvname);
1277  if ( wsvit == Workspace::WsvMap.end() )
1278  {
1279  if (mdd->Name().length() > 6
1280  && mdd->Name().substr (mdd->Name().length() - 6)
1281  != "Create")
1282  {
1283  ostringstream os;
1284  os << "This might be either a typo or you have to create "
1285  << "the variable\nby calling "
1286  << wsv_group_names[Workspace::wsv_data[*outs].Group()]
1287  << "Create( " << wsvname
1288  << " ) first.\n";
1289 
1290  throw UnknownWsv( os.str(),
1291  msource.File(),
1292  msource.Line(),
1293  msource.Column() );
1294  }
1295  else
1296  {
1297  wsvid = Workspace::add_wsv(
1298  WsvRecord(wsvname.c_str(),
1299  "Automatically allocated variable.",
1300  Workspace::wsv_data[*outs].Group(),
1301  true));
1302  }
1303  }
1304 
1305  if (wsvid == -1)
1306  wsvid = wsvit->second;
1307  }
1308 
1309  // Check that this Wsv belongs to the correct group:
1310  if ( Workspace::wsv_data[wsvid].Group() != Workspace::wsv_data[*outs].Group() )
1311  {
1312  throw WrongWsvGroup( wsvname+" is not "+
1313  wsv_group_names[Workspace::wsv_data[*outs].Group()]+", it is "+
1314  wsv_group_names[Workspace::wsv_data[wsvid].Group()],
1315  msource.File(),
1316  msource.Line(),
1317  msource.Column() );
1318  }
1319 
1320  output.push_back(wsvid);
1321  }
1322 
1323  eat_whitespace();
1324 }
1325 
1326 
1341  const Array<TokVal>& auto_vars_values,
1342  const Index method_type,
1343  Agenda& tasklist)
1344 {
1345  extern const map<String, Index> MdMap;
1346  extern const ArrayOfString wsv_group_names;
1347 
1348  for (Index i=0; i<auto_vars.nelem(); i++)
1349  {
1350  map<String, Index>::const_iterator mdit;
1351  Index init_mdid;
1352  TokVal auto_keyword_value;
1353  ArrayOfIndex auto_output_var;
1354  ArrayOfIndex auto_input_var;
1355  Agenda auto_tasks;
1356 
1357  const Index auto_group = Workspace::wsv_data[auto_vars[i]].Group();
1358  if (auto_group != get_wsv_group_id("Index")
1359  && auto_group != get_wsv_group_id("Numeric")
1360  && auto_group != get_wsv_group_id("ArrayOfIndex")
1361  && auto_group != get_wsv_group_id("ArrayOfString")
1362  && auto_group != get_wsv_group_id("String")
1363  && auto_group != get_wsv_group_id("Vector")
1364  && auto_group != get_wsv_group_id("Matrix"))
1365  {
1366  ostringstream os;
1367  os << "Passing a "
1368  << wsv_group_names[Workspace::wsv_data[auto_vars[i]].Group()]
1369  << " constant to a WSM is not supported!";
1370  throw ParseError (os.str(),
1371  msource.File(),
1372  msource.Line(),
1373  msource.Column());
1374  }
1375 
1376  String method_name;
1377  switch (method_type)
1378  {
1379  case 0:
1380  auto_keyword_value = auto_vars_values[i];
1381  auto_output_var.push_back(auto_vars[i]);
1382  method_name = wsv_group_names[
1383  Workspace::wsv_data[auto_vars[i]].Group()] + "Set";
1384  break;
1385  case 1:
1386  auto_input_var.push_back(auto_vars[i]);
1387  method_name = "Delete_sg_" + wsv_group_names[Workspace::wsv_data[auto_vars[i]].Group()];
1388  break;
1389  default:
1390  throw runtime_error("Invalid method_type");
1391  }
1392 
1393  mdit = MdMap.find(method_name);
1394  assert ( mdit != MdMap.end() );
1395  init_mdid = mdit->second;
1396 
1397  tasklist.push_back(MRecord(init_mdid,
1398  auto_output_var, auto_input_var,
1399  auto_keyword_value,
1400  auto_tasks));
1401  }
1402 }
1403 
1404 
1415 bool ArtsParser::is_whitespace(const char c)
1416 {
1417  switch (c)
1418  {
1419  case ' ':
1420  case '\r':
1421  case '\t':
1422  case '#':
1423  return true;
1424  break;
1425  }
1426 
1427  return false;
1428 }
1429 
1430 
1441 {
1442  char dummy;
1443 
1444  while (is_whitespace(dummy=msource.Current()))
1445  {
1446  switch (dummy)
1447  {
1448  case ' ':
1449  case '\r':
1450  case '\t':
1451  msource.AdvanceChar();
1452  break;
1453  case '#':
1454  msource.AdvanceLine();
1455  break;
1456  default:
1457  {
1458  ostringstream os;
1459  os << "Expected whitespace, but got `" << dummy << "'.";
1460  throw UnexpectedChar( os.str(),
1461  msource.File(),
1462  msource.Line(),
1463  msource.Column() );
1464  break;
1465  }
1466  }
1467  }
1468 }
1469 
1470 
1477 {
1478  while (pos < str.length() && is_whitespace(str[pos]))
1479  pos++;
1480 }
1481 
1482 
1495 {
1496  bool stop = false;
1497  name = "";
1498 
1499  if (!isalpha(msource.Current()))
1500  {
1501  ostringstream os;
1502  os << "Workspace variable names must start with a letter!";
1503  throw ParseError( os.str(),
1504  msource.File(),
1505  msource.Line(),
1506  msource.Column() );
1507  }
1508 
1509  while (!stop)
1510  {
1511  char dummy = msource.Current();
1512 
1513  if ( isalnum(dummy) || '_'==dummy )
1514  {
1515  name += dummy;
1516  // AdvanceChar sets LineBreak if a line break occured.
1517  msource.LineBreak() = false;
1518  msource.AdvanceChar();
1519  if ( msource.LineBreak() ) stop = true;
1520  }
1521  else
1522  {
1523  stop = true;
1524  }
1525  }
1526 }
1527 
1528 
1549  ArrayOfIndex& auto_vars,
1550  Array<TokVal>& auto_vars_values,
1551  const String& default_name,
1552  const MdRecord* mdd,
1553  const Index group)
1554 {
1555  name = "";
1556 
1557  if (isalpha(msource.Current()))
1558  {
1559  read_name(name);
1560  return -1;
1561  }
1562 
1563  if (group == get_wsv_group_id ("Any"))
1564  {
1565  ostringstream os;
1566  os << "Passing constants as supergeneric parameters is not supported.";
1567  throw ParseError (os.str (),
1568  msource.File(),
1569  msource.Line(),
1570  msource.Column());
1571  }
1572 
1573  // If a value was given instead of a variable name, we create
1574  // a new variable in the workspace and fill it with the given
1575  // value
1576 
1577  Index wsvid;
1578 
1579  name = "auto_" + mdd->Name() + "_" + default_name;
1580  map<String, Index>::const_iterator wsvit = Workspace::WsvMap.find(name);
1581  if (wsvit == Workspace::WsvMap.end())
1582  {
1583  wsvid = Workspace::add_wsv(WsvRecord(name.c_str(),
1584  "Automatically allocated variable.",
1585  group,
1586  true));
1587  }
1588  else
1589  {
1590  wsvid = wsvit->second;
1591  }
1592 
1593  auto_vars.push_back(wsvid);
1594 
1595  // Now parse the value. This can be:
1596  // String_, Index_, Numeric_, Array_String_, Array_Index_, Vector_, Matrix_
1597  if (group == get_wsv_group_id("String"))
1598  {
1599  String dummy;
1600  parse_String(dummy);
1601  auto_vars_values.push_back(dummy);
1602  }
1603  else if (group == get_wsv_group_id("Index"))
1604  {
1605  Index n;
1606  parse_integer(n);
1607  auto_vars_values.push_back(n);
1608  }
1609  else if (group == get_wsv_group_id("Numeric"))
1610  {
1611  Numeric n;
1612  parse_numeric(n);
1613  auto_vars_values.push_back(n);
1614  }
1615  else if (group == get_wsv_group_id("ArrayOfString"))
1616  {
1617  ArrayOfString dummy;
1618  parse_Stringvector(dummy);
1619  auto_vars_values.push_back(dummy);
1620  }
1621  else if (group == get_wsv_group_id("ArrayOfIndex"))
1622  {
1623  ArrayOfIndex dummy;
1624  parse_intvector(dummy);
1625  auto_vars_values.push_back(dummy);
1626  }
1627  else if (group == get_wsv_group_id("Vector"))
1628  {
1629  Vector dummy;
1630  parse_numvector(dummy);
1631  auto_vars_values.push_back(dummy);
1632  }
1633  else if (group == get_wsv_group_id("Matrix"))
1634  {
1635  Matrix dummy;
1636  parse_matrix(dummy);
1637  auto_vars_values.push_back(dummy);
1638  }
1639  else
1640  {
1641  extern const ArrayOfString wsv_group_names;
1642  ostringstream os;
1643  os << "Unsupported parameter type: " << wsv_group_names[group];
1644  throw runtime_error (os.str());
1645  }
1646 
1647  return wsvid;
1648 }
1649 
1650 
1658 {
1659  if ( c != msource.Current() )
1660  {
1661  ostringstream os;
1662  os << "Expected '" << c << "', but got '" << msource.Current() << "'.";
1663  throw UnexpectedChar( os.str(),
1664  msource.File(),
1665  msource.Line(),
1666  msource.Column() );
1667  }
1668 
1669  msource.AdvanceChar();
1670 }
1671 
1672 
1684 {
1685  bool stop = false;
1686  res = "";
1687 
1688  msource.LineBreak() = false;
1689  assertain_character('"');
1690  if ( msource.LineBreak() )
1691  throw IllegalLinebreak( "Line break before end of String.",
1692  msource.File(),
1693  msource.Line(),
1694  msource.Column() );
1695 
1696  while (!stop)
1697  {
1698  char dummy = msource.Current();
1699  if ( dummy != '"' )
1700  {
1701  res += dummy;
1702  msource.AdvanceChar();
1703 
1704  if ( msource.LineBreak() )
1705  throw IllegalLinebreak( "Line break before end of String.",
1706  msource.File(),
1707  msource.Line(),
1708  msource.Column() );
1709  }
1710  else
1711  {
1712  stop = true;
1713  msource.AdvanceChar();
1714  }
1715  }
1716 }
1717 
1718 
1732 {
1733  bool stop = false;
1734  res = "";
1735  char dummy;
1736  msource.LineBreak() = false;
1737 
1738  dummy = msource.Current();
1739  if ( '+' == dummy || '-' == dummy )
1740  {
1741  res += dummy;
1742  msource.AdvanceChar();
1743  if ( msource.LineBreak() )
1744  throw IllegalLinebreak( "Line break after sign.",
1745  msource.File(),
1746  msource.Line(),
1747  msource.Column() );
1748  }
1749 
1750  if (!isdigit(msource.Current()))
1751  {
1752  ostringstream os;
1753  os << "Expected digit or variable name, but got `" << msource.Current()
1754  << "'.";
1755  throw UnexpectedChar(os.str(),
1756  msource.File(),
1757  msource.Line(),
1758  msource.Column());
1759  }
1760 
1761  while (!stop)
1762  {
1763  char chtmp = msource.Current();
1764  if ( isdigit(chtmp) )
1765  {
1766  res += chtmp;
1767  msource.AdvanceChar();
1768  if ( msource.LineBreak() ) stop = true;
1769  }
1770  else
1771  {
1772  stop = true;
1773  }
1774  }
1775 }
1776 
1777 
1794 {
1795  bool stop;
1796  res = "";
1797  char dummy;
1798  msource.LineBreak() = false;
1799 
1800  // To make sure that there is at least one digit:
1801  bool found_digit = false;
1802 
1803  // Check if there is a sign:
1804  dummy = msource.Current();
1805  if ( '+' == dummy || '-' == dummy )
1806  {
1807  res += dummy;
1808  msource.AdvanceChar();
1809  if ( msource.LineBreak() )
1810  throw IllegalLinebreak( "Linebreak after sign.",
1811  msource.File(),
1812  msource.Line(),
1813  msource.Column() );
1814  }
1815 
1816  // There could be some digits here:
1817  stop = false;
1818  while (!stop)
1819  {
1820  char chtmp = msource.Current();
1821  if ( isdigit(chtmp) )
1822  {
1823  found_digit = true;
1824  res += chtmp;
1825  msource.AdvanceChar();
1826  if ( msource.LineBreak() ) return; // Line break ends scanning immediately.
1827  }
1828  else
1829  {
1830  stop = true;
1831  }
1832  }
1833 
1834  // Next there can be a decimal point
1835  if ( '.' == msource.Current() )
1836  {
1837  res += ".";
1838  msource.AdvanceChar();
1839  if ( msource.LineBreak() )
1840  {
1841  if (found_digit)
1842  {
1843  // Line break ends scanning immediately, if we have
1844  // already found at least one digit.
1845  return;
1846  }
1847  else
1848  {
1849  throw IllegalLinebreak("Expected at least one digit.",
1850  msource.File(),
1851  msource.Line(),
1852  msource.Column());
1853  }
1854  }
1855 
1856  // ... followed by optional more digits
1857  stop = false;
1858  while (!stop)
1859  {
1860  char chtmp = msource.Current();
1861  if ( isdigit(chtmp) )
1862  {
1863  found_digit = true;
1864  res += chtmp;
1865  msource.AdvanceChar();
1866  if ( msource.LineBreak() ) return; // Line break ends scanning immediately.
1867  }
1868  else
1869  {
1870  stop = true;
1871  }
1872  }
1873  }
1874 
1875  // At this point, we must have found at least one digit.
1876  if (!found_digit)
1877  throw ParseError("Expected at least one digit.",
1878  msource.File(),
1879  msource.Line(),
1880  msource.Column());
1881 
1882  // Now there could be a `e' or `E':
1883  dummy = msource.Current();
1884  if ( 'e' == dummy || 'E' == dummy )
1885  {
1886  res += dummy;
1887  msource.AdvanceChar();
1888  if ( msource.LineBreak() )
1889  throw IllegalLinebreak( "Linebreak after e/E.",
1890  msource.File(),
1891  msource.Line(),
1892  msource.Column() );
1893 
1894  // Now there must be an integer (with optional sign)
1895  {
1896  String s;
1897  read_integer(s);
1898  res += s;
1899  }
1900  }
1901 }
1902 
1903 
1909 {
1910  String res;
1911  read_integer(res);
1912  istringstream is(res);
1913  is >> n;
1914 }
1915 
1916 
1922 {
1923  String res;
1924  read_numeric(res);
1925  istringstream is(res);
1926  is >> n;
1927 }
1928 
1929 
1945 {
1946  bool first = true; // To skip the first comma.
1947  res.resize(0); // Clear the result vector (just in case).
1948 
1949  // Make sure that the current character really is `[' and proceed.
1950  assertain_character('[');
1951  // There might have occured a linebreak, which is fine.
1952 
1953  eat_whitespace();
1954 
1955  // Read the elements of the vector (`]' means that we have
1956  // reached the end):
1957  while ( ']' != msource.Current() )
1958  {
1959  String dummy;
1960 
1961  if (first)
1962  first = false;
1963  else
1964  {
1965  assertain_character(',');
1966  eat_whitespace();
1967  }
1968 
1969  parse_String(dummy);
1970  res.push_back(dummy);
1971  eat_whitespace();
1972  }
1973 
1974  msource.AdvanceChar();
1975 }
1976 
1977 
1990 {
1991  bool first = true; // To skip the first comma.
1992  res.resize(0); // Clear the result vector (just in case).
1993 
1994  // Make sure that the current character really is `[' and proceed.
1995  assertain_character('[');
1996  // There might have occured a linebreak, which is fine.
1997 
1998  eat_whitespace();
1999 
2000  // Read the elements of the vector (`]' means that we have
2001  // reached the end):
2002  while ( ']' != msource.Current() )
2003  {
2004  Index dummy;
2005 
2006  if (first)
2007  first = false;
2008  else
2009  {
2010  assertain_character(',');
2011  eat_whitespace();
2012  }
2013 
2014  parse_integer(dummy);
2015  res.push_back(dummy);
2016  eat_whitespace();
2017  }
2018 
2019  msource.AdvanceChar();
2020 }
2021 
2022 
2035 {
2036  bool first = true; // To skip the first comma.
2037 
2038  // We need a temporary Array<Numeric>, so that we can use push_back
2039  // to store the values. FIXME: Need also constructor for Vector from
2040  // Array<Numeric>.
2041  Array<Numeric> tres;
2042 
2043  // Make sure that the current character really is `[' and proceed.
2044  assertain_character('[');
2045  // There might have occured a linebreak, which is fine.
2046 
2047  eat_whitespace();
2048 
2049  // Read the elements of the vector (`]' means that we have
2050  // reached the end):
2051  while ( ']' != msource.Current() )
2052  {
2053  Numeric dummy;
2054 
2055  if (first)
2056  first = false;
2057  else
2058  {
2059  assertain_character(',');
2060  eat_whitespace();
2061  }
2062 
2063  parse_numeric(dummy);
2064  tres.push_back(dummy);
2065  eat_whitespace();
2066  }
2067 
2068  // Copy tres to res:
2069  res.resize(tres.nelem());
2070  for (int i = 0; i < tres.nelem (); i++)
2071  {
2072  res[i] = tres[i];
2073  }
2074 
2075  msource.AdvanceChar();
2076 }
2077 
2078 
2091 {
2092  bool first = true; // To skip the first comma.
2093 
2094  // We need a temporary Array<Numeric>, so that we can use push_back
2095  // to store the values. FIXME: Need also constructor for Vector from
2096  // Array<Numeric>.
2097  Array<Numeric> tres;
2098 
2099  // Make sure that the current character really is `[' and proceed.
2100  assertain_character('[');
2101  // There might have occured a linebreak, which is fine.
2102 
2103  eat_whitespace();
2104 
2105  Index ncols = -1;
2106  Index cur_ncols = 1;
2107  // Read the elements of the vector (`]' means that we have
2108  // reached the end):
2109  while ( ']' != msource.Current() )
2110  {
2111  Numeric dummy;
2112 
2113  if (first)
2114  first = false;
2115  else
2116  {
2117  if (',' == msource.Current())
2118  {
2119  cur_ncols++;
2120  if (ncols != -1 && cur_ncols > ncols)
2121  {
2122  ostringstream os;
2123  os << "Expected ';', but got '" << msource.Current() << "'. Check Matrix dimensions.";
2124  throw UnexpectedChar( os.str(),
2125  msource.File(),
2126  msource.Line(),
2127  msource.Column() );
2128  }
2129  msource.AdvanceChar();
2130  eat_whitespace();
2131  }
2132  else if (';' == msource.Current())
2133  {
2134  if (ncols == -1)
2135  {
2136  ncols = cur_ncols;
2137  }
2138  else if (ncols != cur_ncols)
2139  {
2140  ostringstream os;
2141  os << "Expected ',', but got '" << msource.Current() << "'. Check Matrix dimensions.";
2142  throw UnexpectedChar( os.str(),
2143  msource.File(),
2144  msource.Line(),
2145  msource.Column() );
2146  }
2147  cur_ncols = 1;
2148  msource.AdvanceChar();
2149  eat_whitespace();
2150  }
2151  else
2152  {
2153  char c = ';';
2154  if (ncols > cur_ncols)
2155  c = ',';
2156  ostringstream os;
2157  os << "Expected '" << c << "', but got '" << msource.Current() << "'. Check Matrix dimensions.";
2158  throw UnexpectedChar( os.str(),
2159  msource.File(),
2160  msource.Line(),
2161  msource.Column() );
2162  }
2163  }
2164 
2165  parse_numeric(dummy);
2166  tres.push_back(dummy);
2167  eat_whitespace();
2168  }
2169 
2170  if (ncols == -1) ncols = cur_ncols;
2171  if (ncols != cur_ncols)
2172  {
2173  throw ParseError("Missing element(s) in last row of matrix",
2174  msource.File(),
2175  msource.Line(),
2176  msource.Column());
2177  }
2178 
2179 
2180  // Copy tres to res:
2181  Index nrows = tres.nelem() / ncols;
2182  res.resize(nrows, ncols);
2183  for (Index i = 0; i < nrows; i++)
2184  for (Index j = 0; j < ncols; j++)
2185  res(i, j) = tres[i*ncols+j];
2186 
2187  msource.AdvanceChar();
2188 }
2189 
2190 
2199 {
2200  bool first = true; // To skip the first comma.
2201  size_t pos = 0;
2202 
2203  // We need a temporary Array<Numeric>, so that we can use push_back
2204  // to store the values.
2205  Array<Numeric> tres;
2206 
2207  eat_whitespace_from_string (str, pos);
2208 
2209  // Make sure that the current character really is `[' and proceed.
2210  if (str[pos] != '[')
2211  {
2212  throw runtime_error ("No opening bracket\n");
2213  }
2214 
2215  pos++;
2216 
2217  eat_whitespace_from_string (str, pos);
2218 
2219  // Read the elements of the vector (`]' means that we have
2220  // reached the end):
2221  while ( pos < str.length() && str[pos] != ']' )
2222  {
2223  if (first)
2224  first = false;
2225  else
2226  {
2227  if (str[pos] != ',')
2228  {
2229  return false;
2230  }
2231  pos++;
2232  eat_whitespace_from_string (str, pos);
2233  }
2234 
2235  Numeric dummy;
2236  istringstream is (str.substr(pos));
2237  is >> dummy;
2238  if (is.bad () || is.fail ())
2239  return false;
2240  tres.push_back(dummy);
2241  while (pos < str.length()
2242  && (isdigit(str[pos]) || str[pos] == '-' || str[pos] == '.'
2243  || str[pos] == 'e'))
2244  pos++;
2245  eat_whitespace_from_string (str, pos);
2246  }
2247 
2248  // Copy tres to res:
2249  res.resize(tres.nelem());
2250  for (int i = 0; i < tres.nelem (); i++)
2251  {
2252  res[i] = tres[i];
2253  }
2254 
2255  return true;
2256 }
2257 
2258 
2268 {
2269  bool first = true; // To skip the first comma.
2270  size_t pos = 0;
2271 
2272  // We need a temporary Array<Numeric>, so that we can use push_back
2273  // to store the values.
2274  ArrayOfString tres;
2275 
2276  eat_whitespace_from_string (str, pos);
2277 
2278  // Make sure that the current character really is `[' and proceed.
2279  if (str[pos] != '[')
2280  {
2281  throw runtime_error ("No opening bracket\n");
2282  }
2283 
2284  pos++;
2285 
2286  eat_whitespace_from_string (str, pos);
2287 
2288  // Read the elements of the vector (`]' means that we have
2289  // reached the end):
2290  while ( pos < str.length() && str[pos] != ']' )
2291  {
2292  if (first)
2293  first = false;
2294  else
2295  {
2296  if (str[pos] != ',')
2297  {
2298  return false;
2299  }
2300  pos++;
2301  eat_whitespace_from_string (str, pos);
2302  }
2303 
2304  if (str[pos] != '"')
2305  {
2306  throw runtime_error ("Expected quotes\n");
2307  }
2308 
2309  pos++;
2310 
2311  String dummy;
2312  while ( pos < str.length() && str[pos] != '"' )
2313  {
2314  dummy += str[pos];
2315  pos++;
2316  }
2317 
2318  if (pos == str.length() || str[pos] != '"')
2319  return false;
2320 
2321  tres.push_back(dummy);
2322 
2323  eat_whitespace_from_string (str, pos);
2324  }
2325 
2326  // Copy tres to res:
2327  res.resize(tres.nelem());
2328  for (int i = 0; i < tres.nelem (); i++)
2329  {
2330  res[i] = tres[i];
2331  }
2332 
2333  return true;
2334 }
2335 
Matrix
The Matrix class.
Definition: matpackI.h:767
UnknownMethod
Definition: exceptions.h:94
MdRecord::GOut
const ArrayOfString & GOut() const
Definition: methods.h:93
ArtsParser::parse_specific_output
void parse_specific_output(const MdRecord *mdd, ArrayOfIndex &output, bool &first)
Parse the output WSVs for current method from the controlfile.
Definition: parser.cc:1235
Workspace::wsv_data
static Array< WsvRecord > wsv_data
Definition: workspace_ng.h:59
MdRecord::Supergeneric
bool Supergeneric() const
Definition: methods.h:108
MdRecord::GOutSpecType
const ArrayOfArrayOfIndex & GOutSpecType() const
Definition: methods.h:95
SourceText::AppendFile
void AppendFile(const String &name)
Appends contents of file to the source text.
Definition: sourcetext.cc:23
MdRecord::GOutType
const ArrayOfIndex & GOutType() const
Definition: methods.h:94
exceptions.h
The declarations of all the exception classes.
ArtsParser::parse_generic_output
void parse_generic_output(const MdRecord *&mdd, Index &id, String &methodname, ArrayOfIndex &output, bool &first, bool &still_supergeneric, String &supergeneric_args, Index &supergeneric_index)
Parse the generic output WSVs for current method from the controlfile.
Definition: parser.cc:953
ArtsParser::eat_whitespace_from_string
void eat_whitespace_from_string(String &str, size_t &pos)
Eats whitespace from a String.
Definition: parser.cc:1476
ArtsParser::parse_method
void parse_method(Index &id, ArrayOfIndex &output, ArrayOfIndex &input, Agenda &tasks, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values, String &include_file, bool no_eot=false)
Parse the Contents of text as ARTS control input.
Definition: parser.cc:352
SourceText::Init
void Init()
This sets the pointer to the first existing character in the text.
Definition: sourcetext.cc:118
TokVal
This stores arbitrary token values and remembers the type.
Definition: token.h:33
ArtsParser::read_integer
void read_integer(String &res)
Reads an integer.
Definition: parser.cc:1731
ArtsParser::parse_generic_input
void parse_generic_input(const MdRecord *&mdd, Index &id, String &methodname, ArrayOfIndex &input, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values, bool &first, bool &still_supergeneric, String &supergeneric_args, Index &supergeneric_index)
Parse the generic input WSVs for current method from the controlfile.
Definition: parser.cc:772
md_data_raw
Array< MdRecord > md_data_raw
Lookup information for workspace methods.
Definition: globals_2.cc:54
MdRecord::GInType
const ArrayOfIndex & GInType() const
Definition: methods.h:99
ArtsParser::is_whitespace
bool is_whitespace(const char c)
Returns true if this character is considered whitespace.
Definition: parser.cc:1415
Parameters
Structure to hold all command line Parameters.
Definition: parameters.h:42
Agenda::nelem
Index nelem() const
Return the number of agenda elements.
Definition: agenda_class.h:243
ArtsParser::mcfile
String mcfile
Definition: parser.h:136
ArtsParser::eat_whitespace
void eat_whitespace()
Eats whitespace.
Definition: parser.cc:1440
ArtsParser::parse_specific_input
void parse_specific_input(const MdRecord *mdd, ArrayOfIndex &input, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values, bool &first)
Parse the specific input WSVs for current method from the controlfile.
Definition: parser.cc:1155
SourceText::LineBreak
bool & LineBreak()
Read the line break flag.
Definition: sourcetext.h:89
MRecord
Method runtime data.
Definition: agenda_class.h:112
ArtsParser::parse_matrix
void parse_matrix(Matrix &res)
Read a Matrix.
Definition: parser.cc:2090
Vector::resize
void resize(Index n)
Resize function.
Definition: matpackI.cc:771
IllegalLinebreak
Definition: exceptions.h:85
ArtsParser::read_name
void read_name(String &name)
Reads name of method, keyword, or workspace variable.
Definition: parser.cc:1494
MdRecord::SetMethod
bool SetMethod() const
Definition: methods.h:106
ArtsParser::msource
SourceText msource
Definition: parser.h:138
SourceText::reachedEot
bool reachedEot()
Check if the current position reached the end.
Definition: sourcetext.h:57
CREATE_OUT2
#define CREATE_OUT2
Definition: messages.h:207
ParseError
Definition: exceptions.h:40
ArtsParser::assertain_character
void assertain_character(char c)
Make sure that the current character is equal to c and go to the next character.
Definition: parser.cc:1657
Agenda
The Agenda class.
Definition: agenda_class.h:44
find_file
bool find_file(String &filename, const char *extension)
Find the given file.
Definition: file.cc:379
WsvAlreadyExists
Definition: exceptions.h:112
ArtsParser::parse_intvector
void parse_intvector(ArrayOfIndex &res)
Read a vector of integers.
Definition: parser.cc:1989
ParseError::file
virtual String file() const
Definition: exceptions.h:53
ParseError::column
virtual Index column() const
Definition: exceptions.h:55
Array
This can be used to make arrays out of anything.
Definition: array.h:103
SourceText::Line
Index Line()
Return the line number, but for the file that is associated with the current position.
Definition: sourcetext.cc:103
ArtsParser::verbosity
const Verbosity & verbosity
Definition: parser.h:142
CREATE_OUT3
#define CREATE_OUT3
Definition: messages.h:208
CREATE_OUT0
#define CREATE_OUT0
Definition: messages.h:205
ArtsParser::set_gin_to_default
String set_gin_to_default(const MdRecord *mdd, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values, Index keyword_index)
Set generic input to default value.
Definition: parser.cc:473
SourceText::AdvanceLine
void AdvanceLine()
Advances position pointer by one line.
Definition: sourcetext.cc:66
ParseError::line
virtual Index line() const
Definition: exceptions.h:54
SourceText::Column
Index Column()
Return the current column.
Definition: sourcetext.h:81
ArtsParser::parse_numvector_from_string
bool parse_numvector_from_string(Vector &res, String &str)
Read a vector of Numerics from a String.
Definition: parser.cc:2198
ArtsParser::parse_Stringvector
void parse_Stringvector(ArrayOfString &res)
Read a vector of Strings.
Definition: parser.cc:1944
_U_
#define _U_
Definition: config.h:158
ArtsParser::parse_stringarray_from_string
bool parse_stringarray_from_string(ArrayOfString &res, String &str)
Read an Array of Strings from a String.
Definition: parser.cc:2267
my_basic_string< char >
NODEF
#define NODEF
Definition: methods.h:36
ArtsParser::parse_agenda
void parse_agenda(Agenda &tasklist)
Parse the Contents of text as ARTS control input.
Definition: parser.cc:215
ArtsParser::parse_method_args
void parse_method_args(const MdRecord *&mdd, Index &id, String &methodname, ArrayOfIndex &output, ArrayOfIndex &input, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values)
Parse method's argument list.
Definition: parser.cc:617
Eot
Definition: exceptions.h:67
MdRecord::AgendaMethod
bool AgendaMethod() const
Definition: methods.h:107
wsv_group_names
ArrayOfString wsv_group_names
Definition: groups.cc:40
SourceText::File
const String & File()
Return the filename associated with the current position.
Definition: sourcetext.cc:88
ArtsParser::parse_tasklist
void parse_tasklist()
Public interface to the main function of the parser.
Definition: parser.cc:47
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Verbosity
Definition: messages.h:50
MdRawMap
map< String, Index > MdRawMap
The map associated with md_data_raw.
Definition: globals_2.cc:68
MdRecord::Name
const String & Name() const
Definition: methods.h:89
ArtsParser::read_numeric
void read_numeric(String &res)
Reads a floating point number.
Definition: parser.cc:1793
Matrix::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackI.cc:1549
ArtsParser::mtasklist
Agenda & mtasklist
Definition: parser.h:134
MdRecord::InOnly
const ArrayOfIndex & InOnly() const
Definition: methods.h:103
parameters.h
This file contains header information for the dealing with command line parameters.
MdRecord::GInDefault
const Array< String > & GInDefault() const
Definition: methods.h:101
ArtsParser::read_name_or_value
Index read_name_or_value(String &name, ArrayOfIndex &auto_vars, Array< TokVal > &auto_vars_values, const String &default_name, const MdRecord *mdd, const Index group)
Reads name of a workspace variable or a value.
Definition: parser.cc:1548
md_data
Array< MdRecord > md_data
Lookup information for workspace methods.
Definition: globals_2.cc:62
ArtsParser::ArtsParser
ArtsParser(Agenda &tasklist, String controlfile, const Verbosity &verbosity)
Constructs a new parser.
Definition: parser.cc:36
MdRecord::GIn
const ArrayOfString & GIn() const
Definition: methods.h:98
parser.h
UnknownWsv
Definition: exceptions.h:103
WsvRecord
This class contains all static information for one workspace variable.
Definition: wsv_aux.h:49
workspace_ng.h
This file contains the declaration and partly the implementation of the workspace class.
MdRecord
All information for one workspace method.
Definition: methods.h:42
WrongWsvGroup
Definition: exceptions.h:121
ArtsParser
Definition: parser.h:27
parameters
Parameters parameters
Holds the command line parameters.
Definition: parameters.cc:40
UnexpectedChar
Definition: exceptions.h:76
Workspace::WsvMap
static map< String, Index > WsvMap
Definition: workspace_ng.h:62
SourceText::Current
char Current()
Return the current character.
Definition: sourcetext.h:49
ArtsParser::parse_numeric
void parse_numeric(Numeric &n)
Use a String stream to parse a floating point number.
Definition: parser.cc:1921
MdRecord::GInSpecType
const ArrayOfArrayOfIndex & GInSpecType() const
Definition: methods.h:100
MdMap
map< String, Index > MdMap
The map associated with md_data.
Definition: globals_2.cc:65
Workspace::add_wsv
static Index add_wsv(const WsvRecord &wsv)
Definition: workspace_ng.cc:59
ArtsParser::parse_main
void parse_main()
The main function of the parser.
Definition: parser.cc:58
Agenda::resize
void resize(Index n)
Resize the method list.
Definition: agenda_class.h:231
ArtsParser::parse_numvector
void parse_numvector(Vector &res)
Read a vector of Numerics.
Definition: parser.cc:2034
ArtsParser::parse_integer
void parse_integer(Index &n)
Use a String stream to parse an integer number.
Definition: parser.cc:1908
file.h
This file contains basic functions to handle ASCII files.
SourceText::AdvanceChar
void AdvanceChar()
Advance position pointer by one character.
Definition: sourcetext.cc:32
ArtsParser::mcfile_version
Index mcfile_version
Definition: parser.h:140
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
MdRecord::Out
const ArrayOfIndex & Out() const
Definition: methods.h:92
Agenda::Methods
const Array< MRecord > & Methods() const
Definition: agenda_class.h:70
arts_exit
void arts_exit(int status)
This is the exit function of ARTS.
Definition: arts.cc:42
Parameters::includepath
ArrayOfString includepath
List of paths to search for include files.
Definition: parameters.h:97
ArtsParser::parse_String
void parse_String(String &res)
Reads a String, complete with quotation marks.
Definition: parser.cc:1683
Vector
The Vector class.
Definition: matpackI.h:555
get_wsv_group_id
Index get_wsv_group_id(const String &name)
Definition: groups.cc:192
Agenda::push_back
void push_back(MRecord n)
Append a new method to end of list.
Definition: agenda_class.h:255
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:172
methods.h
Declaration of the class MdRecord.
wsv_aux.h
Auxiliary header stuff related to workspace variable groups.
arts.h
The global header file for ARTS.
ArtsParser::tasklist_insert_set_delete
void tasklist_insert_set_delete(const ArrayOfIndex &auto_vars, const Array< TokVal > &auto_vars_values, const Index method_type, Agenda &tasklist)
Insert Set and Delete methods for automatically allocated output WSVs.
Definition: parser.cc:1340