/* scn.cpp: implementation of lexical scanner for GNU/TOL Language. Copyright (C) 2005 - Bayes Decision, SL (Spain [EU]) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if defined(_MSC_VER) #include #endif #include #include BTraceInit("scn.cpp"); /*! Structure where recognizables tokens of TOL language are stored. * This object is created in PutSymbolTable method, called from * constructor. * \sa PutSymbolTable */ BScanner::BTokenByNameHash BScanner::symbolTable_; BScanner::BTokenByNameHash BScanner::aliasTable_; BScanner::BTokenByNameHash BScanner::usrDefSymbol_; //!< User defined symbols Class, Struct, ... BScanner* BScanner::current_ = NULL; //-------------------------------------------------------------------- BScanner::BScanner() /*! Create BScanner object.
* Create and initialize \a symbolTable_ with * Initialize \a position_, \a nextSymbol_, \a nextArgument_. */ //-------------------------------------------------------------------- { //Std(BText("\nCreating BScanner ")+(BInt)this); PutSymbolTable(); position_ = NIL; nextSymbol_ = NIL; lastSymbol_ = NIL; nextArgument_ = ""; structDefininig_ = false; } //-------------------------------------------------------------------- BScanner::~BScanner() //-------------------------------------------------------------------- { //Std(BText("\nDestroying BScanner ")+(BInt)this); } //-------------------------------------------------------------------- BInt BTokenOrderCriterium(const BAny vBToken1, const BAny vBToken2) /*! Comparision function to sort by name in arrays of BToken* */ //-------------------------------------------------------------------- { /* BToken& sym1 = **((BToken**)vBToken1); BToken& sym2 = **((BToken**)vBToken2); BInt cmp = StrCmp(sym1.String(), sym2.String()); return(cmp); */ BToken* sym1 = *(BToken**)vBToken1; BToken* sym2 = *(BToken**)vBToken2; if (!sym1 && !sym2) { return( 0); } else if(!sym1 && sym2) { return( 1); } else if( sym1 && !sym2) { return(-1); } else { return(StrCmp(sym1->String(), sym2->String())); } } //-------------------------------------------------------------------- BInt Str2SymCmp(const BAny vBChar, const BAny vBToken) /*! Comparision function to find by name in sorted arrays of BToken* *
Obsolete method. Not used by TOL code */ //-------------------------------------------------------------------- { BChar* str = (BChar*) vBChar; BToken& sym = **(BToken**) vBToken; return(strcmp(str, sym.String())); } //#define _USE_TRACE_CURRENT_NEXTARGUMENT_ #if defined( _USE_TRACE_CURRENT_NEXTARGUMENT_ ) //-------------------------------------------------------------------- static void _trace_current_nextArgument_( const char* function, int itemNum) //-------------------------------------------------------------------- { if(BScanner::GetCurrent()) { Std(BText("\n _TRACE_CURRENT_NEXTARGUMENT_(")+function+","+itemNum+") " " -> '"+BScanner::GetCurrent()->NextArgument()+"'\n"); } } #endif #ifdef _USE_TRACE_CURRENT_NEXTARGUMENT_ #define _TRACE_CURRENT_NEXTARGUMENT_(function,itemNum) \ _trace_current_nextArgument_(function,itemNum) #else #define _TRACE_CURRENT_NEXTARGUMENT_(function,itemNum) #endif //-------------------------------------------------------------------- BToken* BScanner::FindSymbol(const BText& name) /*! Find a symbol in \a symbolTable_ which name is \a str and * returns it if exists, else return NIL. * \param str Name of BToken symbol that will be searched * \return BToken found in \a symbolTable_ * \sa BArray::FindSorted */ //-------------------------------------------------------------------- { _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",1); if(!name.HasName()) { return(NULL); } BToken* tok = NULL; _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",2); BTokenByNameHash::const_iterator found; _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",3); found = symbolTable_.find(name); _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",4); if(found==symbolTable_.end()) { _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",5); found = aliasTable_.find(name); _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",6); if(found!=aliasTable_.end()) { _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",7); tok = found->second; _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",8); } _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",9); } else { _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",10); tok = found->second; _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",11); } _TRACE_CURRENT_NEXTARGUMENT_("FindSymbol",12); return(tok); } //-------------------------------------------------------------------- BToken* BScanner::FindSymbol(const BChar* str) /*! Find a symbol in \a symbolTable_ which name is \a str and * returns it if exists, else return NIL. * \param str Name of BToken symbol that will be searched * \return BToken found in \a symbolTable_ * \sa BArray::FindSorted */ //-------------------------------------------------------------------- { BText name = str; return(FindSymbol(name)); } //-------------------------------------------------------------------- BInt BScanner::CountSymbols() /*! Return size of \a symbolTable_ attribute. */ //-------------------------------------------------------------------- { return(symbolTable_.size()); } //-------------------------------------------------------------------- BInt BScanner::AddSymbol(BToken* sym) /*! Store in \a symbolTable_ BToken \a sym parameter. * \param sym BToken that will be stores in \a symbolTable_ * \return Size of symbolTable_ * \sa BArray::AddSorted */ //-------------------------------------------------------------------- { const BText& name = sym->Name(); assert(name.HasName()); BToken* s = FindSymbol(name); if(!s) { //Std(BText("\nAdding Symbol <") + sym->Name()+">"); s = symbolTable_[name] = sym; if(sym->TokenType()==TYPE) { usrDefSymbol_[name]=sym; } } s->IncNRefs(); return(symbolTable_.size()); } //-------------------------------------------------------------------- BInt BScanner::DelSymbol(const BText& name) /*! Remove BToken with \a name_ attribute equal to \a str parameter * from symbolTable_. * \param str Char* value of \a name_ of BToken that will be removed * \return symbolTable_ size. * \sa BArray::FindSorted, BArray::ReallocBuffer */ //-------------------------------------------------------------------- { BToken* s = FindSymbol(name); if(s) { s->DecNRefs(); if(!s->NRefs()) { symbolTable_.erase(name); } } return(symbolTable_.size()); } //-------------------------------------------------------------------- BInt BScanner::DelSymbol(const BChar* str) /*! Remove BToken with \a name_ attribute equal to \a str parameter * from symbolTable_. * \param str Char* value of \a name_ of BToken that will be removed * \return symbolTable_ size. * \sa BArray::FindSorted, BArray::ReallocBuffer */ //-------------------------------------------------------------------- { BText name = str; return(DelSymbol(name)); } //-------------------------------------------------------------------- // Tables of tokens by type //-------------------------------------------------------------------- static BOpenToken defOpe_[] = { BOpenToken("("), BOpenToken("["), BOpenToken("{"), BOpenToken("#{#"), BOpenToken("#(#") }; static BCloseToken defClo_[] = { BCloseToken(")", &(defOpe_[0])), BCloseToken("]", &(defOpe_[1])), BCloseToken("}", &(defOpe_[2])), BCloseToken("#}#", &(defOpe_[3])), BCloseToken("#)#", &(defOpe_[4])) }; //-------------------------------------------------------------------- char GetIdFromTokenClose(BCloseToken* c) //-------------------------------------------------------------------- { BCloseToken* t = &(defClo_[0]); if(!c) { return('\0'); } assert((c>=t)&&(c=0)&&(k<=5)); if(!k) { return(NULL); } return(&defClo_[k-1]); } static BSeparatorToken defSep_[] = { BSeparatorToken(";", 1), BSeparatorToken(",", 2) }; static BToken defBin_[] = { BBinaryToken("=", 3), // 0 BBinaryToken(":=", 3), // 1 BBinaryToken("#F#", 4), // 2 BBinaryToken("|", 5), // 3 BBinaryToken("&", 6), // 4 BBinaryToken("Of", 7), // 5 BBinaryToken(">", 8), // 6 BBinaryToken("<", 8), // 7 BBinaryToken(">", 8), // 8 BBinaryToken("==", 8), // 9 BBinaryToken(">=", 8), // 10 BBinaryToken("<=", 8), // 11 BBinaryToken(":>", 8), // 12 BBinaryToken("<:", 8), // 13 BBinaryToken("!=", 8), // 14 BBinaryToken("#+#", 9), // 15 BBinaryToken("#-#", 9), // 16 BBinaryToken("*", 10), // 17 BBinaryToken("$*", 10), // 18 BBinaryToken("/", 11), // 19 BBinaryToken("$/", 11), // 20 BBinaryToken("%", 11), // 21 BBinaryToken("^", 12), // 22 BBinaryToken("**", 12), // 23 BBinaryToken("&&", 13), // 24 BBinaryToken("||", 13), // 25 BBinaryToken(":", 14), // 26 BBinaryToken("<<", 15), // 27 BBinaryToken(">>", 15), // 28 BBinaryToken("->", 16), // 29 BBinaryToken("#E#", 17), // 30 BBinaryToken("#::#", 18) // 31 }; static BMonaryToken defMon_[] = { BMonaryToken("+", &(defBin_[15])), BMonaryToken("-", &(defBin_[16])), BMonaryToken("~"), BMonaryToken("!"), BMonaryToken("$"), BMonaryToken("Do"), BMonaryToken("Struct"), BMonaryToken("Class"), BMonaryToken("Static"), BMonaryToken("::", &(defBin_[31])) }; static BTypeToken defTyp_[] = { BTypeToken("Anything", BTypeToken::BSYSTEM), BTypeToken("Set", BTypeToken::BSYSTEM), BTypeToken("Date", BTypeToken::BSYSTEM), BTypeToken("CTime", BTypeToken::BSYSTEM), BTypeToken("Real", BTypeToken::BSYSTEM), BTypeToken("Complex", BTypeToken::BSYSTEM), BTypeToken("Matrix", BTypeToken::BSYSTEM), BTypeToken("VMatrix", BTypeToken::BSYSTEM), BTypeToken("Polyn", BTypeToken::BSYSTEM), BTypeToken("Ratio", BTypeToken::BSYSTEM), BTypeToken("Text", BTypeToken::BSYSTEM), BTypeToken("TimeSet", BTypeToken::BSYSTEM), BTypeToken("CTimeSet", BTypeToken::BSYSTEM), BTypeToken("Serie", BTypeToken::BSYSTEM), BTypeToken("CSeries", BTypeToken::BSYSTEM), BTypeToken("Code", BTypeToken::BSYSTEM), BTypeToken("NameBlock", BTypeToken::BSYSTEM), BTypeToken("PolMatrix", BTypeToken::BSYSTEM), BTypeToken("#Require", BTypeToken::BSYSTEM) }; static BMacroToken defMac_[] = { BMacroToken("#Embed") }; static const char* alias_[][2] = { { "Ration", "Ratio" } }; static const char* usrDef_[] = { "Struct", "Class" }; static BInt defOpeNum_ = sizeof(defOpe_)/sizeof(BOpenToken); static BInt defCloNum_ = sizeof(defClo_)/sizeof(BCloseToken); static BInt defSepNum_ = sizeof(defSep_)/sizeof(BSeparatorToken); static BInt defBinNum_ = sizeof(defBin_)/sizeof(BBinaryToken); static BInt defMonNum_ = sizeof(defMon_)/sizeof(BMonaryToken); static BInt defTypNum_ = sizeof(defTyp_)/sizeof(BTypeToken); static BInt defMacNum_ = sizeof(defMac_)/sizeof(BMacroToken); static BInt aliasNum_ = sizeof(alias_ )/sizeof(alias_ [1]); static BInt usrDefNum_ = sizeof(usrDef_)/sizeof(usrDef_[1]); static BInt defTokNum_ = defOpeNum_ + defCloNum_ + defSepNum_ + defBinNum_ + defMonNum_ + defTypNum_ + defMacNum_ ; //-------------------------------------------------------------------- void BScanner::PutSymbolTable() /*! Puts all recognizables tokens of TOL in \a symbolTable_ static * attribute and sorts it.
* Different types of tokens, stored in different static tables:
*
    *
  • \a defOpe_ array for tokens that represents open symbols *
  • \a defClo_ array for tokens that represents close symbols *
  • \a defSep_ array for tokens that represents separator symbols *
  • \a defBin_ array for tokens that represents binary symbols *
  • \a defMon_ array for tokens that represents monary symbols *
  • \a defTyp_ array for tokens that represents types *
