Compile.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  *  Copyright (C) 2002-2003 The Pentagram Team
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include "pent_include.h"
00022 
00023 /* Many things really, truely suck. One of them is the interface to the c++
00024         FlexLexer... */
00025 #undef yyFlexLexer
00026 #define yyFlexLexer llcFlexLexer
00027 #include "llcLexer.h"
00028 /* One of the problems being that it expects that flex is installed and that
00029         FlexLexer.h is found in one of the global include paths, which may
00030         not be the case, so we'll likely have to include it in our cvs
00031         staticly. *bleah* */
00032 
00033 #include <list>
00034 using std::list;
00035 #include <fstream>
00036 using std::ifstream;
00037 #include <iomanip>
00038 #include <string>
00039 #include <cassert>
00040 
00041 #include "llcTokens.h"
00042 
00043 #include "CoreApp.h"
00044 
00045 //#define CTRACE(X)
00046 #define CTRACE(x) perr << x << std::endl
00047 
00048 const char *UNKNOWN_ERR = "Unknown Expression.";
00049 
00050 const char * const random_generic_errors[] =
00051 {
00052         "Ugh! That's got to be the sickest thing I've ever seen!\n ...next to that poncy git there.\n\t--Giants: Citizen Kabuto",
00053         "Hark! Is that the sweet song of lamentation I hear?\n\t-- The Guardian, Ultima 8",
00054         "I do so enjoy the cries of torment.\n\t-- The Guardian, Ultima 8",
00055         "Ouch! -That- must have hurt, Avatar!\n\t-- The Guardian, Ultima 8",
00056         
00057         ""
00058 };
00059 
00060 #ifdef USE_CQUIRKS
00061 #define QUIRK(X, Y) X
00062 #else
00063 #define QURIK(X, Y) Y
00064 #endif
00065 
00066 #define ICE_ME(X) { msg(MT_ICE, X, this); return true; }
00067 
00068 /****************************************************************************
00069         Warning Messages
00070  ****************************************************************************/
00071 enum MsgType { MT_MSG, MT_WARN, MT_ERR, MT_ICE };
00072 
00073 class CompileUnit;
00074 
00075 MsgType msg(const MsgType msgType, const char * const msgDetails, CompileUnit *cu=0);
00076 /****************************************************************************/
00077 
00078 // Compile Unit **************************************************************
00079 #include "CompileUnit.h"
00080 
00081 CompileUnit::CompileUnit(FileSystem *filesystem) : currclass(0), ifile(0), idatasource(0),
00082         parser(0), filesys(filesystem), _state(CSTATE_NEW), _ccomplete(false),
00083         _expect(LLC_NONE), _warned(false)
00084         #ifdef COMPILER_TEST
00085         , testidx(0)
00086         #endif
00087 {
00088         setState(CSTATE_NEW);
00089         filesys->ListFiles("@work/usecode/src/*", filelist);
00090         for(FileSystem::FileList::iterator i=filelist.begin(); i!=filelist.end(); i++)
00091                 pout << "FILE: " << *i << std::endl;
00092 
00093         #ifdef COMPILER_TEST
00094         //filelist.push_back("@data/test-err/invalid-class-2.llc");
00095         //filelist.push_back("@data/test-err/invalid-block.llc");
00096         filelist.push_back("@work/usecode/src/nothing.llc");
00097         //filelist.push_back("@data/test-err/invalid-class-3.llc");
00098         filelist.push_back("@work/usecode/src/empty-class.llc");
00099         #endif
00100 }
00101 
00102 // Wheeee! Debugging stuff...
00103 void CompileUnit::debugPrint(std::ostream &o, CompileNode *n) const
00104 {
00105         debugPrintHead(o, n);
00106         n->print_unk(o);
00107         debugPrint(o);
00108 }
00109 
00110 void CompileUnit::debugPrint(std::ostream &o) const
00111 {
00112         debugPrintHead(o);
00113         debugPrintBody(o);
00114 }
00115 
00116 void CompileUnit::debugPrintHead(std::ostream &o, CompileNode *n) const
00117 {
00118         o << "Compile Stack:" << std::endl;
00119         if(n!=0)
00120                 o << std::setw(4) << n->linenum << ": ";
00121         else
00122                 if(nodes.size())
00123                         o << std::setw(4) << nodes.front()->linenum << ": ";
00124 }
00125 
00126 void CompileUnit::debugPrintBody(std::ostream &o) const
00127 {
00128         for(std::list<CompileNode *>::const_iterator i=nodes.begin(); i!=nodes.end(); i++)
00129         {
00130                 o << '\t';
00131                 (*i)->print_unk(o);
00132                 o << std::endl;
00133         }
00134 }
00135 
00136 #ifdef COMPILER_TEST
00137 
00138 /*enum TestX { TEST_END=0, TEST_XFAIL, TEST_XPASS, TEST_XWARN };
00139 
00140 struct CTestS
00141 {
00142         const char * filename;
00143         TestX xpect;
00144 };*/
00145 
00146 #endif
00147 
00148 bool CompileUnit::consume(const LLCToken &tok)
00149 {
00150         if(found(tok))
00151                 nodes.pop_front();
00152         else
00153                 ICE_ME("Errornous token encountered in stream in CompileUnit::consume()");
00154                 
00155         return false;
00156 }
00157 
00158 bool CompileUnit::parse()
00159 {
00160         CTRACE("CompileUnit::parse()");
00161 
00162         std::string fname;
00163         
00164         if(!parser || state()==CSTATE_FINISHED)
00165         {
00166                 #ifdef COMPILER_TEST
00167                 //fname = ctests[testidx].filename;
00168                 //pout << "Testing: " << fname << "..." << std::endl;
00169                 #endif
00170                 assert(filelist.size());
00171                 fname = filelist.back();
00172                 filelist.pop_back();
00173                 pout << "Opening... " << fname << std::endl;
00174 
00175                 idatasource = filesys->ReadFile(fname.c_str());
00176                 assert(idatasource!=0); // FIXME: Error checking!
00177                 ifile = idatasource->GetRawIfstream();
00178 
00179                 assert((ifile!=0) && (!ifile->fail())); //FIXME: Error checking!
00180 
00181                 parser = new llcFlexLexer(ifile, 0);
00182                 //parser->switch_streams(ifile, 0);
00183         }
00184 
00185         sint32 token=parser->yylex();
00186         switch(token)
00187         {
00188                 // #expect cases
00189                 case LLC_XFAIL: _expect=LLC_XFAIL; return true; break;
00190                 case LLC_XPASS: _expect=LLC_XPASS; return true; break;
00191                 case LLC_XWARN: _expect=LLC_XWARN; return true; break;
00192         
00193                 // more normal cases...
00194                 case LLC_CLASS:
00195                         nodes.push_back(new ClassNode(parser->lineno()));
00196                         break;
00197                 case LLC_IDENT:
00198                         nodes.push_back(new VarIdentNode(parser->YYText(), parser->lineno()));
00199                         break;
00200                 case LLC_OPEN_BRACE:
00201                         // adding this is rather pointless, but makes error reporting cleaner
00202                         nodes.push_back(new FencePostNode(LLC_OPEN_BRACE, parser->lineno()));
00203                         return parse_openblock();
00204                         break;
00205                 case LLC_CLOSE_BRACE:
00206                         nodes.push_back(new FencePostNode(LLC_CLOSE_BRACE, parser->lineno()));
00207                         return parse_closeblock();
00208                         break;
00209                 /*case LLC_UNIT:
00210                         {
00211                                 * Unit declarations take the form:
00212                                         unit = "Unit Name";
00213                                 *
00214                                 // got 'unit'
00215                                 const char * const unitErr = "Unit declaration of the form:\n\tunit = \"Unit Name\";\nexpected.";
00216                                 expect(LLC_EQUALS, parser, unitErr, ERR_UNIT); // want '='
00217                                 expect(LLC_STRING, LLC_CSTRING, parser, unitErr, ERR_UNIT); // want "Unit Name" or 'Unit Name'
00218                                 name=parser.YYText();
00219                                 expect(LLC_SEMICOLON, parser, unitErr, ERR_UNIT); // want ';'
00220                         }
00221                         break;*/
00222                 case LLC_EOF:
00223                         if(currclass==0)
00224                                 msg(MT_WARN, "Encountered end-of-file without encountering a class definition.");
00225                         setState(CSTATE_FINISHED); // FIXME: Should handle multiple files in the future...
00226                         return true;
00227                         break;
00228                 default:
00229                         con.Printf("\n%d\n", token);
00230                         return false;
00231         }
00232 
00233         return false;
00234 }
00235 
00236 bool CompileUnit::parse_openblock()
00237 {
00238         CTRACE("CompileUnit::parse_openblock()");
00239         /* Ok... so we get here when we recieve a { in the stream. This should only be from a:
00240                 class Fnord ... {
00241                 if (...) {
00242                 else if(...) {
00243                 else {
00244                 foreach ... {
00245 
00246                 So our task, for the moment, is theorietically simple, just fold all the following
00247                 tokens *back* into the original c++class new-ed for the primary nodes.
00248         */
00249 
00250         // first see if we *have* any nodes, if we don't then we've got serious problems.
00251         if(nodes.size()==0)
00252                 ICE_ME("Empty nodes stack should not occur within CompileUnit::parse_openblock()");
00253 
00254         // >class< Fnord {
00255         // >class< Fnord inherits class FnordBase {
00256         if(found(LLC_CLASS))
00257         {
00258                 if(currclass!=0)
00259                 {
00260                         msg(MT_ERR, "Class already defined in this file.", this);
00261                         return true;
00262                 }
00263                 
00264                 currclass = static_cast<ClassNode *>(nodes.front());
00265                 nodes.pop_front();
00266                 
00267                 // class >Fnord< {
00268                 // class >Fnord< inherits class FnordBase {
00269                 if(!found(LLC_IDENT))
00270                 {
00271                         nodes.push_front(currclass); currclass=0;
00272                         msg(MT_ERR, "Class name not found in declaration.", this);
00273                         return true;
00274                 }
00275                 
00276                 currclass->name=static_cast<VarIdentNode *>(nodes.front())->str;
00277                 nodes.pop_front();
00278 
00279                 if(!found(LLC_INHERITS) && !found(LLC_OPEN_BRACE))
00280                 {
00281                         nodes.push_front(currclass); currclass=0;
00282                         msg(MT_ERR, "Badly formed class expression: 'inherits' or '{' expected.", this);
00283                         return true;
00284                 }
00285                 
00286                 // class Fnord >{<
00287                 if(found(LLC_OPEN_BRACE))
00288                 {
00289                         consume(LLC_OPEN_BRACE);
00290                         return true;
00291                 }
00292                 
00293                 if(found(LLC_INHERITS))
00294                 {
00295 
00296                 }
00297 
00298                 return false;
00299         }
00300         // general case where we've got a 'block' but nothing to define it. Really shouldn't happen...
00301         else if(found(LLC_OPEN_BRACE))
00302         {
00303                 msg(MT_ERR, "Incorrectly defined block {", this);
00304                 return true;
00305         }
00306         else
00307         {
00308                 debugPrint(pout); assert(false); //FIXME: Error checking!
00309         }
00310 
00311         return false;
00312 };
00313 
00314 
00315 bool CompileUnit::parse_closeblock()
00316 {
00317         CTRACE("CompileUnit::parse_openblock()");
00318         /* This should handle the closing of any opened blocks.
00319                 Basically it should 'just' be a '}' on the nodes stack, and it should
00320                 just have to finish off any special things one might need to do terminate
00321                 a function/class/if/whatever block.
00322         */
00323 
00324         // first see if we *have* any nodes, if we don't then we've got serious problems.
00325         if(nodes.size()==0)
00326                 ICE_ME("Empty nodes stack should not occur within CompileUnit::parse_closeblock()");
00327         
00328         // honestly, there shouldn't be anything on the stack except a }, if there is... we've got problems!
00329         if(nodes.size()>1 || !found(LLC_CLOSE_BRACE))
00330                 ICE_ME("Unknown tokens before block terminator.");
00331         
00332         consume(LLC_CLOSE_BRACE);
00333 
00334         return false;
00335 }
00336 
00337 bool CompileUnit::setState(const CState cs)
00338 {
00339         switch(cs)
00340         {
00341                 // we're going to set outselves up nice and pristine for the new compile...
00342                 case CSTATE_NEW:
00343                         // if we've just succeeded, there should be no nodes...
00344                         if(_state==CSTATE_FINISHED && nodes.size()!=0)
00345                                 ICE_ME("Nodes stack should be empty on successful compile, it isn't! CompileUnit::setState()");
00346                         nodes.clear(); // remove any excess nodes, should they be there...
00347                         if(currclass!=0)
00348                                 tailclasses.push_back(currclass); // archive our class, should we need it's info later...
00349                         currclass=0;
00350                         FORGET_OBJECT(idatasource); // delete our data stream...
00351                         ifile=0; // ... and our ifstream should have been clobbered also
00352                         FORGET_OBJECT(parser); // blow away our parser. technically not needed and should be 'fixed' later... FIXME:
00353                         _warned=false;
00354                         _expect=LLC_NONE;
00355                         _state=cs;
00356                         break;
00357                 case CSTATE_FINISHED:
00358                 case CSTATE_FAIL:
00359                 case CSTATE_WORKING:
00360                         _state=cs;
00361                         break;
00362                 case CSTATE_WARNED: // doesn't actually change the state, but sets a flag instead...
00363                         _warned=true;
00364                         break;
00365                 default:
00366                         CANT_HAPPEN();
00367                         break;
00368         }
00369         return false;
00370 }
00371 
00372 /****************************************************************************
00373         Warning Messages
00374  ****************************************************************************/
00375 MsgType msg(const MsgType msgType, const char * const msgDetails, CompileUnit *cu)
00376 {
00377         switch(msgType)
00378         {
00379                 case MT_MSG:
00380                         con.Printf_err("%s\n", msgDetails);
00381                         break;
00382                 case MT_WARN:
00383                         if(cu!=0) cu->debugPrint(pout);
00384                         con.Printf_err("Warning: %s\n", msgDetails);
00385                         cu->setState(CompileUnit::CSTATE_WARNED);
00386                         break;
00387                 case MT_ERR:
00388                         assert(cu!=0);
00389                         cu->debugPrint(pout);
00390                         con.Printf_err("Error: %s\n", msgDetails);
00391                         cu->setState(CompileUnit::CSTATE_FAIL);
00392                         break;
00393                 case MT_ICE:
00394                         con.Printf_err("Internal Compile Error: %s\n", msgDetails);
00395                         con.Printf_err(">> Attempting to dump internal datastacks...\n");
00396                         assert(cu!=0);
00397                         cu->debugPrint(pout);
00398                         cu->setState(CompileUnit::CSTATE_FAIL);
00399                         break;
00400                 default:
00401                         assert(false); // can't happen
00402         }
00403         return msgType;
00404 }
00405 
00406 

Generated on Fri Jul 27 22:27:11 2007 for pentagram by  doxygen 1.4.7