📄 cjparser.cpp
字号:
// "reversed" versions of skip_token() and get_next_token()static inline void skip_token_back( char*& cur ){ // FIXME:: now, when moving backwards, neither strings nor // comment blocks are checked --cur; // skip to the trailing character if ( *cur == ',' || *cur == ')' || *cur == '(' ) return; for( ; cur < _gSrcEnd ; --cur ) { switch ( *cur ) { case ' ' : break; case '\t': break; case 13 : break; case 10 : break; case ',' : break; case '(' : break; default : continue; }; break; } ++cur; // get to the leading character of the token}static inline void skip_next_token_back( char*& cur ){ --cur; // skip leading character of the current token if ( *cur == ',' || *cur == ')' || *cur == '(' ) { ++cur; return; } for( ; cur < _gSrcEnd; --cur ) { switch ( *cur ) { case ' ' : continue; case '\t': continue; case 13 : continue; case 10 : continue; case ',' : continue; case '(' : continue; default : break; }; break; } ++cur; // position after the trailing charcter of the prev token}static wxString get_token_str( char* cur ){ return wxString( cur, get_token_len( cur ) );}// skips token or whole expression which may have// nested expressions between '(' ')' brackets.//// Upon return, the cursor points to the terminating bracket ')',//// Return value is the size of the blockstatic size_t skip_block( char*& cur ){ size_t level = 0; // nesting level char* start = cur; // NOTE:: assumed that block not necessarely starts // with bracket rightaway if ( *cur == '(' ) { ++level; } do { skip_token( cur ); char* savedPos = cur; int tmpLnNo; store_line_no( tmpLnNo ); get_next_token( cur ); if ( cur >= _gSrcEnd ) return 0; if ( *cur == '(' ) { ++level; } else if ( *cur == ')' ) { if ( level == 0 ) { cur = savedPos; restore_line_no( tmpLnNo ); return size_t(cur-start); } --level; if ( level == 0 ) { ++cur; // QUICK-HACK::to easily handle function prototypes , // it works, besause theoretically there should // be no cast-expressions in non-implementation // scope (e.g. "time( (long*)(ptr+1) )" should not // appear in the declarations, thus it is most likelly // for the ")(" fragment to be within a function // prototype in the declarations scope if ( *cur == '(' ) { ++level; continue; } else return size_t(cur-start); } } else { if ( level == 0 ) { cur = savedPos; restore_line_no( tmpLnNo ); return size_t(cur-start); } } } while(1);}// returns 0, if end of source reachedstatic inline bool skip_imp_block( char*& cur ){ while( *cur != '{' && cur < _gSrcEnd ) { skip_token( cur ); if ( !get_next_token( cur ) ) return false; } while( *cur != '}' && cur < _gSrcEnd ) { skip_token( cur ); if ( !get_next_token( cur ) ) return false; } ++cur; return true;}static bool is_class_token( char*& cur ){ // FIXME:: the below mess should be cleaned in it's entirely if ( *cur == 'i' ) if ( *(cur+1) == 'n' ) return cmp_tokens_fast( cur, "interface", 9 ); if ( *cur == 'c' ) if ( *(cur+1) == 'l' ) return cmp_tokens_fast( cur, "class", 5 ); if ( *cur == 's' ) if ( *(cur+1) == 't' ) return cmp_tokens_fast( cur, "struct", 6 ); if ( *cur == 'u' ) if ( *(cur+1) == 'n' ) return cmp_tokens_fast( cur, "union", 5 ); return false;}inline static bool is_forward_decl( char* cur ){ do { switch( *cur ) { case ':' : return false; case '{' : return false; case '(' : return false; case ';' : return true; default : break; }; ++cur; } while (cur < _gSrcEnd); // prevent running out of bounds return false;}inline static bool is_function( char* cur, bool& isAMacro ){ isAMacro = false; int tmpLnNo; store_line_no( tmpLnNo ); // NOTE:: comments and quoted strings are not checked here // first,check for "single-line hanginging macros" like: // ___UNICODE // char* eol = cur; skip_to_eol( eol ); skip_token( cur ); get_next_token( cur ); if ( cur > eol ) { isAMacro = true; restore_line_no( tmpLnNo ); return true; } // it's not a macro, go to the begining of arg. list do { // if bracket found, it's a function or a begining // of some macro if ( *cur == '(' ) { restore_line_no( tmpLnNo ); return true; } // end of statement found without any brackets in it // - it cannot be a function if ( *cur == ';' ) { restore_line_no( tmpLnNo ); return false; } ++cur; } while( cur < _gSrcEnd); isAMacro = 1; restore_line_no( tmpLnNo ); return false;}// upon return the cursor is positioned after the// terminating curly bracestatic inline void skip_scope_block( char*& cur ){ size_t level = 0; for( ; cur < _gSrcEnd ; ++cur ) switch( *cur ) { case '/' : skip_comments( cur ); --cur; continue; case '"' : skip_quoted_string( cur ); --cur; continue; case '{' : ++level; continue; case '}' :--level; if ( level == 0 ) { ++cur; // skip final closing curly brace return; } case 10 : ++_gLineNo; continue; default : continue; };}// moves tokens like '*' '**', '***', '&' from the name// to the typestatic void arrange_indirection_tokens_between( wxString& type, wxString& identifier ){ // TBD:: FIXME:: return value of operators ! while ( identifier[0u] == _T('*') || identifier[0u] == _T('&') ) { type += identifier[0u]; identifier.erase(0,1); if ( !identifier.length() ) return; }}// the only function where multi-lang keyword map is accessedstatic bool is_keyword( char* cur ){ size_t len = get_token_len( cur ); // put a terminating zero after the given token char tmp = *(cur + len); *(cur+len) = '\0'; KeywordMapT::iterator i; i = __gMultiLangMap.find( cur ); // restore original character suppresed by terminating zero *(cur + len) = tmp; return i == __gMultiLangMap.end() ? false : true;}static inline void get_string_between( wxChar* start, wxChar* end, wxString* pStr ){ char saved = *end; *end = _T('\0'); *pStr = start; *end = saved;}static wxChar* set_comment_text( wxString& text, wxChar* start ){ wxChar* end = start; // to avoid poluting the queue with this comment _gLastSuppresedComment = start; skip_comments( end ); if ( *(end-1) == _T('/') ) end -= 2; start += 2; // skip multiple leading '/''s or '*''s while( *start == _T('/') && start < end ) ++start; while( *start == _T('*') && start < end ) ++start; get_string_between( start, end, &text ); return end;}/***** Implementation for class CJSourceParser *****/CJSourceParser::CJSourceParser( bool collectCommnets, bool collectMacros ) : mpStart(0), mpEnd(0), mpCurCtx( 0 ), mCommentsOn( collectCommnets ), mMacrosOn ( collectMacros ){ check_keyword_map();}spFile* CJSourceParser::Parse( char* start, char* end ){ // set up state variables mCurVis = SP_VIS_PRIVATE; spFile* pTopCtx = new spFile(); mpCurCtx = pTopCtx; mIsVirtual = 0; mIsTemplate = 0; mNestingLevel = 0; m_cur = start; mpStart = start; mpEnd = end; _gSrcEnd = mpEnd; // let all the C-functions "smell" the end of file _gSrcStart = start; _gLineNo = 0; clear_commets_queue(); // main parsing loop do { if ( !get_next_token( m_cur ) ) // end of source reached return pTopCtx; if ( memcmp( m_cur, "ScriptSection( const string&", strlen( "ScriptSection( const string&" ) ) == 0 ) { // int o = 0; // ++o; } switch (*m_cur) { case '#' : { AddMacroNode( m_cur ); continue; } case ':' : { skip_token( m_cur ); continue; } case ';' : { skip_token( m_cur ); continue; } case ')' : { skip_token( m_cur ); continue; } case '=' : { skip_token( m_cur ); continue; } default: break; } // 'const' is a part of the return type, not a keyword here if ( strncmp(m_cur, "const", 5) != 0 && is_keyword( m_cur ) ) { // parses, token, if token identifies // the container context (e.g. class/namespace) // the corresponding context object is created // and set as current context ParseKeyword( m_cur ); continue; } if ( *m_cur >= _T('0') && *m_cur <= _T('9') ) { skip_token( m_cur ); continue; } if ( *m_cur == _T('}') ) { if ( mCurCtxType != SP_CTX_CLASS ) { // FOR NOW:: disable the below assertion // DBG:: unexpected closing-bracket found //ASSERT(0); skip_token( m_cur ); // just skip it continue; } if ( mpCurCtx->GetType() == SP_CTX_CLASS ) { int curOfs = ( (m_cur+1) - _gSrcStart ); mpCurCtx->mContextLength = ( curOfs - mpCurCtx->mSrcOffset ); } --mNestingLevel; // terminate operation/class/namespace context // TBD:: check if it's really this type of context wxASSERT( mpCurCtx ); mpCurCtx = mpCurCtx->GetOutterContext(); wxASSERT( mpCurCtx ); if ( mNestingLevel == 0 ) { mCurCtxType = SP_CTX_FILE; // not-nested class delclaration finished, // rest template flag in any case mIsTemplate = 0; } skip_token( m_cur ); continue; } bool isAMacro = false; if ( is_function( m_cur, isAMacro ) ) { if ( isAMacro ) { skip_token( m_cur ); continue; } char* savedPos = m_cur; int tmpLnNo; store_line_no( tmpLnNo ); wxUnusedVar( tmpLnNo ); isAMacro = false; if ( !ParseNameAndRetVal( m_cur, isAMacro ) ) { if ( !isAMacro ) { m_cur = savedPos; SkipFunction( m_cur ); } continue; } if ( !ParseArguments( m_cur ) ) { // failure while parsing arguments,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -