📄 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 block
static 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 reached
static 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 brace
static 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 type
static 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 accessed
static 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 + -