*/ //-------------------------------------------------------------------- { static bool symbolTableFilled_ = BFALSE; if (!symbolTableFilled_) { SetEmptyKey(symbolTable_, NULL); SetDeletedKey(symbolTable_, name_del_key()); symbolTableFilled_ = BTRUE; BInt n=0, m=0; for(n=0; n * Algorythm: *
    *
  1. If there are no more text -> returns the type NONE.

    *
  2. Else-If the next no blank character is a comma then:

    *
      *
    1. Puts the text until the next comma in \a nextArgument_ field, *
    2. moves \a position_ after the last comma, and *
    3. returns the type ARGUMENT. *


    *
  3. Else reads the word until next blank character. Then

    *
      *
    1. Moves \a position_ after the blank character, and *
        *
      1. If this word is the name of a token then: *
          *
        1. Puts the word in \a nextSymbol_ field, *
        2. returns the type of the found token. *
        *
      2. else *
          *
        1. Puts NIL in \a nextSymbol_ field, *
        2. puts the word in \a nextArgument_ field, *
        3. returns the type ARGUMENT. *
        *
      *
    *
*/ BTokenType BScanner::NextWordType() { BChar nextWord[256]; BTokenByNameHash::const_iterator found; static BToken* structToken_ = NULL; static BToken* fieldToken_ = NULL; if(!structToken_) { structToken_ = FindSymbol("Struct"); fieldToken_ = FindSymbol("->"); } BTokenType type = ARGUMENT; if(nextSymbol_) { lastSymbol_ = nextSymbol_; } nextSymbol_ = NIL; if(NextChar()) { if(position_[0]=='\"') { BInt n=0; do { n++; } while(position_[n] && (position_[n]!='\"')); nextArgument_.Copy(position_, n); nextArgument_.Replace("\\'","\""); position_+=n+1; } else { BInt nChar; if(sscanf(position_, "%s%n", nextWord, &nChar)) { BInt rest = expression_+length_-position_; if(rest>nChar) { position_+=nChar; } else { position_=expression_+length_; } if(nChar>255) nextWord[255]='\0'; nextSymbol_ = FindSymbol(nextWord); if(nextSymbol_ && lastSymbol_) { if((lastSymbol_==structToken_) && (nextSymbol_->TokenType()==OPEN)) { structDefininig_ = true; } else if(structDefininig_ && (nextSymbol_->TokenType()==CLOSE)) { structDefininig_ = false; } else if(structDefininig_ && (lastSymbol_->TokenType()==TYPE)) { found = usrDefSymbol_.find(nextSymbol_->Name()); if(found != usrDefSymbol_.end()) { nextSymbol_ = NULL; } } else { //if((nextSymbol_->Name()=="Class")&&(lastSymbol_->Name()=="->")) if(lastSymbol_== fieldToken_) { found = usrDefSymbol_.find(nextSymbol_->Name()); if(found != usrDefSymbol_.end()) { nextSymbol_ = NULL; } } } } if(nextSymbol_) { type = nextSymbol_->TokenType(); } else { nextArgument_.Copy(nextWord,nChar); } } } } else { type = NONE; } return(type); } //-------------------------------------------------------------------- /*! Reads the next word. * If its type is ARGUMENT read the next word and returns its type, * else returns ARGUMENT type. * \return Type of next word to be scanned * \sa BScanner::NextWordType */ BTokenType BScanner::ReadNextSymbol() { if(nextSymbol_) { lastSymbol_ = nextSymbol_; } nextSymbol_ = NIL; nextArgument_ = ""; BTokenType type = NextWordType(); if(type==ARGUMENT) { type = NextWordType(); } return (type); } //-------------------------------------------------------------------- BText BScanner::Scanned() /*! Returns the text scanned at this moment. * Its usefull for parser error messages. */ //-------------------------------------------------------------------- { return(BText(expression_,0,(position_-expression_)-1)); }