📄 cjparser.cpp
字号:
// remove enclosing operation context
spContext* pFailed = mpCurCtx;
mpCurCtx = mpCurCtx->GetOutterContext();
mpCurCtx->RemoveChild( pFailed );
skip_to_eol( m_cur );
//m_cur = savedPos;
}
else
{
// otherwise, successfully close operation context:
clear_commets_queue();
SkipFunctionBody( m_cur );
mpCurCtx = mpCurCtx->GetOutterContext();
// DBG::
wxASSERT( mpCurCtx );
}
}
else // otherwise it's declaration of a variable;
{
// now, the cursor point to the end of statement (';' token)
if ( mCurCtxType != SP_CTX_CLASS )
{
// non-class members are ignored
skip_token( m_cur ); // skip the end of statement
continue;
}
ParseMemberVar( m_cur );
}
} while( 1 );
}
void CJSourceParser::AttachComments( spContext& ctx, wxChar* cur )
{
if ( !mCommentsOn ) return;
MCommentListT& lst = ctx.GetCommentList();
wxChar* prevComEnd = 0;
int tmpLnNo;
store_line_no( tmpLnNo );
// attach comments which were found before the given context
for( int i = 0; i != _gCQSize; ++i )
{
spComment* pComment = new spComment();
lst.push_back( pComment );
// find the end of comment
wxChar* start = _gCommentsQueue[i];
pComment->mIsMultiline = ( *(start+1) == _T('*') );
// first comment in the queue and multiline
// comments are always treated as a begining
// of the new paragraph in the comment text
if ( i == 0 )
{
pComment->mStartsPar = true;
}
else if ( pComment->mIsMultiline )
{
pComment->mStartsPar = true;
}
else
{
// find out wheather there is a new-line
// between to adjecent comments
wxChar* prevLine = start;
skip_to_prev_line(prevLine);
if ( prevLine >= prevComEnd )
pComment->mStartsPar = true;
else
pComment->mStartsPar = false;
}
prevComEnd = set_comment_text( pComment->m_Text, start );
}
// attach comments which are at the end of the line
// of the given context (if any)
if ( skip_to_next_comment_in_the_line( cur ) )
{
spComment* pComment = new spComment();
lst.push_back( pComment );
set_comment_text( pComment->m_Text, cur );
pComment->mStartsPar = 1;
pComment->mIsMultiline = ( *(cur+1) == _T('*') );
// mark this comment, so that it would not
// get in the comments list of the next context
_gLastSuppresedComment = cur;
}
restore_line_no( tmpLnNo );
clear_commets_queue();
}
void CJSourceParser::AddMacroNode( wxChar*& cur )
{
wxChar* start = cur;
int lineNo = get_line_no();
skip_preprocessor_dir( cur );
int tmpLnNo;
store_line_no( tmpLnNo );
if ( !mMacrosOn ) return;
spPreprocessorLine* pPL = new spPreprocessorLine();
pPL->mSrcLineNo = lineNo;
AttachComments( *pPL, cur );
get_string_between( start, cur, &pPL->m_Line );
++start; // skip '#'
get_next_token( start );
pPL->mDefType = SP_PREP_DEF_OTHER;
// if we found a definition or redefinition,
// determine the type exactly and assign
// a name to the context
if ( *start == _T('d') )
{
if ( cmp_tokens_fast( start, _T("define"), 6 ) )
{
char* tok = start+6;
get_next_token( tok );
pPL->m_Name = get_token_str( tok );
skip_token( tok );
get_next_token( tok);
if ( tok > cur )
pPL->mDefType = SP_PREP_DEF_DEFINE_SYMBOL;
else
pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
}
}
else if ( *start == _T('i') )
{
if ( cmp_tokens_fast( start, _T("include"), 7 ) )
{
pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
}
else if ( *++start == _T('f') )
{
// either "#if" or "#ifdef"
cur = start;
skip_token( cur );
get_next_token( cur );
wxString condition = get_token_str( cur );
// currently, everything except '0' is true
if ( condition == _T("0") ) {
// skip until the following else or enif
while ( cur < _gSrcEnd ) {
skip_to_eol( cur );
skip_eol( cur );
get_next_token( cur );
if ( *cur++ == _T('#') && *cur == _T('e') )
break;
}
}
// TODO parse the condition...
}
}
else if ( cmp_tokens_fast( start, _T("else"), 4 ) )
{
// skip until "#endif"
while ( cur < _gSrcEnd ) {
skip_to_eol( cur );
skip_eol( cur );
get_next_token( cur );
if ( *cur++ == _T('#') && cmp_tokens_fast( cur, "endif", 5 ) )
break;
}
}
mpCurCtx->AddMember( pPL );
skip_to_eol( cur );
skip_eol( cur );
restore_line_no( tmpLnNo );
clear_commets_queue();
}
void CJSourceParser::ParseKeyword( char*& cur )
{
// analyze token, which identifies the begining of a new context
if ( CheckVisibilty( cur ) )
{
skip_token( cur );
return;
}
if ( is_class_token( cur ) )
{
if ( is_forward_decl( cur ) )
{
// forward declarations are ignored;
skip_token( cur );
return;
}
if ( mNestingLevel == 0 )
{
// change context form global class context
mCurCtxType = SP_CTX_CLASS;
}
++mNestingLevel;
// add information about new class (name, inheritance, etc)
AddClassNode( cur );
// the default visiblity for class members is 'private'
mCurVis = SP_VIS_PRIVATE;
return;
}
size_t len = get_token_len( cur );
if ( cmp_tokens_fast( cur, "typedef", len ) )
{
skip_token(cur);
get_next_token(cur);
if ( cmp_tokens_fast( cur, "struct", len ) ||
cmp_tokens_fast( cur, "union", len ) ||
cmp_tokens_fast( cur, "class", len )
)
{
if ( mNestingLevel == 0 )
{
// change context form global class context
mCurCtxType = SP_CTX_CLASS;
}
++mNestingLevel;
// add information about new class (name, inheritance, etc)
AddClassNode( cur );
// the default visiblity for class members is 'private'
mCurVis = SP_VIS_PRIVATE;
return;
// FOR NOW:: typedef struct, etc are also ignored
//skip_scope_block( cur );
}
if ( cmp_tokens_fast( cur, "enum", len ) )
{
AddEnumNode( cur );
return;
}
AddTypeDefNode( cur );
return;
}
if ( cmp_tokens_fast( cur, "enum", len ) )
{
AddEnumNode( cur );
return;
}
if ( cmp_tokens_fast( cur, "extern", len ) )
{
// extern's are ignored (both extern "C" and extern vars)
while ( *cur != '{' &&
*cur != ';' )
{
skip_token( cur );
get_next_token( cur );
}
return;
}
if ( cmp_tokens_fast( cur, "enum", len ) )
{
// enumeration blocks are ignored
skip_scope_block( cur );
get_next_token( cur );
skip_token( cur ); // skip ';' token;
return;
}
if ( cmp_tokens_fast( cur, "package", len ) )
{
// packages are ignored
skip_statement( cur );
return;
};
if ( cmp_tokens_fast( cur, "import", len ) )
{
// import statements are ignored
skip_statement( cur );
return;
}
if ( cmp_tokens_fast( cur, "virtual", len ) )
{
// probably the virtual method is in front of us;
mIsVirtual = 1;
skip_token( cur );
return;
}
if ( cmp_tokens_fast( cur, "template", len ) )
{
mIsTemplate = 1;
skip_tempalate_statement( cur );
return;
}
if ( cmp_tokens_fast( cur, "friend", len ) )
{
skip_statement( cur );
return;
}
// ingnore "unsigificant" tokens (i.e. which do not
// affect the current parsing context)
skip_token( cur );
}
bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
{
isAMacro = false;
// FOR NOW:: all functions in the global
// scope are ignored
int lineNo = get_line_no();
char* start = cur;
bool isVirtual = false;
while( *cur != '(' )
{
if ( get_token_str( cur ) == "virtual" )
isVirtual = true;
skip_token( cur );
if ( !get_next_token( cur ) ) return false;
}
char* bracketPos = cur;
char* savedPos = cur + 1;
int tmpLnNo;
store_line_no( tmpLnNo );
// skip gap between function name and start of paramters list
while ( *(cur-1) == ' ' )
--cur;
// check if it's not a macro, and let plugin handle it, if so
if ( mpPlugin )
{
skip_token_back( cur );
char* tmp = cur;
if ( mpPlugin->CanUnderstandContext( tmp, _gSrcEnd, mpCurCtx ) )
{
cur = tmp;
mpPlugin->ParseContext( _gSrcStart, cur, _gSrcEnd, mpCurCtx );
isAMacro = true;
return false;
}
}
spOperation* pOp = new spOperation();
pOp->mSrcLineNo = lineNo;
pOp->mSrcOffset = int( start - _gSrcStart );
pOp->mHeaderLength = int( bracketPos - start );
if ( mpCurCtx->GetContextType() == SP_CTX_CLASS )
pOp->mScope = mpCurCtx->m_Name;
mpCurCtx->AddMember( pOp );
pOp->mVisibility = mCurVis;
pOp->mIsVirtual = isVirtual;
// add comments about operation
AttachComments( *pOp, cur );
// go backwards to method name
skip_token_back( cur );
pOp->m_Name = get_token_str( cur );
// checker whether it's not an operator
char chFirst = *pOp->m_Name.c_str();
if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' ) {
// skip 'operator'
skip_next_token_back( cur );
skip_token_back( cur );
wxString lastToken = get_token_str( cur );
if ( lastToken == "operator" ) {
lastToken += pOp->m_Name;
pOp->m_Name = lastToken;
}
else {
// ok, it wasn't an operator after all
skip_token( cur );
}
}
else if ( pOp->m_Name == "operator" ) {
skip_token( cur );
get_next_token( cur );
wxString oper = get_token_str( cur );
pOp->m_Name += oper;
}
// go backwards to method return type
skip_next_token_back( cur );
if ( cur >= start )
{
wxString rettype = wxString( start, size_t( cur-start ) );
// FIXME just for now...
wxString::size_type pos = 0;
wxString toerase("WXDLLEXPORT ");
while((pos = rettype.find(toerase, pos)) != wxString::npos)
rettype.erase(pos, toerase.length());
pOp->m_RetType = rettype;
}
arrange_indirection_tokens_between( pOp->m_RetType, pOp->m_Name );
cur = savedPos;
restore_line_no( tmpLnNo );
// now, enter operation context
mpCurCtx = pOp;
return true;
}
bool CJSourceParser::ParseArguments( char*& cur )
{
// DANGER-MACROS::
// now cursor position is right after the first opening bracket
// of the function declaration
char* blocks [16]; // used exclusivelly for iterative "lean out"
// of macros and misc. not-obviouse grammar
// (dirty,, but we cannot do it very nice,
// we're not preprocessor-free C/C++ code)
int blockSizes[16];
do
{
size_t blocksSkipped = 0;
get_next_token( cur );
bool first_blk = true;
while( *cur != ')' && *cur != ',' )
{
blocks[blocksSkipped] = cur;
if ( first_blk )
{
char* prev = cur;
skip_token( cur );
blockSizes[blocksSkipped] = size_t(cur-prev);
first_blk = 0;
}
else
blockSizes[blocksSkipped] = skip_block( cur );
get_next_token( cur );
++blocksSkipped;
}
if ( blocksSkipped == 1 )
{
// check if the empty arg. list stressed with "void" inside
if ( cmp_tokens_fast( blocks[0] , "void", 4 ) )
{
cur++; // skip ')'
break;
}
// FIXME:: TBD:: K&R-style function declarations!
// if only one block enclosed, than it's probably
// some macro, there should be at least two blocks,
// one for argument type and another for it's identifier
return false;
}
if ( blocksSkipped == 0 )
{
if ( *cur == 10 ) ++_gLineNo;
++cur; // skip ')'
break; // function without paramters
}
// we should be in the operation context now
spOperation* pOp = (spOperation*)mpCurCtx;
spParameter* pPar = new spParameter();
pOp->AddMember( pPar );
// FOR NOW:: line number is not exact if argument list is mutiline
pPar->mSrcLineNo = get_line_no();
size_t nameBlock = blocksSkipped - 1;
size_t typeBlock = nameBlock - 1;
// check if default values present
if ( *blocks[typeBlock] == '=' )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -