C-Breeze
C Compiler Infrastructure

[ Project home page]
Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

arch_info_parser.cc

Go to the documentation of this file.
00001 // $Id: arch_info_parser.cc,v 1.8 2003/08/11 17:38:51 abrown Exp $
00002 // ----------------------------------------------------------------------
00003 //
00004 //  C-Breeze
00005 //  C Compiler Framework
00006 // 
00007 //  Copyright (c) 2002 University of Texas at Austin
00008 // 
00009 //  Charles Nevill
00010 //  Paul Arthur Navratil
00011 //  Calvin Lin
00012 //  Adam C. Brown
00013 // 
00014 //  Permission is hereby granted, free of charge, to any person
00015 //  obtaining a copy of this software and associated documentation
00016 //  files (the "Software"), to deal in the Software without
00017 //  restriction, including without limitation the rights to use, copy,
00018 //  modify, merge, publish, distribute, sublicense, and/or sell copies
00019 //  of the Software, and to permit persons to whom the Software is
00020 //  furnished to do so, subject to the following conditions:
00021 //  
00022 //  The above copyright notice and this permission notice shall be
00023 //  included in all copies or substantial portions of the Software.
00024 //  
00025 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00026 //  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00027 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00028 //  NONINFRINGEMENT.  IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT
00029 //  AUSTIN BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00030 //  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
00031 //  OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00032 //  THE SOFTWARE.
00033 //
00034 //  We acknowledge the C-to-C Translator from MIT Laboratory for
00035 //  Computer Science for inspiring parts of the C-Breeze design.
00036 //
00037 // ----------------------------------------------------------------------
00038 
00039 #include "c_breeze.h"
00040 #include "arch_info_parser.h"
00041 #include "lirutil.h"
00042 
00043 // for handling errors when we parse the desc
00044 #define PARSE_ERROR CBZFAIL
00045 
00046 arch_info_parser::arch_info_parser() 
00047 {
00048         // internal initial values
00049         _initialized = false;
00050         _pSpecFile = NULL;
00051         _lastChar = NO_CHAR;
00052         _wasNewLine = false;
00053 }
00054 
00055 arch_info_parser::~arch_info_parser() 
00056 {
00057 }
00058 
00059 void arch_info_parser::init_parser()
00060 {
00061   // only do this once
00062   if ( _initialized )
00063     return;
00064 
00066   // initialize character classes
00067 
00068   int i;
00069 
00070   // everyone starts special
00071   for ( i = 0; i < 256; ++i )
00072     _charClass[i] = SPECIAL;
00073 
00074   // setup alphanum
00075   for ( i = '0'; i <= '9'; ++i )
00076     _charClass[i] = ALPHANUM;
00077   for ( i = 'a'; i <= 'z'; ++i )
00078     _charClass[i] = ALPHANUM;
00079   for ( i = 'A'; i <= 'Z'; ++i )
00080     _charClass[i] = ALPHANUM;
00081 
00082   // setup whitespace and line breaks
00083   _charClass[' '] = WS;
00084   _charClass['\t'] = WS;
00085   _charClass['\n'] = LINEBREAK;
00086 
00088   // initialize top-level things to parse
00089 
00090   // top-level stuff
00091   _thingsToParse.push_back(thing_to_parse("ArchName", &arch_info::_archName));
00092   _thingsToParse.push_back( thing_to_parse("AsmLineComment", 
00093                                            &arch_info::_asmLineComment));
00094   _thingsToParse.push_back( thing_to_parse( "AsmRegPrefixAdd",
00095                                             &arch_info::_asmRegPrefixAdd ) );
00096   _thingsToParse.push_back( thing_to_parse("AsmRegPrefixRemove",
00097                                            &arch_info::_asmRegPrefixRemove ) );
00098   _thingsToParse.push_back( thing_to_parse( "AsmConstPrefix",
00099                                             &arch_info::_asmConstPrefix ) );
00100 
00101   // register stuff
00102   _thingsToParse.push_back( thing_to_parse( "RegsAll",
00103                                             &arch_info::_regsAll, true ) );
00104   _thingsToParse.push_back( thing_to_parse( "RegsGpr",
00105                                             &arch_info::_regsGpr ) );
00106   _thingsToParse.push_back( thing_to_parse( "RegsFpr",
00107                                             &arch_info::_regsFpr ) );
00108   _thingsToParse.push_back( thing_to_parse( "RegSp",
00109                                             &arch_info::_regSp ) );
00110   _thingsToParse.push_back( thing_to_parse( "RegFp",
00111                                             &arch_info::_regFp ) );
00112   _thingsToParse.push_back( thing_to_parse( "RegsParamFixed",
00113                                             &arch_info::_regsParamFixed ) );
00114   _thingsToParse.push_back( thing_to_parse( "RegsParamFloat",
00115                                             &arch_info::_regsParamFloat ) );
00116   _thingsToParse.push_back( thing_to_parse( "RegRetvalFixed",
00117                                             &arch_info::_regRetvalFixed ) );
00118   _thingsToParse.push_back( thing_to_parse( "RegRetvalFloat",
00119                                             &arch_info::_regRetvalFloat ) );
00120   _thingsToParse.push_back( thing_to_parse( "RegsCallerSave",
00121                                             &arch_info::_regsCallerSave ) );
00122   _thingsToParse.push_back( thing_to_parse( "RegsCalleeSave",
00123                                             &arch_info::_regsCalleeSave ) );
00124   _thingsToParse.push_back( thing_to_parse( "RegDataTypeGpr",
00125                                             &arch_info::_regDataTypeGpr ) );
00126   _thingsToParse.push_back( thing_to_parse( "RegDataTypeFpr",
00127                                             &arch_info::_regDataTypeFpr ) );
00128 
00129   // data size stuff
00130   _thingsToParse.push_back( thing_to_parse( "DataSizeShort",
00131                                             &arch_info::_dataSizeShort ) );
00132   _thingsToParse.push_back( thing_to_parse( "DataSizeInt",
00133                                             &arch_info::_dataSizeInt ) );
00134   _thingsToParse.push_back( thing_to_parse( "DataSizeLong",
00135                                             &arch_info::_dataSizeLong ) );
00136   _thingsToParse.push_back( thing_to_parse( "DataSizeFloat",
00137                                             &arch_info::_dataSizeFloat ) );
00138   _thingsToParse.push_back( thing_to_parse( "DataSizeDouble",
00139                                             &arch_info::_dataSizeDouble ) );
00140   _thingsToParse.push_back( thing_to_parse( "DataSizePtr",
00141                                             &arch_info::_dataSizePtr ) );
00142 
00143   // data alignment stuff
00144   _thingsToParse.push_back( thing_to_parse( "DataAlignChar",
00145                                             &arch_info::_dataAlignChar ) );
00146   _thingsToParse.push_back( thing_to_parse( "DataAlignShort",
00147                                             &arch_info::_dataAlignShort ) );
00148   _thingsToParse.push_back( thing_to_parse( "DataAlignInt",
00149                                             &arch_info::_dataAlignInt ) );
00150   _thingsToParse.push_back( thing_to_parse( "DataAlignLong",
00151                                             &arch_info::_dataAlignLong ) );
00152   _thingsToParse.push_back( thing_to_parse( "DataAlignFloat",
00153                                             &arch_info::_dataAlignFloat ) );
00154   _thingsToParse.push_back( thing_to_parse( "DataAlignDouble",
00155                                             &arch_info::_dataAlignDouble ) );
00156   _thingsToParse.push_back( thing_to_parse( "DataAlignPtr",
00157                                             &arch_info::_dataAlignPtr ) );
00158 
00159   // stack management stuff
00160   _thingsToParse.push_back( thing_to_parse( "StackFrameMinSize",
00161                                             &arch_info::_stackFrameMinSize ) );
00162   _thingsToParse.push_back( thing_to_parse( "StackExtraTop",
00163                                             &arch_info::_stackExtraTop ) );
00164   _thingsToParse.push_back( thing_to_parse( "StackExtraBottom",
00165                                             &arch_info::_stackExtraBottom ) );
00166   _thingsToParse.push_back( thing_to_parse( "StackAlign",
00167                                             &arch_info::_stackAlign ) );
00168   _thingsToParse.push_back( thing_to_parse("StackFormalsOffset",
00169                                            &arch_info::_stackFormalsOffset ) );
00170 
00171   // arch_info::Lir2Asm stuff
00172   _thingsToParse.push_back( thing_to_parse( "LirEmulate3Address",
00173                                             &arch_info::_emulate3Address ) );
00174   _thingsToParse.push_back( thing_to_parse( "Lir2Asm",
00175                                             &arch_info::_Lir2Asm_records ) );
00176 
00178         // initialize mnemonic map thingy
00179         // NOTE: these map keys must be lower-case in order for us to do
00180         // case-insensitive lookup
00181 #define MNEMONIC( mnemonic ) \
00182 { \
00183         string temp( #mnemonic ); \
00184         cbz_util::string_to_lower( temp ); \
00185         _mnemonicMap[ temp ] = mn_##mnemonic; \
00186 }
00187   MNEMONIC( NOP );
00188   MNEMONIC( ConvertType );
00189   MNEMONIC( Load );
00190   MNEMONIC( LoadImmediate );
00191   MNEMONIC( LoadStatic );
00192   MNEMONIC( Store );
00193   MNEMONIC( StoreStatic );
00194   MNEMONIC( GetEffectiveAddr );
00195   MNEMONIC( GetGlobalAddr );
00196   MNEMONIC( Move );
00197   MNEMONIC( Add );
00198   MNEMONIC( Sub );
00199   MNEMONIC( Mul );
00200   MNEMONIC( Div );
00201   MNEMONIC( Mod );
00202   MNEMONIC( Neg );
00203   MNEMONIC( BitwiseOR );
00204   MNEMONIC( BitwiseAND );
00205   MNEMONIC( BitwiseXOR );
00206   MNEMONIC( BitwiseNOT );
00207   MNEMONIC( BitwiseShiftLeft );
00208   MNEMONIC( BitwiseShiftRight );
00209   MNEMONIC( BitwiseRotateRight );
00210   MNEMONIC( BitwiseRotateLeft );
00211   MNEMONIC( Compare );
00212   MNEMONIC( BranchEQ );
00213   MNEMONIC( BranchNE );
00214   MNEMONIC( BranchLT );
00215   MNEMONIC( BranchLE );
00216   MNEMONIC( BranchGT );
00217   MNEMONIC( BranchGE );
00218   MNEMONIC( Jmp );
00219   MNEMONIC( Call );
00220   MNEMONIC( IndirectCall );
00221   MNEMONIC( Return );
00222   MNEMONIC( Label );
00223   MNEMONIC( DeclLocal );
00224   MNEMONIC( DeclGlobal );
00225   MNEMONIC( StaticDataString );
00226   MNEMONIC( StaticDataLong );
00227   MNEMONIC( StaticDataInt );
00228   MNEMONIC( StaticDataShort );
00229   MNEMONIC( StaticDataChar );
00230   MNEMONIC( StaticDataSingle );
00231   MNEMONIC( StaticDataDouble );
00232   MNEMONIC( StaticDataZero );
00233   MNEMONIC( StaticDataUninit );
00234   MNEMONIC( BeginProc );
00235   MNEMONIC( EndProc );
00236   MNEMONIC( BeginUnit );
00237   MNEMONIC( EndUnit );
00238 #undef MNEMONIC
00239 
00241   // initialize typeNode * map thingy
00242   // NOTE: these map keys must be lower-case in order for us
00243   // to do case-insensitive lookup
00244 #define VARTYPE( vartype, nodeType ) \
00245 { \
00246         string temp( #vartype ); \
00247         cbz_util::string_to_lower( temp ); \
00248         _varTypeMap[ temp ] = nodeType; \
00249 }
00250   VARTYPE( char, new primNode(typeNode::NONE, basic_type::SChar) );
00251   VARTYPE( uchar, new primNode(typeNode::NONE, basic_type::UChar) );
00252   VARTYPE( short, new primNode(typeNode::NONE, basic_type::SShort) );
00253   VARTYPE( ushort, new primNode(typeNode::NONE, basic_type::UShort) );
00254   VARTYPE( int, new primNode(typeNode::NONE, basic_type::SInt) );
00255   VARTYPE( uint, new primNode(typeNode::NONE, basic_type::UInt) );
00256   VARTYPE( long, new primNode(typeNode::NONE, basic_type::SLong) );
00257   VARTYPE( ulong, new primNode(typeNode::NONE, basic_type::ULong) );
00258   VARTYPE( float, new primNode(typeNode::NONE, basic_type::Float) );
00259   VARTYPE( double, new primNode(typeNode::NONE, basic_type::Double) );
00260   VARTYPE( pointer, LirUtil::newVoidPtr() );
00261 #undef VARTYPE
00262 
00263 // cout << (basic_type::Long).to_string() << endl;
00264 // cout << (basic_type::Short).to_string() << endl;
00265 
00266 // for ( vartype_map::iterator p = _varTypeMap.begin();
00267 //       p != _varTypeMap.end();
00268 //       p++ ) {
00269 //   cout << p->first << " -> " << ( (p->second->typ() == Prim) ?
00270 //     ((primNode *) p->second)->basic().to_string() : "pointer") << endl;
00271 // }
00272 
00273         // we are now initialized
00274         _initialized = true;
00275 }
00276 
00277 bool 
00278 arch_info_parser::parse( const char * pFileName, arch_info * pArchInfo )
00279 {
00280   // initialize ourself
00281   _pArchInfo = pArchInfo;
00282   init_parser();
00283 
00284   // can we open it?
00285   _pSpecFile = fopen( pFileName, "rt" );
00286   if ( ! _pSpecFile ) {
00287     cerr << "ERROR:  Can't load '" << pFileName << "' for reading." << endl;
00288     return false;
00289   }
00290 
00291   // reset parser state
00292   _lastChar = NO_CHAR;
00293   _currentLine = 1;
00294 
00295   // munch whitespace
00296   char c;
00297   while ( (c = peek_char(true)) != EOF && c == '\n' )
00298     get_char();
00299 
00300   // repeatedly parse a string and whatever goes with it
00301   string keyName;
00302   while ( read_string( keyName ) ) {
00303     // we will be case-insensitive
00304     string keyNameLower( keyName );
00305     cbz_util::string_to_lower( keyNameLower );
00306 
00307     // can we find an action that goes with this?
00308     size_t sz = _thingsToParse.size();
00309     bool found = false;
00310     for ( int i = 0; i < (int)sz; ++i ) {
00311       // is this the thing we're looking at?
00312       if ( _thingsToParse[i]._keyName == keyNameLower ) {
00313         thing_to_parse & parseThing = _thingsToParse[i];
00314 
00315         // parse this thing
00316         bool res;
00317         switch ( parseThing._parseType )
00318           {
00319           case type_reg:
00320             res = parse_reg_item(keyName, parseThing._data._reg );
00321             break;
00322           case type_reg_list:
00323             res = parse_reg_list_item(keyName, parseThing._data._regList, 
00324                                       parseThing._regIsMasterList ); 
00325             break;
00326           case type_string:
00327             res = parse_string_item(keyName, parseThing._data._string );
00328             break;
00329           case type_integer:
00330             res = parse_integer_item(keyName, parseThing._data._int );
00331             break;
00332           case type_boolean:
00333             res = parse_bool_item(keyName, parseThing._data._bool );
00334             break;
00335           case type_vartype:
00336             res = parse_vartype_item(keyName, parseThing._data._vartype );
00337             break;
00338           case type_Lir2Asm:
00339             res = parse_Lir2Asm_item(keyName, parseThing._data._Lir2AsmList );
00340             break;
00341           default:
00342             assert( false );
00343             break;
00344           } // end switch
00345 
00346         // success?
00347         if ( ! res )
00348           return false;
00349 
00350         // we found what we were looking for - go to the next thing in the file
00351         found = true;
00352         break;
00353       }
00354     }
00355 
00356     // did we find something?
00357     if ( ! found )
00358       PARSE_ERROR( ("unrecognized key name '%s'", keyName.c_str()) );
00359 
00360     // munch whitespace
00361     while ( (c = peek_char(true)) != EOF && c == '\n' )
00362       get_char();
00363   }
00364 
00365   return true;
00366 }
00367 
00368 char 
00369 arch_info_parser::get_char( bool skipWhitespace ) {
00370   char c;
00371 
00372   // do we already have one?
00373   if ( _lastChar == NO_CHAR 
00374        || (skipWhitespace && _charClass[_lastChar] == WS) )
00375     peek_char( skipWhitespace );
00376 
00377   // return what we have
00378   c = (char)_lastChar;
00379   if ( _lastChar != EOF )
00380     _lastChar = NO_CHAR;
00381 
00382   return c;
00383 }
00384 
00385 char 
00386 arch_info_parser::peek_char( bool skipWhitespace ) {
00387   // do we need to get one?
00388   while ( _lastChar != EOF 
00389           && (_lastChar == NO_CHAR 
00390               || (skipWhitespace && _charClass[_lastChar] == WS)) ) {
00391     char ch = do_getc();
00392     char ch2;
00393     switch ( ch )
00394       {
00395       case EOF:
00396         // we are finished
00397         _lastChar = EOF;
00398         break;
00399 
00400       case '/':
00401         // what's next?
00402         ch2 = do_getc();
00403         if ( ch2 == '*' ) {
00404           // eat a block comment
00405           char ch3;
00406           while ( ch2 != EOF ) {
00407             // is there a '*'?
00408             ch2 = do_getc();
00409             if ( ch2 != '*' )
00410               continue;
00411 
00412             // is there a '/'?
00413             ch3 = do_getc();
00414             if ( ch3 == '/' )
00415               break;
00416 
00417             // put this thing back
00418             do_ungetc( ch3 );
00419           }
00420 
00421           // sanity checks
00422           assert( ch2 == EOF || ch3 == '/' );
00423 
00424           // keep looking for real characters
00425           continue;
00426         } else if ( ch2 != '/' ) {
00427           // this is not a line comment - put ch2 back and 
00428           //    give the first '/' to caller
00429           do_ungetc( ch2 );
00430           _lastChar = ch;
00431           break;
00432         }
00433 
00434         // if we are here, we have a c++-style line comment, so 
00435         //      just fall through to line comment handler
00436 
00437       case '#':
00438         // line comment - eat all characters up to newline
00439         while ( ((ch2 = do_getc()) != EOF) && ch2 != '\n');
00440 
00441         // sanity checks
00442         assert( ch2 == EOF || ch2 == '\n' );
00443 
00444         // go on and look for more interesting things
00445         continue;
00446 
00447       case '\\': // escape character
00448         // is next comment character?
00449         ch2 = do_getc();
00450         if ( ch2 == '#' ) {
00451           // treat this as non-comment
00452           _lastChar = ch2;
00453           continue;
00454         } else {
00455           // pass on as normal
00456           do_ungetc( ch2 );
00457           _lastChar = ch;
00458           continue;
00459         }
00460 
00461         break;
00462 
00463       default:
00464         // the user probably wants to see this
00465         _lastChar = ch;
00466         break;
00467       }
00468   }
00469   return _lastChar;
00470 }
00471 
00472 char 
00473 arch_info_parser::do_getc() {
00474   _wasNewLine = false;
00475 
00476   // gat a new char
00477   char c = fgetc( _pSpecFile );
00478 
00479   // is it an escape char?
00480   if ( c == '\\' ) {
00481     // line continuation character?
00482     char c2 = fgetc( _pSpecFile );
00483     if ( c2 == '\n' ) {
00484       // it was an escaped newline - eat the newline and give out next thing
00485       _currentLine++;
00486       return do_getc();
00487     } else {
00488       // put this back - it was not a newline
00489       ungetc( c2, _pSpecFile );
00490       return c;
00491     }
00492   } else if ( c == '\n' ) {
00493     _currentLine++;
00494     _wasNewLine = true;
00495   }
00496 
00497   return c;
00498 }
00499 
00500 void 
00501 arch_info_parser::do_ungetc( char c ) {
00502   // put it back
00503   ungetc( c, _pSpecFile );
00504 
00505   // fix line count if it was a newline
00506   if ( _wasNewLine ) {
00507     _wasNewLine = false;
00508     _currentLine--;
00509   }
00510 }
00511 
00512 bool 
00513 arch_info_parser::read_string( string & stringOut, bool readAnyChars, 
00514                                bool skipLeadingNewlines ) {
00515   // default to no results
00516   stringOut.clear();
00517 
00518   char c;
00519 
00520   // maybe skip leading newlines
00521   if ( skipLeadingNewlines )
00522     while ( (c = peek_char( true )) != EOF && c == '\n' )
00523       get_char();
00524 
00525   // read all the alphanums we can get in a row (skip preceding spaces)
00526   c = peek_char( true );
00527   while ( c != EOF 
00528           && c != '\n' 
00529           && (readAnyChars || _charClass[c] == ALPHANUM) ) {
00530     // add this to the string and get the next character
00531     stringOut.append( 1, c );
00532     get_char();
00533     c = peek_char(); // don't skip whitespace - that would reformat the string
00534   }
00535 
00536   // we succeeded if our string was non-empty
00537   return (! stringOut.empty());
00538 }
00539 
00540 bool 
00541 arch_info_parser::parse_reg_item( string keyName, reg_info_ptr toRead ) {
00542   // should have an equal sign first of all
00543   char c = get_char( true );
00544   if ( c != '=' )
00545     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00546 
00547   c = get_char( true );
00548 
00549   // it may be empty...
00550   if ( c == '\n' )
00551     return true;
00552 
00553   // now there should be an @ symbol to denote a register
00554   if ( c != '@' )
00555     PARSE_ERROR( ("expected '@' preceding register name") );
00556 
00557   // is there anything here for this item?  it's ok if there is not
00558   if ( peek_char( true ) == '\n' )
00559     return true;
00560 
00561   // now a string with the register name
00562   string regName;
00563   if ( !read_string( regName ) )
00564     PARSE_ERROR( ("expected register name after '@'") );
00565 
00566   // this thing really should already be in our list
00567   arch_info::register_info * info;
00568   if ( ! _pArchInfo->find_register_info( regName.c_str(), info ) )
00569     PARSE_ERROR( ("register '%s' is undefined - is it missing from the "
00570                   "RegsAll list?", regName.c_str()) );
00571 
00572   // set the member variable for this guy
00573   _pArchInfo->*toRead = info;
00574 
00575   // should have line terminator now
00576   c = get_char( true );
00577   if ( c != '\n' )
00578     PARSE_ERROR( ("expected newline after register name", regName.c_str()) );
00579 
00580   return true;
00581 }
00582 
00583 bool 
00584 arch_info_parser::parse_reg_list_item( string keyName, 
00585                                        reg_info_list_ptr toRead, 
00586                                        bool isMasterList, bool allowTokens ) {
00587   // clear out the list
00588   (_pArchInfo->*toRead).empty();
00589 
00590   // master list cannot have tokens
00591   assert( ! (isMasterList && allowTokens) );
00592 
00593   char c;
00594 
00595   // should have an equal sign first of all
00596   c = get_char( true );
00597   if ( c != '=' )
00598     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00599 
00600   // read a bunch of registers
00601   c = get_char( true );
00602   while ( c == '@' || (allowTokens && c == '$') ) {
00603     // now a string with the register name
00604     string regName;
00605     if ( !read_string( regName ) )
00606       PARSE_ERROR( ("expected register name after '%c'", c) );
00607 
00608     // is this the master list?
00609     if ( isMasterList ) {
00610       // add it to the list
00611       arch_info::register_info * info = new arch_info::register_info;
00612       info->_id = _pArchInfo->_nextRegId++;
00613       info->_name = regName;
00614       assert( (_pArchInfo->*toRead).size() == info->_id );
00615       (_pArchInfo->*toRead).push_back( info );
00616       
00617       // add it to the map
00618       _pArchInfo->_regMap[ regName ] = info;
00619     } else {
00620       // go find it in existing list
00621       arch_info::register_info * info;
00622       if ( ! _pArchInfo->find_register_info( regName.c_str(), info ) )
00623         PARSE_ERROR( ("register '%s' is undefined - is it missing from the "
00624                       "RegsAll list?", regName.c_str()) );
00625 
00626       // add it to the list
00627       (_pArchInfo->*toRead).push_back( info );
00628     }
00629 
00630     // get the next
00631     c = get_char( true );
00632   }
00633 
00634   // whatever's left should be line terminator
00635   if ( c != '\n' )
00636     PARSE_ERROR( ("after '=', expected register list followed by newline") );
00637 
00638   return true;
00639 }
00640 
00641 bool 
00642 arch_info_parser::parse_string_item( string keyName, string_ptr toRead ) {
00643   // should have an equal sign first of all
00644   char c = get_char( true );
00645   if ( c != '=' )
00646     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00647 
00648   // is there anything here for this item?  it's ok if there is not
00649   if ( peek_char( true ) == '\n' )
00650     return true;
00651 
00652   // read everything up to newline
00653   string str;
00654   c = get_char( true );
00655   while ( c != EOF && c != '\n' ) {
00656     // add this to the string and get next char
00657     str.append( 1, c );
00658     c = get_char( false ); // preserve whitespace inside string
00659   }
00660 
00661   // save this thing
00662   _pArchInfo->*toRead = str;
00663 
00664   return true;
00665 }
00666 
00667 bool 
00668 arch_info_parser::parse_integer_item( string keyName, int_ptr toRead ) {
00669   // should have an equal sign first of all
00670   char c = get_char( true );
00671   if ( c != '=' )
00672     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00673 
00674   // is there anything here for this item?  it's ok if there is not
00675   if ( peek_char( true ) == '\n' )
00676     return true;
00677 
00678   // read a string after the equal sign
00679   string str;
00680   if ( ! read_string( str ) )
00681     PARSE_ERROR( ("expected numeric constant after '='") );
00682 
00683   // any invalid chars?
00684   int value = atoi( str.c_str() );
00685   if ( value == 0 && str.find_first_not_of( "0123456789" ) != -1 )
00686     PARSE_ERROR( ("expected numeric constant after '='") );
00687 
00688   // whatever's left should be line terminator
00689   c = get_char( true );
00690   if ( c != '\n' )
00691     PARSE_ERROR( ("expected newline after integer constant") );
00692 
00693   // save this thing
00694   _pArchInfo->*toRead = value;
00695 
00696   return true;
00697 }
00698 
00699 bool 
00700 arch_info_parser::parse_bool_item( string keyName, bool_ptr toRead ) {
00701   // should have an equal sign first of all
00702   char c = get_char( true );
00703   if ( c != '=' )
00704     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00705 
00706   // read a string after the equal sign
00707   string str;
00708   if ( ! read_string( str ) )
00709     PARSE_ERROR( ("expected boolean value after '='") );
00710 
00711   // this string has to be "true", "false", "yes", or "no"
00712   cbz_util::string_to_lower( str );
00713   if ( str == "true" || str == "yes" )
00714     _pArchInfo->*toRead = true;
00715   else if ( str == "false" || str == "no" )
00716     _pArchInfo->*toRead = false;
00717   else
00718     PARSE_ERROR( ("expected 'true'/'yes' or 'false'/'no' after '='") );
00719 
00720   // whatever's left should be line terminator
00721   c = get_char( true );
00722   if ( c != '\n' )
00723     PARSE_ERROR( ("expected newline after integer constant") );
00724 
00725   return true;
00726 }
00727 
00728 bool 
00729 arch_info_parser::parse_vartype_item( string keyName, vartype_ptr toRead ) {
00730   // should have an equal sign first of all
00731   char c = get_char( true );
00732   if ( c != '=' )
00733     PARSE_ERROR( ("expected '=' after key '%s'", keyName.c_str()) );
00734 
00735   // read a string after the equal sign
00736   string typeStr;
00737   if ( ! read_string( typeStr ) )
00738     PARSE_ERROR( ("expected data type after '='") );
00739 
00740   // this string has to map to a variable type
00741   cbz_util::string_to_lower( typeStr );
00742   vartype_map::iterator it = _varTypeMap.find( typeStr );
00743   if ( it == _varTypeMap.end() )
00744     PARSE_ERROR( ("unrecognized variable type '%s'", typeStr.c_str()) );
00745 
00746   // whatever's left should be line terminator
00747   c = get_char( true );
00748   if ( c != '\n' )
00749     PARSE_ERROR( ("expected newline after integer constant") );
00750 
00751   // save it
00752   _pArchInfo->*toRead = (*it).second;
00753 
00754   return true;
00755 }
00756 
00757 bool 
00758 arch_info_parser::parse_Lir2Asm_item( string keyName, 
00759                                       Lir2Asm_list_ptr toAppend ) {
00760   // ignore line breaks and such
00761   char c;
00762   while ( (c = get_char( true )) == '\n' );
00763 
00764   // should have a bracket
00765   if ( c != '[' )
00766     PARSE_ERROR( ("expected '[' after '%s'", keyName.c_str()) );
00767 
00768   // read the different parts
00769   bool hasCode = false;
00770   arch_info::Lir2Asm lir2asm;
00771   lir2asm.reset();
00772   string keyStr;
00773   while ( read_string( keyStr, false, true ) ) {
00774     string keyStrLower = keyStr;
00775     cbz_util::string_to_lower( keyStrLower );
00776     if ( keyStrLower == "lir" ) {
00777       // parse a string here
00778       _pArchInfo->_tempParseString.clear();
00779       if ( ! parse_string_item( "lir", &arch_info::_tempParseString ) )
00780         return false;
00781       string mnemonicStr = _pArchInfo->_tempParseString;
00782       _pArchInfo->_tempParseString.clear();
00783 
00784       // look up the mnemonic
00785       string tempStr( mnemonicStr );
00786       cbz_util::string_to_lower( tempStr );
00787       mnemonic_map::iterator it = _mnemonicMap.find( tempStr );
00788       if ( it == _mnemonicMap.end() )
00789         PARSE_ERROR( ("unrecognized LIR instruction '%s'", 
00790                       mnemonicStr.c_str()) );
00791 
00792       // save the actual enumerated type of the mnemonic
00793       lir2asm._lirInstTypes.push_back( (*it).second );
00794     } else if ( keyStrLower == "datatype" ) {
00795       // parse a string here
00796       _pArchInfo->_tempParseString.clear();
00797       if ( ! parse_string_item( "datatype", &arch_info::_tempParseString ) )
00798         return false;
00799       string typeStr = _pArchInfo->_tempParseString;
00800       _pArchInfo->_tempParseString.clear();
00801 
00802       // look up the variable type
00803       string tempStr( typeStr );
00804       cbz_util::string_to_lower( tempStr );
00805       vartype_map::iterator it = _varTypeMap.find( tempStr );
00806       if ( it == _varTypeMap.end() )
00807         PARSE_ERROR( ("unrecognized variable type '%s'", typeStr.c_str()) );
00808 
00809       // add this variable type to supported list for this record
00810       lir2asm._dataTypes.push_back( (*it).second );
00811     } else if ( keyStrLower == "converttotype" ) {
00812       // parse a string here
00813       _pArchInfo->_tempParseString.clear();
00814       if ( ! parse_string_item( "converttotype", 
00815                                 &arch_info::_tempParseString ) )
00816         return false;
00817       string typeStr = _pArchInfo->_tempParseString;
00818       _pArchInfo->_tempParseString.clear();
00819 
00820       // look up the variable type
00821       string tempStr( typeStr );
00822       cbz_util::string_to_lower( tempStr );
00823       vartype_map::iterator it = _varTypeMap.find( tempStr );
00824       if ( it == _varTypeMap.end() )
00825         PARSE_ERROR( ("unrecognized variable type '%s'", typeStr.c_str()) );
00826 
00827       // add this variable type to supported list for this record
00828       lir2asm._convertToTypes.push_back( (*it).second );
00829     } else if ( keyStrLower == "kill" ) {
00830       // read a standard register list into class temporary list
00831       _pArchInfo->_tempRegList.clear();
00832       if ( ! parse_reg_list_item( "kill", &arch_info::_tempRegList, false, 
00833                                   true ) )
00834         return false;
00835 
00836       // set this to be the arch_info::Lir2Asm thing's list
00837       cbz_util::vector_copy( _pArchInfo->_tempRegList, lir2asm._killRegs );
00838       _pArchInfo->_tempRegList.clear();
00839     } else if ( keyStrLower == "immed" ) {
00840       // read true/false for this guy's immediate field
00841       _pArchInfo->_tempBool = false;
00842       if ( ! parse_bool_item( "immed", &arch_info::_tempBool ) )
00843         return false;
00844       lir2asm._immed = _pArchInfo->_tempBool ? 
00845         arch_info::Lir2Asm::Immed_Yes : 
00846         arch_info::Lir2Asm::Immed_No;
00847     } else if ( keyStrLower == "code" ) {
00848       char c;
00849 
00850       // there is code for this template
00851       hasCode = true;
00852 
00853       // eat all whitespace including newlines
00854       while ( (c = peek_char( true )) == '\n' || _charClass[c] == WS )
00855         get_char();
00856 
00857       // what's next?
00858       get_char();
00859       if ( c == '=' ) {
00860         // just read a string (should be the code)
00861         string str;
00862         if ( read_string( str, true ) ) {
00863           // this is the code for this guy
00864           lir2asm._codeTemplate.push_back( str );
00865         }
00866 
00867         // eat up to and including newline
00868         c = get_char( true );
00869         assert( c == EOF || c == '\n' );
00870         get_char();
00871       } else if ( c == '{' ) {
00872         // read as many lines as we need
00873         while ( 1 ) {
00874           // read all chars on this line (skip leading whitespace)
00875           string line;
00876           c = get_char( true );
00877           while ( c != EOF && c != '\n' && c != '}' ) {
00878             line += c;
00879             c = get_char();
00880           }
00881 
00882           // add to list
00883           if ( ! line.empty() )
00884             lir2asm._codeTemplate.push_back( line );
00885 
00886           // are we done?
00887           if ( c == EOF || c == '}' )
00888             break;
00889         }
00890       } else {
00891         // we have no idea what to do here
00892         PARSE_ERROR( ("missing '=' or '{' after 'code'") );
00893       }
00894     } else {
00895       // we have no idea what this thing is
00896       PARSE_ERROR( ("unrecognized key string '%s'.", keyStr.c_str()) );
00897     }
00898   }
00899 
00900   // look for close bracket
00901   while ( (c = get_char( true )) == '\n' );
00902   if ( c != ']' )
00903     PARSE_ERROR( ("expected ']' after arch_info::Lir2Asm record") );
00904 
00905   // is there code for this template?  if not, don't add it to any lists.
00906   if ( ! hasCode )
00907     return true;
00908 
00909   // add this to the list
00910   _pArchInfo->_Lir2Asm_records.push_back( lir2asm );
00911   int addpos = (int)(_pArchInfo->_Lir2Asm_records.size()) - 1;
00912   assert( addpos >= 0 );
00913 
00914   // setup the map - we are mapping from LIR mnemonic to array index of
00915   // this arch_info::Lir2Asm thingy
00916   size_t sz = lir2asm._lirInstTypes.size();
00917   for ( int i = 0; i < (int)sz; ++i ) {
00918     // is there a vector for this guy?  if not, insert one
00919     arch_info::map_menmonic_to_record_set::iterator it = 
00920       _pArchInfo->_Lir2Asm_mnemonicLookup.find( lir2asm._lirInstTypes[i] );
00921     if ( it == _pArchInfo->_Lir2Asm_mnemonicLookup.end() ) {
00922       arch_info::map_menmonic_to_record_set::value_type toInsert( lir2asm._lirInstTypes[i], vector<int>() );
00923       it = _pArchInfo->_Lir2Asm_mnemonicLookup.insert( toInsert ).first;
00924     }
00925 
00926     // add this thing to the list
00927     it->second.push_back( addpos );
00928   }
00929 
00930   return true;
00931 }
00932 

Generated on August 27, 2003
Back to the C-Breeze home page