00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 #include "arts.h"
00019 #include <map>
00020 #include "messages.h"
00021 #include "exceptions.h"
00022 #include "file.h"
00023 #include "auto_wsv.h"
00024 #include "methods.h"
00025 #include "parser.h"
00026 #include "wsv_aux.h"
00027 
00028 void SourceText::AppendFile(const String& name) 
00029 {
00030   mSfLine.push_back(mText.nelem());
00031   mSfName.push_back(name);
00032 
00033   read_text_from_file(mText, name);    
00034 }
00035 
00036 void SourceText::AdvanceChar() 
00037 {
00038   if ( mColumn < mText[mLine].nelem()-1 )
00039     {
00040       ++mColumn;
00041     }
00042   else
00043     {
00044       mLineBreak = true;
00045       do
00046         {
00047           if (mLine>=mText.nelem()-1)
00048             {
00049               throw Eot( "",
00050                          this->File(),
00051                          this->Line(),
00052                          this->Column() ); 
00053             }
00054           else
00055             {
00056               ++mLine;
00057               mColumn = 0;
00058             }
00059         }
00060       while ( 1 > mText[mLine].nelem() ); 
00061     }
00062 }
00063 
00064 
00065 void SourceText::AdvanceLine() 
00066 {
00067   mLineBreak = true;
00068   mColumn = 0;
00069   do
00070     {
00071       if (mLine>=mText.nelem()-1)
00072         {
00073           throw Eot( "",
00074                      this->File(),
00075                      this->Line(),
00076                      this->Column() ); 
00077         }
00078       else
00079         {
00080           ++mLine;
00081         }
00082     }
00083   while ( 1 > mText[mLine].nelem() ); 
00084 }
00085 
00086 
00087 const String& SourceText::File()
00088 {
00089   Index i    = 0;
00090   bool   stop = false;
00091 
00092   while ( i<mSfLine.nelem()-1 && !stop )
00093     {
00094       if (mLine>=mSfLine[i+1]) ++i;
00095       else                     stop = true;
00096     }
00097 
00098   return mSfName[i];
00099 }
00100 
00101 
00102 Index SourceText::Line()
00103 {
00104   Index i    = 0;
00105   bool   stop = false;
00106 
00107   while ( i<mSfLine.nelem()-1 && !stop )
00108     {
00109       if (mLine>=mSfLine[i+1]) ++i;
00110       else                     stop = true;
00111     }
00112 
00113   return mLine - mSfLine[i] + 1; 
00114 }
00115 
00116 
00117 void SourceText::Init()
00118 {
00119   mLine   = 0;
00120   mColumn = 0;
00121     
00122   if ( 1 > mText.nelem() )
00123     {
00124       throw Eot( "Empty text!",
00125                  this->File(),
00126                  this->Line(),
00127                  this->Column() ); 
00128     }
00129   else
00130     {
00131       
00132       while ( 1 > mText[mLine].nelem() )
00133         {
00134           if (mLine>=mText.nelem()-1)
00135             {
00136               throw Eot( "",
00137                          this->File(),
00138                          this->Line(),
00139                          this->Column() ); 
00140             }
00141           else
00142             {
00143               mLineBreak = true;
00144               ++mLine;
00145             }
00146         }
00147     }
00148 }
00149 
00150 
00151 ostream& operator << (ostream& os, const SourceText& text)
00152 {
00153   for (Index i=0; i<text.mText.nelem();++i)
00154     cout << i
00155          << "(" << text.mText[i].nelem() << ")"
00156          << ": " << text.mText[i] << '\n';
00157   return(os);
00158 }
00159 
00160 
00168 bool is_whitespace(const char c)
00169 {
00170   switch (c) 
00171     {
00172     case ' ':
00173     case '\r':
00174     case '\t':
00175     case '#':
00176       return true;
00177       break;
00178     default:
00179       return false;
00180       break;
00181     }
00182 }
00183 
00193 void eat_whitespace(SourceText& text)
00194 {
00195   char dummy;
00196 
00197   while (is_whitespace(dummy=text.Current())) 
00198     {
00199       switch (dummy)
00200         {
00201         case ' ':
00202         case '\r':
00203         case '\t':
00204           text.AdvanceChar();
00205           break;
00206         case '#':
00207           text.AdvanceLine();
00208           break;
00209         default:
00210           {
00211             ostringstream os;
00212             os << "Expected whitespace, but got `" << dummy << "'.";
00213             throw UnexpectedChar( os.str(),
00214                                   text.File(),
00215                                   text.Line(),
00216                                   text.Column() ); 
00217             break;
00218           }
00219         }
00220     }
00221 }
00222 
00223 
00232 void read_name(String& name, SourceText& text)
00233 {
00234   bool stop = false;
00235   name = "";
00236 
00237   while (!stop) 
00238     {
00239       char dummy = text.Current();
00240 
00241       if ( isalnum(dummy) || '_'==dummy )
00242         {
00243           name += dummy;
00244           
00245           text.LineBreak() = false;
00246           text.AdvanceChar();
00247           if ( text.LineBreak() ) stop = true;
00248         }
00249       else
00250         {
00251           stop = true;
00252         }
00253     }
00254 
00255   
00256 }
00257 
00262 void assertain_character(char c, SourceText& text)
00263 {
00264   if ( c != text.Current() )
00265     {
00266       ostringstream os;
00267       os << "Expected `" << c << "', but got `" << text.Current() << "'.";
00268       throw UnexpectedChar( os.str(),
00269                             text.File(),
00270                             text.Line(),
00271                             text.Column() ); 
00272     }
00273   
00274   text.AdvanceChar();
00275 }
00276 
00285 void parse_String(String& res, SourceText& text)
00286 {
00287   bool stop = false;
00288   res = "";
00289 
00290   text.LineBreak() = false;
00291   assertain_character('"',text);
00292   if ( text.LineBreak() )
00293     throw IllegalLinebreak( "Line break before end of String.",
00294                             text.File(),
00295                             text.Line(),
00296                             text.Column() ); 
00297 
00298   while (!stop) 
00299     {
00300       char dummy = text.Current();
00301       if ( dummy != '"' )
00302         {
00303           res += dummy;
00304           text.AdvanceChar();
00305 
00306           if ( text.LineBreak() )
00307             throw IllegalLinebreak( "Line break before end of String.",
00308                                     text.File(),
00309                                     text.Line(),
00310                                     text.Column() ); 
00311         }
00312       else
00313         {
00314           stop = true;
00315           text.AdvanceChar();
00316         }
00317     }
00318 }
00319 
00330 void read_integer(String& res, SourceText& text)
00331 {
00332   bool stop = false;
00333   res = "";
00334   char dummy;
00335   text.LineBreak() = false;
00336 
00337   dummy = text.Current();
00338   if ( '+' == dummy || '-' == dummy )
00339     {
00340       res += dummy;
00341       text.AdvanceChar();
00342       if ( text.LineBreak() )
00343         throw IllegalLinebreak( "Line break after sign.",
00344                                 text.File(),
00345                                 text.Line(),
00346                                 text.Column() ); 
00347     }
00348 
00349   if (!isdigit(text.Current()))
00350     {
00351       ostringstream os;
00352       os << "Expected digit, but got `" << text.Current() << "'.";
00353       throw UnexpectedChar(os.str(),
00354                            text.File(),
00355                            text.Line(),
00356                            text.Column());
00357     }
00358 
00359   while (!stop) 
00360     {
00361       char dummy = text.Current();
00362       if ( isdigit(dummy) )
00363         {
00364           res += dummy;
00365           text.AdvanceChar();
00366           if ( text.LineBreak() ) stop = true;
00367         }
00368       else
00369         {
00370           stop = true;
00371         }
00372     }
00373 }
00374 
00388 void read_numeric(String& res, SourceText& text)
00389 {
00390   bool stop;
00391   res = "";
00392   char dummy;
00393   text.LineBreak() = false;
00394 
00395   
00396   bool found_digit = false;
00397 
00398   
00399   dummy = text.Current();
00400   if ( '+' == dummy || '-' == dummy )
00401     {
00402       res += dummy;
00403       text.AdvanceChar();
00404       if ( text.LineBreak() )
00405         throw IllegalLinebreak( "Linebreak after sign.",
00406                                 text.File(),
00407                                 text.Line(),
00408                                 text.Column() ); 
00409     }
00410 
00411   
00412   stop = false;
00413   while (!stop) 
00414     {
00415       char dummy = text.Current();
00416       if ( isdigit(dummy) )
00417         {
00418           found_digit = true;
00419           res += dummy;
00420           text.AdvanceChar();
00421           if ( text.LineBreak() ) return; 
00422         }
00423       else
00424         {
00425           stop = true;
00426         }
00427     }
00428 
00429   
00430   if ( '.' == text.Current() )
00431     {
00432       res += ".";
00433       text.AdvanceChar();
00434       if ( text.LineBreak() )
00435         if (found_digit)
00436           {
00437             
00438             
00439             return;
00440           }
00441         else
00442           {
00443             throw IllegalLinebreak("Expected at least one digit.",
00444                                    text.File(),
00445                                    text.Line(),
00446                                    text.Column());
00447           }
00448 
00449       
00450       stop = false;
00451       while (!stop) 
00452         {
00453           char dummy = text.Current();
00454           if ( isdigit(dummy) )
00455             {
00456               found_digit = true;
00457               res += dummy;
00458               text.AdvanceChar();
00459               if ( text.LineBreak() ) return; 
00460             }
00461           else
00462             {
00463               stop = true;
00464             }
00465         }    
00466     }
00467 
00468   
00469   if (!found_digit)
00470     throw ParseError("Expected at least one digit.",
00471                      text.File(),
00472                      text.Line(),
00473                      text.Column());
00474 
00475   
00476   dummy = text.Current();
00477   if ( 'e' == dummy || 'E' == dummy )
00478     {
00479       res += dummy;
00480       text.AdvanceChar();
00481       if ( text.LineBreak() )
00482         throw IllegalLinebreak( "Linebreak after e/E.",
00483                                 text.File(),
00484                                 text.Line(),
00485                                 text.Column() );
00486       
00487       
00488       {
00489         String s;
00490         read_integer(s,text);
00491         res += s;
00492       }
00493     }
00494 }
00495 
00497 void parse_integer(Index& n, SourceText& text)
00498 {
00499   String res;
00500   read_integer(res, text);
00501   istringstream is(res);
00502   is >> n;
00503 }
00504 
00506 void parse_numeric(Numeric& n, SourceText& text)
00507 {
00508   String res;
00509   read_numeric(res, text);
00510   istringstream is(res);
00511   is >> n;
00512 }
00513 
00528 void parse_Stringvector(ArrayOfString& res, SourceText& text)
00529 {
00530   bool first = true;            
00531   res.resize(0);                        
00532 
00533   
00534   assertain_character('[',text);
00535   
00536   
00537   eat_whitespace(text);
00538 
00539   
00540   
00541   while ( ']' != text.Current() )
00542     {
00543       String dummy;
00544 
00545       if (first)
00546         first = false;
00547       else
00548         {
00549           assertain_character(',',text);
00550           eat_whitespace(text);
00551         }
00552 
00553       parse_String(dummy, text);
00554       res.push_back(dummy);
00555       eat_whitespace(text);
00556     }
00557 
00558   text.AdvanceChar();
00559 }
00560 
00572 void parse_intvector(ArrayOfIndex& res, SourceText& text)
00573 {
00574   bool first = true;            
00575   res.resize(0);                        
00576 
00577   
00578   assertain_character('[',text);
00579   
00580   
00581   eat_whitespace(text);
00582 
00583   
00584   
00585   while ( ']' != text.Current() )
00586     {
00587       Index dummy;
00588 
00589       if (first)
00590         first = false;
00591       else
00592         {
00593           assertain_character(',',text);
00594           eat_whitespace(text);
00595         }
00596 
00597       parse_integer(dummy, text);
00598       res.push_back(dummy);
00599       eat_whitespace(text);
00600     }
00601 
00602   text.AdvanceChar();
00603 }
00604 
00616 void parse_numvector(Vector& res, SourceText& text)
00617 {
00618   bool first = true;            
00619 
00620   
00621   
00622   
00623   Array<Numeric> tres;
00624 
00625   
00626   assertain_character('[',text);
00627   
00628   
00629   eat_whitespace(text);
00630 
00631   
00632   
00633   while ( ']' != text.Current() )
00634     {
00635       Numeric dummy;
00636 
00637       if (first)
00638         first = false;
00639       else
00640         {
00641           assertain_character(',',text);
00642           eat_whitespace(text);
00643         }
00644 
00645       parse_numeric(dummy, text);
00646       tres.push_back(dummy);
00647       eat_whitespace(text);
00648     }
00649 
00650   
00651   res.resize(tres.nelem());
00652   res = tres;
00653 
00654   text.AdvanceChar();
00655 }
00656 
00684 bool parse_method(Index& id, 
00685                   Array<TokVal>& values,
00686                   ArrayOfIndex& output,
00687                   ArrayOfIndex& input,
00688                   SourceText& text,
00689                   const std::map<String, Index> MdMap,
00690                   const std::map<String, Index> WsvMap)
00691 {
00692   extern const Array<WsvRecord> wsv_data;
00693   extern const Array<MdRecord> md_data;
00694   extern const ArrayOfString wsv_group_names;
00695 
00696   Index wsvid;                  
00697                                 
00698 
00699   
00700   id = 0;
00701   values.resize( 0 );
00702   output.resize( 0 );
00703   input.resize(  0 );
00704 
00705   {
00706     String methodname;
00707     read_name(methodname, text);
00708 
00709     {
00710       
00711       const map<String, Index>::const_iterator i = MdMap.find(methodname);
00712       if ( i == MdMap.end() )
00713         throw UnknownMethod(methodname,
00714                             text.File(),
00715                             text.Line(),
00716                             text.Column());
00717 
00718       id = i->second;
00719     }
00720     
00721     
00722   }
00723 
00724   eat_whitespace(text);
00725 
00726   
00727   
00728   if ( 0 < md_data[id].GOutput().nelem() + md_data[id].GInput().nelem() )
00729     {
00730       
00731       String wsvname;
00732       bool first = true;        
00733 
00734       assertain_character('(',text);
00735       eat_whitespace(text);
00736 
00737       
00738       for ( Index j=0 ; j<md_data[id].GOutput().nelem() ; ++j )
00739         {
00740           if (first)
00741             first = false;
00742           else
00743             {
00744               assertain_character(',',text);
00745               eat_whitespace(text);
00746             }
00747 
00748           read_name(wsvname, text);
00749 
00750           {
00751             
00752             const map<String, Index>::const_iterator i = WsvMap.find(wsvname);
00753             if ( i == WsvMap.end() )
00754               throw UnknownWsv( wsvname,
00755                                 text.File(),
00756                                 text.Line(),
00757                                 text.Column() );
00758 
00759             wsvid = i->second;
00760           }
00761 
00762           
00763           if ( wsv_data[wsvid].Group() != md_data[id].GOutput()[j] )
00764             {
00765             throw WrongWsvGroup( wsvname+" is not "+
00766                         wsv_group_names[md_data[id].GOutput()[j]]+", it is "+ 
00767                         wsv_group_names[wsv_data[wsvid].Group()],
00768                                  text.File(),
00769                                  text.Line(),
00770                                  text.Column() );
00771             }
00772 
00773           
00774           output.push_back(wsvid);
00775           
00776           eat_whitespace(text);
00777         }
00778 
00779       
00780       for ( Index j=0 ; j<md_data[id].GInput().nelem() ; ++j )
00781         {
00782           if (first)
00783             first = false;
00784           else
00785             {
00786               assertain_character(',',text);
00787               eat_whitespace(text);
00788             }
00789 
00790           read_name(wsvname, text);
00791 
00792           {
00793             
00794             const map<String, Index>::const_iterator i = WsvMap.find(wsvname);
00795             if ( i == WsvMap.end() )
00796               throw UnknownWsv( wsvname,
00797                                 text.File(),
00798                                 text.Line(),
00799                                 text.Column() );
00800 
00801             wsvid = i->second;
00802           }
00803 
00804           
00805           if ( wsv_data[wsvid].Group() != md_data[id].GInput()[j] )
00806             throw WrongWsvGroup( wsvname+" is not "+
00807                         wsv_group_names[md_data[id].GInput()[j]]+", it is "+ 
00808                         wsv_group_names[wsv_data[wsvid].Group()],
00809                                  text.File(),
00810                                  text.Line(),
00811                                  text.Column() );
00812 
00813           
00814           input.push_back(wsvid);
00815           
00816           eat_whitespace(text);
00817         }
00818 
00819       assertain_character(')',text);
00820       eat_whitespace(text);
00821     }
00822 
00823   
00824   assertain_character('{',text);
00825   eat_whitespace(text);
00826   
00827   
00828   
00829   
00830   
00831   
00832   
00833   
00834   
00835   
00836   
00837   for ( Index i=0 ; i<md_data[id].Keywords().nelem() ; ++i )
00838     {
00839       if (!isalpha(text.Current()) && 1==md_data[id].Keywords().nelem())
00840         {
00841           
00842           
00843 
00844           
00845         }
00846       else  
00847         {      
00848           
00849           String keyname;
00850           read_name(keyname,text);
00851 
00852           
00853           if ( keyname != md_data[id].Keywords()[i] )
00854             {
00855               throw UnexpectedKeyword( keyname,
00856                                        text.File(),
00857                                        text.Line(),
00858                                        text.Column());
00859             }
00860 
00861           eat_whitespace(text);
00862 
00863           
00864           assertain_character('=',text);
00865           eat_whitespace(text);
00866         }
00867 
00868       
00869       
00870       
00871       switch (md_data[id].Types()[i]) 
00872         {
00873         case String_t:
00874           {
00875             String dummy;
00876             parse_String(dummy, text);
00877             values.push_back(dummy);
00878             break;
00879           }
00880         case Index_t:
00881           {
00882             Index n;
00883             parse_integer(n, text);
00884             values.push_back(n);
00885             break;
00886           }
00887         case Numeric_t:
00888           {
00889             Numeric n;
00890             parse_numeric(n, text);
00891             values.push_back(n);
00892             break;
00893           }
00894         case Array_String_t:
00895           {
00896             ArrayOfString dummy;
00897             parse_Stringvector(dummy, text);
00898             values.push_back(dummy);
00899             break;
00900           }
00901         case Array_Index_t:
00902           {
00903             ArrayOfIndex dummy;
00904             parse_intvector(dummy, text);
00905             values.push_back(dummy);
00906             break;
00907           }
00908         case Vector_t:
00909           {
00910             Vector dummy;
00911             parse_numvector(dummy, text);
00912             values.push_back(dummy);
00913             break;
00914           }
00915         default:
00916           throw logic_error("Impossible parameter type.");
00917           break;
00918         }
00919 
00920       eat_whitespace(text);
00921 
00922       
00923       
00924     }
00925 
00926 
00927   
00928   
00929   
00930   try
00931     {
00932      assertain_character('}',text);
00933     }
00934   catch (const Eot x)
00935     {
00936       
00937       return true;
00938     }
00939   return false;
00940 }
00941 
00955 void parse(Array<MRecord>& tasklist,
00956            SourceText& text,
00957            const std::map<String, Index> MdMap,
00958            const std::map<String, Index> WsvMap)
00959 {
00960   extern const Array<MdRecord> md_data;
00961   bool last = false;
00962   
00963   Index id;             
00964  
00965   Array<TokVal> values;
00966   
00967   ArrayOfIndex output;          
00968   
00969   ArrayOfIndex input;
00970 
00971   out3 << "\nParsing:\n";
00972 
00973   
00974 
00975   eat_whitespace(text);
00976 
00977   while (!last)
00978     {
00979       last = parse_method(id,values,output,input,text,MdMap,WsvMap);
00980 
00981       
00982       tasklist.push_back(MRecord(id,values,output,input));
00983 
00984       {
00985         
00986         
00987         extern const Array<WsvRecord> wsv_data;
00988 
00989         out3 << "- " << md_data[id].Name() << "\n";
00990 
00991         for ( Index j=0 ; j<values.nelem() ; ++j )
00992           {
00993             out3 << "   " 
00994                  << md_data[id].Keywords()[j] << ": "
00995                  << values[j] << '\n';
00996           }
00997           
00998         
00999         if ( 0 < md_data[id].GOutput().nelem() + md_data[id].GInput().nelem() )
01000           {
01001             out3 << "   Output: ";
01002             for ( Index j=0 ; j<output.nelem() ; ++j )
01003               {
01004                 out3 << wsv_data[output[j]].Name() << " ";
01005               }
01006             out3 << "\n";
01007 
01008             out3 << "   Input: ";
01009             for ( Index j=0 ; j<input.nelem() ; ++j )
01010               {
01011                 out3 << wsv_data[input[j]].Name() << " ";
01012               }
01013             out3 << "\n";
01014           }
01015       }
01016 
01017       
01018       
01019       if (!last)
01020         try
01021           {
01022             eat_whitespace(text);
01023           }
01024         catch (const Eot x)
01025           {
01026             last = true;
01027           }
01028     }
01029 }
01030 
01031 void parse_main(Array<MRecord>& tasklist, SourceText& text)
01032 {
01033   
01034   
01035   extern const std::map<String, Index> MdMap;
01036   extern const std::map<String, Index> WsvMap;
01037 
01038   try 
01039     {
01040       text.Init();
01041       parse(tasklist,text,MdMap,WsvMap);
01042     }
01043   catch (const Eot x)
01044     {
01045       
01046       out0 << "Unexpected end of control script.\n";
01047       out0 << "File: " << x.file() << '\n';
01048       out0 << "Line: " << x.line() << '\n';
01049       exit(true);
01050     }
01051   catch (const UnexpectedChar x)
01052     {
01053       
01054       out0 << "Unexpected character:\n";
01055       out0 << x.what()   << '\n';
01056       out0 << "File: "   << x.file() << '\n';
01057       out0 << "Line: "   << x.line() << '\n';
01058       out0 << "Column: " << x.column() << '\n';
01059       exit(true);
01060     }
01061   catch (const IllegalLinebreak x)
01062     {
01063       
01064       out0 << "Illegal Line break:\n";
01065       out0 << x.what()   << '\n';
01066       out0 << "File: "   << x.file() << '\n';
01067       out0 << "Line: "   << x.line() << '\n';
01068       exit(true);
01069     }
01070   catch (const UnknownMethod x)
01071     {
01072       
01073       
01074       
01075       out0 << "Unknown Method:\n";
01076       out0 << x.what()   << '\n';
01077       out0 << "File: "   << x.file() << '\n';
01078       out0 << "Line: "   << x.line() << '\n';
01079       out3 << "Column: " << x.column() << '\n';
01080       exit(true);
01081     }
01082   catch (const UnknownWsv x)
01083     {
01084       
01085       
01086       
01087       out0 << "Unknown workspace variable:\n";
01088       out0 << x.what()   << '\n';
01089       out0 << "File: "   << x.file() << '\n';
01090       out0 << "Line: "   << x.line() << '\n';
01091       out3 << "Column: " << x.column() << '\n';
01092       exit(true);
01093     }
01094   catch (const WrongWsvGroup x)
01095     {
01096       
01097       
01098       
01099       out0 << "Workspace variable belongs to the wrong group:\n";
01100       out0 << x.what()   << '\n';
01101       out0 << "File: "   << x.file() << '\n';
01102       out0 << "Line: "   << x.line() << '\n';
01103       out3 << "Column: " << x.column() << '\n';
01104       exit(true);
01105     }
01106   catch (const UnexpectedKeyword x)
01107     {
01108       
01109       
01110       
01111       out0 << "Unknown keyword:\n";
01112       out0 << x.what()   << '\n';
01113       out0 << "File: "   << x.file() << '\n';
01114       out0 << "Line: "   << x.line() << '\n';
01115       out3 << "Column: " << x.column() << '\n';
01116       exit(true);
01117     }
01118   catch (const ParseError x)
01119     {
01120       
01121       out0 << "Parse error:\n";
01122       out0 << x.what()   << '\n';
01123       out0 << "File: "   << x.file() << '\n';
01124       out0 << "Line: "   << x.line() << '\n';
01125       out0 << "Column: " << x.column() << '\n';
01126       exit(true);
01127     }
01128   catch (const runtime_error x)
01129     {
01130       cout << "Runtime error: ";
01131       cout << x.what() << '\n';
01132     }
01133   catch (const logic_error x)
01134     {
01135       cout << "Logic error: ";
01136       cout << x.what() << '\n';
01137     }
01138 
01139 }