1086 lines
27 KiB
C++
1086 lines
27 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 2000.
|
||
|
//
|
||
|
// File: CXX.CXX
|
||
|
//
|
||
|
// Contents: C and C++ Filter
|
||
|
//
|
||
|
// Classes: CxxFilter
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
// 17-Oct-94 BartoszM Rewrote
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::CxxScanner, public
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CxxScanner::CxxScanner ()
|
||
|
: _pStream(0),
|
||
|
_fIgnorePreamble(FALSE),
|
||
|
_fScanningPrepro(FALSE),
|
||
|
_fIdFound(FALSE),
|
||
|
_cLines( 0 )
|
||
|
{
|
||
|
_buf[0] = L'\0';
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::Init, public
|
||
|
//
|
||
|
// Arguments: [pStream] -- stream for text
|
||
|
//
|
||
|
// History: 24-Nov-93 AmyA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CxxScanner::Init ( CFilterTextStream * pStream )
|
||
|
{
|
||
|
_pStream = pStream;
|
||
|
// Position scanner on a token
|
||
|
Accept();
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::NextToken, public
|
||
|
//
|
||
|
// Arguments: [c] -- lookahead character
|
||
|
//
|
||
|
// Returns: Recognized token
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CToken CxxScanner::NextToken( int c )
|
||
|
{
|
||
|
BOOL fFirstTime = TRUE;
|
||
|
|
||
|
// Loop until a token is recognized
|
||
|
for(;;)
|
||
|
{
|
||
|
switch (c)
|
||
|
{
|
||
|
case -1: // UNICODE EOF
|
||
|
_token = tEnd;
|
||
|
return _token;
|
||
|
|
||
|
case L'\n':
|
||
|
_cLines++;
|
||
|
_fScanningPrepro = FALSE;
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
|
||
|
case L'{':
|
||
|
_token = tLBrace;
|
||
|
return _token;
|
||
|
|
||
|
case L'}':
|
||
|
_token = tRBrace;
|
||
|
return _token;
|
||
|
|
||
|
case L';':
|
||
|
_token = tSemi;
|
||
|
return _token;
|
||
|
|
||
|
case L',':
|
||
|
if ( _fIgnorePreamble )
|
||
|
{
|
||
|
// skip comma in the preamble
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
_token = tComma;
|
||
|
return _token;
|
||
|
|
||
|
case L'*':
|
||
|
if ( _fIgnorePreamble )
|
||
|
{
|
||
|
// skip star in the preamble
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
_token = tStar;
|
||
|
return _token;
|
||
|
|
||
|
case L'#': // not a token!
|
||
|
// consume preprocessor command
|
||
|
_fScanningPrepro = TRUE;
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
|
||
|
case L'(':
|
||
|
if ( _fIgnorePreamble )
|
||
|
{
|
||
|
// skip parentheses in the preamble
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
_token = tLParen;
|
||
|
return _token;
|
||
|
|
||
|
case L')':
|
||
|
if ( _fIgnorePreamble )
|
||
|
{
|
||
|
// skip parentheses in the preamble
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
_token = tRParen;
|
||
|
return _token;
|
||
|
|
||
|
case L':':
|
||
|
c = _pStream->GetChar();
|
||
|
// ignore colons in the preamble
|
||
|
if ( !_fIgnorePreamble && c == L':')
|
||
|
{
|
||
|
_token = tDoubleColon;
|
||
|
return _token;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L'/': // not a token!
|
||
|
// consume comment
|
||
|
c = EatComment();
|
||
|
break;
|
||
|
|
||
|
case L'"': // not a token!
|
||
|
// consume string literal
|
||
|
c = EatString();
|
||
|
break;
|
||
|
|
||
|
case L'\'': // not a token!
|
||
|
// consume character literal
|
||
|
c = EatCharLiteral();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
// We don't really care about indentifiers.
|
||
|
// We store them in the buffer so that when
|
||
|
// we recognize a real token like :: or (
|
||
|
// we can retrieve them.
|
||
|
// Look out for 'class' 'struct' and 'union' though.
|
||
|
|
||
|
if ( iswalpha((wint_t)c) || (c == L'_') || (c == L'~') )
|
||
|
{
|
||
|
_fIdFound = TRUE;
|
||
|
|
||
|
// in preamble skip names except for the first
|
||
|
// one, which is the name of the procedure
|
||
|
|
||
|
if ( _fIgnorePreamble && !fFirstTime )
|
||
|
{
|
||
|
c = SkipName(c);
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
c = LoadName (c);
|
||
|
fFirstTime = FALSE;
|
||
|
}
|
||
|
|
||
|
if (!_fIgnorePreamble)
|
||
|
{
|
||
|
// look for class/struct/union keywords
|
||
|
|
||
|
if ( wcscmp(_buf, L"class" ) == 0 )
|
||
|
{
|
||
|
_token = tClass;
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"struct") == 0 )
|
||
|
{
|
||
|
_token = tStruct;
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"union" ) == 0 )
|
||
|
{
|
||
|
_token = tUnion;
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"interface" ) == 0 )
|
||
|
{
|
||
|
_token = tInterface;
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"typedef" ) == 0 )
|
||
|
{
|
||
|
_token = tTypedef;
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"enum" ) == 0 )
|
||
|
{
|
||
|
_token = tEnum;
|
||
|
return _token;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( _fScanningPrepro )
|
||
|
{
|
||
|
if ( wcscmp(_buf, L"define" ) == 0 )
|
||
|
{
|
||
|
_token = tDefine;
|
||
|
c = LoadName(c);
|
||
|
return _token;
|
||
|
}
|
||
|
else if ( wcscmp(_buf, L"include" ) == 0 )
|
||
|
{
|
||
|
_token = tInclude;
|
||
|
c = LoadIncludeFileName(c);
|
||
|
return _token;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
c = EatPrepro();
|
||
|
_fScanningPrepro = FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else // not recognized, continue scanning
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
}
|
||
|
break;
|
||
|
} // end of switch
|
||
|
} // end of infinite loop
|
||
|
|
||
|
return _token;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::SkipName, public
|
||
|
//
|
||
|
// Returns: Next character after identifier
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::SkipName(int c)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
i++;
|
||
|
}
|
||
|
while ( (iswalnum((wint_t)c) || (c == L'_')) && (i < MAXIDENTIFIER) );
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::LoadName, public
|
||
|
//
|
||
|
// Synopsis: Scans and copies identifier into scanner's buffer
|
||
|
//
|
||
|
// Arguments: [c] -- GetChar character
|
||
|
//
|
||
|
// Returns: Next character after identifier
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::LoadName(int c)
|
||
|
{
|
||
|
WCHAR * pCur = _buf;
|
||
|
_pStream->GetRegion ( _region, -1, 0 );
|
||
|
int i = 0;
|
||
|
do
|
||
|
{
|
||
|
_buf[i++] = (WCHAR)c;
|
||
|
c = _pStream->GetChar();
|
||
|
}
|
||
|
while ( (iswalnum((wint_t)c) || (c == L'_')) && (i < MAXIDENTIFIER));
|
||
|
|
||
|
_region.cwcExtent = i;
|
||
|
// c is not a symbol character
|
||
|
|
||
|
_buf[i] = L'\0';
|
||
|
|
||
|
//DbgPrint("LoadName: =================> %ws\n", _buf);
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::LoadIncludeFileName, public
|
||
|
//
|
||
|
// Synopsis: Scans and copies a file name following a
|
||
|
// #include statement to internal buffer
|
||
|
// If a path exists, it is ignored.
|
||
|
// A '.' is converted to '_' because searching an id
|
||
|
// with a '.' does not seem to work with ci.
|
||
|
// For example,
|
||
|
// #include <\foo\bar\fname.h> --> fname_h
|
||
|
//
|
||
|
// Arguments: [c] -- GetChar character
|
||
|
//
|
||
|
// Returns: Next character after the #include stmt
|
||
|
//
|
||
|
// History: 10-June-2000 kumarp Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::LoadIncludeFileName(int c)
|
||
|
{
|
||
|
WCHAR * pCur = _buf;
|
||
|
int i = 0;
|
||
|
|
||
|
// skip chars preceeding the file name
|
||
|
do
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
}
|
||
|
while ((c == L'\t') || (c == L' ') || (c == L'"') || (c == L'<'));
|
||
|
|
||
|
_pStream->GetRegion ( _region, -1, 0 );
|
||
|
|
||
|
do
|
||
|
{
|
||
|
_buf[i++] = (WCHAR)c;
|
||
|
if ((c == L'\\') || (c == L'/'))
|
||
|
{
|
||
|
// ignore path
|
||
|
i = 0;
|
||
|
_pStream->GetRegion ( _region, 0, 0 );
|
||
|
}
|
||
|
|
||
|
c = _pStream->GetChar();
|
||
|
// if (c == L'.')
|
||
|
// {
|
||
|
// c = L'_';
|
||
|
// }
|
||
|
}
|
||
|
while ((iswalnum((wint_t)c) || ( c == L'.' ) ||
|
||
|
(c == L'_') || (c == L'\\') || (c == L'/')) &&
|
||
|
(i < MAXIDENTIFIER));
|
||
|
|
||
|
_region.cwcExtent = i;
|
||
|
_buf[i] = L'\0';
|
||
|
|
||
|
c = EatPrepro();
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::EatComment, public
|
||
|
//
|
||
|
// Synopsis: Eats comments
|
||
|
//
|
||
|
// Returns: First non-comment character
|
||
|
//
|
||
|
// Requires: Leading '/' found and scanned
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::EatComment()
|
||
|
{
|
||
|
int c = _pStream->GetChar();
|
||
|
|
||
|
if ( c == L'*')
|
||
|
{
|
||
|
// C style comment
|
||
|
while ((c = _pStream->GetChar()) != EOF )
|
||
|
{
|
||
|
while ( c == L'*' )
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
|
||
|
if ( c == EOF )
|
||
|
return EOF;
|
||
|
|
||
|
if ( c == L'/' )
|
||
|
return _pStream->GetChar();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ( c == L'/' )
|
||
|
{
|
||
|
// C++ style comment
|
||
|
while ((c = _pStream->GetChar()) != EOF )
|
||
|
{
|
||
|
if ( c == L'\n' )
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::EatString, public
|
||
|
//
|
||
|
// Synopsis: Eats string literal
|
||
|
//
|
||
|
// Returns: First non-string character
|
||
|
//
|
||
|
// Requires: Leading '"' found and scanned
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::EatString()
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
while ((c = _pStream->GetChar()) != EOF )
|
||
|
{
|
||
|
if ( c == L'"' )
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// eat backslashes
|
||
|
// skip escaped quotes
|
||
|
|
||
|
if ( c == L'\\' )
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
if ( c == EOF )
|
||
|
return EOF;
|
||
|
}
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::EatCharLiteral, public
|
||
|
//
|
||
|
// Synopsis: Eats character literal
|
||
|
//
|
||
|
// Returns: First non-char-literal character
|
||
|
//
|
||
|
// Requires: Leading apostrophe ' found and scanned
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::EatCharLiteral()
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
while ((c = _pStream->GetChar()) != EOF )
|
||
|
{
|
||
|
if ( c == L'\'' )
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// eat backslashes
|
||
|
// skip escaped quotes
|
||
|
|
||
|
if ( c == L'\\' )
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
if ( c == EOF )
|
||
|
return EOF;
|
||
|
}
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxScanner::EatPrepro, public
|
||
|
//
|
||
|
// Synopsis: Eats preprocessor commands. Possibly multi-line.
|
||
|
//
|
||
|
// Returns: First non-preprocessor character
|
||
|
//
|
||
|
// Requires: Leading # found and scanned
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int CxxScanner::EatPrepro()
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
_fScanningPrepro = FALSE;
|
||
|
|
||
|
while ((c = _pStream->GetChar()) != EOF && (c != L'\n'))
|
||
|
{
|
||
|
if ( c == L'\\' ) // skip whatever follows backslash
|
||
|
{
|
||
|
c = _pStream->GetChar();
|
||
|
if (c == L'\r')
|
||
|
c = _pStream->GetChar();
|
||
|
if ( c == EOF )
|
||
|
return EOF;
|
||
|
}
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxParser::CxxParser, public
|
||
|
//
|
||
|
// Synopsis: Initialize parser
|
||
|
//
|
||
|
// Arguments: [pStm] -- stream
|
||
|
// [drep] -- data repository
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CxxParser::CxxParser ()
|
||
|
: _scope(0),
|
||
|
_inClass(0),
|
||
|
_fParsingTypedef(FALSE),
|
||
|
_fParsingFnPtrTypedef(FALSE),
|
||
|
_iVal(0)
|
||
|
{
|
||
|
_strClass[0] = L'\0';
|
||
|
_strName[0] = L'\0';
|
||
|
_attribute.ulKind = PRSPEC_LPWSTR;
|
||
|
_attribute.lpwstr = PROP_CLASS;
|
||
|
|
||
|
_psVal[Function].ulKind = PRSPEC_LPWSTR;
|
||
|
_psVal[Function].lpwstr = PROP_FUNC;
|
||
|
|
||
|
_psVal[Class].ulKind = PRSPEC_LPWSTR;
|
||
|
_psVal[Class].lpwstr = PROP_CLASS;
|
||
|
|
||
|
_psVal[Lines].ulKind = PRSPEC_LPWSTR;
|
||
|
_psVal[Lines].lpwstr = PROP_LINES;
|
||
|
|
||
|
_aVal[Function] = 0;
|
||
|
_aVal[Class] = 0;
|
||
|
_aVal[Lines] = 0;
|
||
|
}
|
||
|
|
||
|
CxxParser::~CxxParser()
|
||
|
{
|
||
|
delete _aVal[Function];
|
||
|
delete _aVal[Class];
|
||
|
delete _aVal[Lines];
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxParser::Init, public
|
||
|
//
|
||
|
// Synopsis: Initialize parser
|
||
|
//
|
||
|
// Arguments: [pStream] -- stream
|
||
|
//
|
||
|
// History: 24-Nov-93 AmyA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CxxParser::Init ( CFilterTextStream * pStream )
|
||
|
{
|
||
|
_scan.Init(pStream);
|
||
|
_token = _scan.Token();
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CxxParser::Parse, public
|
||
|
//
|
||
|
// Synopsis: Parse the file
|
||
|
//
|
||
|
// History: 26-Jun-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CxxParser::Parse()
|
||
|
{
|
||
|
_cwcCopiedClass = 0;
|
||
|
_cwcCopiedName = 0;
|
||
|
|
||
|
while ( _token != tEnd)
|
||
|
{
|
||
|
switch ( _token )
|
||
|
{
|
||
|
case tTypedef:
|
||
|
if ( !_fParsingTypedef )
|
||
|
{
|
||
|
_fParsingTypedef = TRUE;
|
||
|
_typedefScope = _scope;
|
||
|
}
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tSemi:
|
||
|
if ( _fParsingTypedef && ( _scope == _typedefScope ))
|
||
|
{
|
||
|
ASSERT(_fParsingFnPtrTypedef == FALSE);
|
||
|
SetName();
|
||
|
//DbgPrint("tSemi: name: %ws, scope: %d\n", _strName, _scope);
|
||
|
PutFunction();
|
||
|
_fParsingTypedef = FALSE;
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tComma:
|
||
|
if ( _fParsingTypedef && ( _scope == _typedefScope ))
|
||
|
{
|
||
|
ASSERT(_fParsingFnPtrTypedef == FALSE);
|
||
|
SetName();
|
||
|
//DbgPrint("tComma: name: %ws, scope: %d\n", _strName, _scope);
|
||
|
PutFunction();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tEnum:
|
||
|
//DbgPrint("tEnum\n");
|
||
|
//_scan.IgnorePreamble(TRUE);
|
||
|
_token = _scan.Accept();
|
||
|
//_scan.IgnorePreamble(FALSE);
|
||
|
|
||
|
if ( _token == tLBrace )
|
||
|
{
|
||
|
// Good, we're inside a enum definition
|
||
|
|
||
|
_scope++;
|
||
|
SetName();
|
||
|
//DbgPrint("tEnum: %ws\n", _strName);
|
||
|
PutFunction();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
// otherwise it was a false alarm
|
||
|
break;
|
||
|
|
||
|
case tClass:
|
||
|
case tStruct:
|
||
|
case tUnion:
|
||
|
case tInterface:
|
||
|
|
||
|
// We have to recognize stuff like this:
|
||
|
// class FOO : public bar:a, private b {
|
||
|
// ----- --
|
||
|
// text between 'class' and left brace is
|
||
|
// a preamble that the scanner will skip
|
||
|
// If it's only a forward declaration, we
|
||
|
// will stop at a semicolon and ignore the
|
||
|
// whole business.
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
_classToken = _token;
|
||
|
#endif // CIDBG == 1
|
||
|
|
||
|
// scan through stuff like
|
||
|
// : public foo, private bar
|
||
|
|
||
|
_scan.IgnorePreamble(TRUE);
|
||
|
_token = _scan.Accept();
|
||
|
_scan.IgnorePreamble(FALSE);
|
||
|
|
||
|
// Ignore embedded classes
|
||
|
if ( _inClass == 0 )
|
||
|
SetClass(); // record class name for later
|
||
|
|
||
|
if ( _token == tLBrace )
|
||
|
{
|
||
|
// Good, we're inside a class definition
|
||
|
|
||
|
_inClass++;
|
||
|
_scope++;
|
||
|
PutClass ();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
// otherwise it was a false alarm
|
||
|
|
||
|
break;
|
||
|
|
||
|
case tDoubleColon:
|
||
|
|
||
|
// Here we deal with constructs like
|
||
|
// FOO::FOO ( int x ) : bar(state::ok), (true) {
|
||
|
// -- - --
|
||
|
// Text between left paren and left brace is preamble
|
||
|
// and the scanner skips it. If we hit a semicolon
|
||
|
// rather than left brace, we ignore the whole
|
||
|
// construct (it was an invocation or something)
|
||
|
|
||
|
SetClass(); // record class name just in case
|
||
|
_token = _scan.Accept();
|
||
|
if ( _token == tLParen )
|
||
|
{
|
||
|
SetName(); // record method name just in case
|
||
|
|
||
|
_scan.IgnorePreamble(TRUE);
|
||
|
_token = _scan.Accept();
|
||
|
_scan.IgnorePreamble(FALSE);
|
||
|
|
||
|
if ( _token == tLBrace )
|
||
|
{
|
||
|
// Yes, we have method definition
|
||
|
_scope++;
|
||
|
_token = _scan.Accept();
|
||
|
PutMethod();
|
||
|
return TRUE;
|
||
|
}
|
||
|
// otherwise it was a false alarm
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case tLParen:
|
||
|
if ( _fParsingTypedef && ( _scope == _typedefScope ))
|
||
|
{
|
||
|
//
|
||
|
// at present we only support fn-ptr typedefs
|
||
|
// of the following type:
|
||
|
//
|
||
|
// typedef void (*FnPtr1) ( int i, float f );
|
||
|
//
|
||
|
|
||
|
//SetName();
|
||
|
//DbgPrint("tLParen: name: %ws, scope: %d\n", _strName, _scope);
|
||
|
_scan.SetIdFound(FALSE);
|
||
|
_token = _scan.Accept();
|
||
|
if ( ( _token == tStar ) && !_scan.IdFound() )
|
||
|
{
|
||
|
_fParsingFnPtrTypedef = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//PutFunction();
|
||
|
_fParsingTypedef = FALSE;
|
||
|
_fParsingFnPtrTypedef = FALSE;
|
||
|
}
|
||
|
|
||
|
_token = _scan.Accept();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetName(); // record procedure name just in case
|
||
|
|
||
|
// It may be an inline constructor
|
||
|
// skip argument list and constructor stuff like
|
||
|
// : Parent(blah), member(blah)
|
||
|
|
||
|
_scan.IgnorePreamble(TRUE);
|
||
|
_token = _scan.Accept();
|
||
|
_scan.IgnorePreamble(FALSE);
|
||
|
|
||
|
if ( _token == tLBrace )
|
||
|
{
|
||
|
// Yes, it's a definition
|
||
|
|
||
|
if ( _inClass )
|
||
|
{
|
||
|
// inline method definition inside class definition
|
||
|
_scope++;
|
||
|
_token = _scan.Accept();
|
||
|
PutInlineMethod();
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if ( _scope == 0 )
|
||
|
{
|
||
|
// function definitions
|
||
|
// in outer scope
|
||
|
|
||
|
_scope++;
|
||
|
PutFunction();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
// else continue--false alarm
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case tRParen:
|
||
|
if ( _fParsingFnPtrTypedef && ( _scope == _typedefScope ))
|
||
|
{
|
||
|
SetName();
|
||
|
//DbgPrint("tRParen: name: %ws, scope: %d\n", _strName, _scope);
|
||
|
PutFunction();
|
||
|
_fParsingTypedef = FALSE;
|
||
|
_fParsingFnPtrTypedef = FALSE;
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
}
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tEnd:
|
||
|
return FALSE;
|
||
|
|
||
|
case tLBrace:
|
||
|
// keep track of scope
|
||
|
_scope++;
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tRBrace:
|
||
|
// keep track of scope and (nested) class scope
|
||
|
_scope--;
|
||
|
if ( _inClass > _scope )
|
||
|
{
|
||
|
_inClass--;
|
||
|
}
|
||
|
_token = _scan.Accept();
|
||
|
break;
|
||
|
|
||
|
case tDefine:
|
||
|
SetName();
|
||
|
PutFunction();
|
||
|
_scan.EatPrepro();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
|
||
|
case tInclude:
|
||
|
SetName();
|
||
|
PutFunction();
|
||
|
_token = _scan.Accept();
|
||
|
return TRUE;
|
||
|
|
||
|
default:
|
||
|
_token = _scan.Accept();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( _aVal[Lines] == 0 )
|
||
|
{
|
||
|
_aVal[Lines] = new CPropVar;
|
||
|
if ( 0 == _aVal[Lines] )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
_aVal[Lines]->SetUI4( _scan.Lines() );
|
||
|
|
||
|
return FALSE; // we only end up here if _token == tEnd
|
||
|
}
|
||
|
|
||
|
void CxxParser::PutClass ()
|
||
|
{
|
||
|
_tokenType = ttClass;
|
||
|
_attribute.lpwstr = PROP_CLASS;
|
||
|
_strName[0] = L'\0';
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
if ( _aVal[Class] == 0 )
|
||
|
{
|
||
|
_aVal[Class] = new CPropVar;
|
||
|
if ( 0 == _aVal[Class] )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
_aVal[Class]->SetLPWSTR( _strClass, _aVal[Class]->Count() );
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// PROP_CLASS, _strClass
|
||
|
|
||
|
//DbgPrint("PutClass: class: %ws\n", _strClass);
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
if ( _classToken == tClass )
|
||
|
{
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE,"class %ws\n", _strClass ));
|
||
|
}
|
||
|
else if ( _classToken == tStruct )
|
||
|
{
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE, "struct %ws\n", _strClass ));
|
||
|
}
|
||
|
else if ( _classToken == tUnion )
|
||
|
{
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE, "union %ws\n", _strClass ));
|
||
|
}
|
||
|
else if ( _classToken == tInterface )
|
||
|
{
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE, "interface %ws\n", _strClass ));
|
||
|
}
|
||
|
#endif // CIDBG == 1
|
||
|
}
|
||
|
|
||
|
void CxxParser::PutMethod ()
|
||
|
{
|
||
|
_tokenType = ttMethod;
|
||
|
_attribute.lpwstr = PROP_FUNC;
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
if ( _aVal[Function] == 0 )
|
||
|
{
|
||
|
_aVal[Function] = new CPropVar;
|
||
|
if ( 0 == _aVal[Function] )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
_aVal[Function]->SetLPWSTR( _strName, _aVal[Function]->Count() );
|
||
|
|
||
|
#endif
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE, "%ws::%ws\n", _strClass, _strName ));
|
||
|
}
|
||
|
|
||
|
void CxxParser::PutInlineMethod ()
|
||
|
{
|
||
|
_tokenType = ttInlineMethod;
|
||
|
_attribute.lpwstr = PROP_FUNC;
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
if ( _aVal[Function] == 0 )
|
||
|
{
|
||
|
_aVal[Function] = new CPropVar;
|
||
|
if ( 0 == _aVal[Function] )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
_aVal[Function]->SetLPWSTR( _strName, _aVal[Function]->Count() );
|
||
|
|
||
|
#endif
|
||
|
|
||
|
cxxDebugOut((DEB_ITRACE, "%ws::%ws\n", _strClass, _strName ));
|
||
|
}
|
||
|
|
||
|
void CxxParser::PutFunction ()
|
||
|
{
|
||
|
_tokenType = ttFunction;
|
||
|
_attribute.lpwstr = PROP_FUNC;
|
||
|
_strClass[0] = L'\0';
|
||
|
|
||
|
#if 0
|
||
|
if ( _aVal[Function] == 0 )
|
||
|
{
|
||
|
_aVal[Function] = new CPropVar;
|
||
|
if ( 0 == _aVal[Function] )
|
||
|
THROW( CException( E_OUTOFMEMORY ) );
|
||
|
}
|
||
|
|
||
|
_aVal[Function]->SetLPWSTR( _strName, _aVal[Function]->Count() );
|
||
|
#endif
|
||
|
|
||
|
//DbgPrint("PutFunction: func: %ws\n", _strName);
|
||
|
cxxDebugOut((DEB_ITRACE, "function %ws\n", _strName ));
|
||
|
}
|
||
|
|
||
|
void CxxParser::GetRegion ( FILTERREGION& region )
|
||
|
{
|
||
|
switch (_tokenType)
|
||
|
{
|
||
|
case ttClass:
|
||
|
region = _regionClass;
|
||
|
break;
|
||
|
case ttFunction:
|
||
|
case ttInlineMethod:
|
||
|
case ttMethod:
|
||
|
region = _regionName;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL CxxParser::GetTokens ( ULONG * pcwcBuffer, WCHAR * awcBuffer )
|
||
|
{
|
||
|
ULONG cwc = *pcwcBuffer;
|
||
|
*pcwcBuffer = 0;
|
||
|
|
||
|
if (_strClass[0] != L'\0')
|
||
|
{
|
||
|
// We have a class name
|
||
|
|
||
|
WCHAR * strClass = _strClass + _cwcCopiedClass;
|
||
|
|
||
|
ULONG cwcClass = wcslen( strClass );
|
||
|
if ( cwcClass > cwc )
|
||
|
{
|
||
|
wcsncpy( awcBuffer, strClass, cwc );
|
||
|
_cwcCopiedClass += cwc;
|
||
|
return FALSE;
|
||
|
}
|
||
|
wcscpy( awcBuffer, strClass );
|
||
|
*pcwcBuffer = cwcClass;
|
||
|
_cwcCopiedClass += cwcClass;
|
||
|
awcBuffer[(*pcwcBuffer)++] = L' ';
|
||
|
}
|
||
|
|
||
|
if (_strName[0] == L'\0')
|
||
|
{
|
||
|
// it was only a class name
|
||
|
awcBuffer[*pcwcBuffer] = L'\0';
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
cwc -= *pcwcBuffer;
|
||
|
WCHAR * awc = awcBuffer + *pcwcBuffer;
|
||
|
WCHAR * strName = _strName + _cwcCopiedName;
|
||
|
ULONG cwcName = wcslen( strName );
|
||
|
|
||
|
if ( cwcName > cwc )
|
||
|
{
|
||
|
wcsncpy( awc, strName, cwc );
|
||
|
_cwcCopiedName += cwc;
|
||
|
return FALSE;
|
||
|
}
|
||
|
wcscpy( awc, strName );
|
||
|
*pcwcBuffer += cwcName;
|
||
|
_cwcCopiedName += cwcName;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL CxxParser::GetValueAttribute( PROPSPEC & ps )
|
||
|
{
|
||
|
for ( ; _iVal <= Lines && 0 == _aVal[_iVal]; _iVal++ )
|
||
|
continue;
|
||
|
|
||
|
if ( _iVal > Lines )
|
||
|
return FALSE;
|
||
|
else
|
||
|
{
|
||
|
ps = _psVal[_iVal];
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PROPVARIANT * CxxParser::GetValue()
|
||
|
{
|
||
|
if ( _iVal > Lines )
|
||
|
return 0;
|
||
|
|
||
|
CPropVar * pTemp = _aVal[_iVal];
|
||
|
_aVal[_iVal] = 0;
|
||
|
_iVal++;
|
||
|
|
||
|
return (PROPVARIANT *)(void *)pTemp;
|
||
|
}
|