Index: src/CodeBlocks.cbp =================================================================== --- src/CodeBlocks.cbp (revision 6203) +++ src/CodeBlocks.cbp (working copy) @@ -1154,6 +1154,12 @@ + + + + Index: src/plugins/codecompletion/Makefile.am =================================================================== --- src/plugins/codecompletion/Makefile.am (revision 6203) +++ src/plugins/codecompletion/Makefile.am (working copy) @@ -25,7 +25,8 @@ parser/parserthread.cpp \ parser/token.cpp \ parser/tokenizer.cpp \ - parser/searchtree.cpp + parser/searchtree.cpp \ + parser/expression noinst_HEADERS = ccdebuginfo.h \ ccoptionsdlg.h \ @@ -40,4 +41,5 @@ parser/parserthread.h \ parser/token.h \ parser/tokenizer.h \ - parser/searchtree.h + parser/searchtree.h \ + parser/expression.h Index: src/plugins/codecompletion/parser/expression.cpp =================================================================== --- src/plugins/codecompletion/parser/expression.cpp (revision 0) +++ src/plugins/codecompletion/parser/expression.cpp (revision 0) @@ -0,0 +1,447 @@ +/* + * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3 + * http://www.gnu.org/licenses/gpl-3.0.html + * Designed by Loaden (loaden@gmail.com) + */ + +#include +#include "expression.h" +#include "logmanager.h" + +#include + +#define PARSERTHREAD_DEBUG_OUTPUT 0 + +#ifdef PARSER_TEST + extern void ParserTrace(const wxChar* format, ...); + #define TRACE(format, args...)\ + ParserTrace(format , ## args) +#else +#if PARSERTHREAD_DEBUG_OUTPUT + #define TRACE(format, args...)\ + Manager::Get()->GetLogManager()->DebugLog(F( format , ## args)) +#else + #define TRACE(format, args...) +#endif +#endif + +namespace ExpressionConsts +{ + const wxString Plus (_T("+")); + const wxString Subtract (_T("-")); + const wxString MultiPly (_T("*")); + const wxString Divide (_T("/")); + const wxString LParentheses (_T("(")); + const wxString RParentheses (_T(")")); + const wxString Mod (_T("%")); + const wxString Power (_T("^")); + const wxString BitwiseAnd (_T("&")); + const wxString BitwiseOr (_T("|")); + const wxString And (_T("&&")); + const wxString Or (_T("||")); + const wxString Not (_T("!")); + const wxString Equal (_T("==")); + const wxString Unequal (_T("!=")); + const wxString GT (_T(">")); + const wxString LT (_T("<")); + const wxString GTOrEqual (_T(">=")); + const wxString LTOrEqual (_T("<=")); + const wxString LShift (_T("<<")); + const wxString RShift (_T(">>")); +} + +ExpressionNode::ExpressionNode() +{ + Initialize(wxEmptyString); +} + +void ExpressionNode::Initialize(wxString token) +{ + m_Unitary = false; + m_Token = token; + m_Type = ParseNodeType(m_Token); + m_Priority = GetNodeTypePriority(m_Type); +} + +ExpressionNode::ExpressionNodeType ExpressionNode::ParseNodeType(wxString token) +{ + if (token.IsEmpty() || token.IsNull()) return ExpressionNode::Unknown; + else if (token == ExpressionConsts::Plus) return ExpressionNode::Plus; + else if (token == ExpressionConsts::Subtract) return ExpressionNode::Subtract; + else if (token == ExpressionConsts::MultiPly) return ExpressionNode::MultiPly; + else if (token == ExpressionConsts::Divide) return ExpressionNode::Divide; + else if (token == ExpressionConsts::Mod) return ExpressionNode::Mod; + else if (token == ExpressionConsts::Power) return ExpressionNode::Power; + else if (token == ExpressionConsts::LParentheses) return ExpressionNode::LParentheses; + else if (token == ExpressionConsts::RParentheses) return ExpressionNode::RParentheses; + else if (token == ExpressionConsts::BitwiseAnd) return ExpressionNode::BitwiseAnd; + else if (token == ExpressionConsts::BitwiseOr) return ExpressionNode::BitwiseOr; + else if (token == ExpressionConsts::And) return ExpressionNode::And; + else if (token == ExpressionConsts::Or) return ExpressionNode::Or; + else if (token == ExpressionConsts::Not) return ExpressionNode::Not; + else if (token == ExpressionConsts::Equal) return ExpressionNode::Equal; + else if (token == ExpressionConsts::Unequal) return ExpressionNode::Unequal; + else if (token == ExpressionConsts::GT) return ExpressionNode::GT; + else if (token == ExpressionConsts::LT) return ExpressionNode::LT; + else if (token == ExpressionConsts::GTOrEqual) return ExpressionNode::GTOrEqual; + else if (token == ExpressionConsts::LTOrEqual) return ExpressionNode::LTOrEqual; + else if (token == ExpressionConsts::LShift) return ExpressionNode::LShift; + else if (token == ExpressionConsts::RShift) return ExpressionNode::RShift; + else if (token == ExpressionConsts::Plus) return ExpressionNode::Plus; + else + { + if (token.IsNumber()) return ExpressionNode::Numeric; + else return ExpressionNode::Unknown; + } +} + +long ExpressionNode::GetNodeTypePriority(ExpressionNodeType type) +{ + switch (type) + { + case LParentheses: + case RParentheses: + return 9; + case Not: + return 8; + case Mod: + return 7; + case MultiPly: + case Divide: + case Power: + return 6; + case Plus: + case Subtract: + return 5; + case LShift: + case RShift: + return 4; + case BitwiseAnd: + case BitwiseOr: + return 3; + case Equal: + case Unequal: + case GT: + case LT: + case GTOrEqual: + case LTOrEqual: + return 2; + case And: + case Or: + return 1; + default: + return 0; + } +} + +bool ExpressionNode::IsUnitaryNode(ExpressionNodeType type) +{ + switch (type) + { + case ExpressionNode::Plus: + case ExpressionNode::Subtract: + case ExpressionNode::Not: + return true; + default: + return false; + } +} + + +bool ExpressionNode::IsDoubleOperator(wxString first, wxString second) +{ + switch (first.GetChar(0)) + { + case _T('&'): + case _T('|'): + case _T('='): + case _T('!'): + case _T('>'): + case _T('<'): + { + wxString newOperator(first + second); + if (newOperator == ExpressionConsts::And || + newOperator == ExpressionConsts::Or || + newOperator == ExpressionConsts::Equal || + newOperator == ExpressionConsts::Unequal || + newOperator == ExpressionConsts::GTOrEqual || + newOperator == ExpressionConsts::LTOrEqual || + newOperator == ExpressionConsts::LShift || + newOperator == ExpressionConsts::RShift) + return true; + else + return false; + } + default: + return false; + } +} + +void Expression::Clear() +{ + m_InfixExpression.clear(); + m_PostfixExpression.clear(); +} + +void Expression::AddToInfixExpression(wxString token) +{ + if (!m_InfixExpression.empty()) + { + wxString& lastToken = m_InfixExpression[m_InfixExpression.size() - 1]; + if (ExpressionNode::IsDoubleOperator(lastToken, token)) + { + lastToken += token; + return; + } + } + m_InfixExpression.push_back(token); +} + +void Expression::ConvertInfixToPostfix() +{ + if (!m_PostfixExpression.empty() || m_InfixExpression.empty()) + return; + + m_Result = true; + m_Status = true; + + std::stack stackOperator; + ExpressionNode::ExpressionNodeType lastType = ExpressionNode::Unknown; + for (PostfixVector::size_type i = 0; i < m_InfixExpression.size(); ++i) + { + ExpressionNode expNode; + expNode.Initialize(m_InfixExpression[i]); + const ExpressionNode::ExpressionNodeType type = expNode.GetType(); + if (type == ExpressionNode::Numeric) + { + // Operand, add to postfix expression + m_PostfixExpression.push_back(expNode); + while (!stackOperator.empty() && stackOperator.top().IsUnitary()) + { + m_PostfixExpression.push_back(stackOperator.top()); + stackOperator.pop(); + } + } + else if (type == ExpressionNode::LParentheses) + { + // Left Parentheses, add to stack + stackOperator.push(expNode); + } + else if (type == ExpressionNode::RParentheses) + { + // Right Parentheses, reverse search the Left Parentheses, add all operator of the middle + ExpressionNode node; + while (!stackOperator.empty()) + { + node = stackOperator.top(); + stackOperator.pop(); + if (node.GetType() == ExpressionNode::LParentheses) + { + while (!stackOperator.empty() && stackOperator.top().IsUnitary()) + { + m_PostfixExpression.push_back(stackOperator.top()); + stackOperator.pop(); + } + break; + } + else + m_PostfixExpression.push_back(node); + } + // The lastest node must be Left Parentheses + if (node.GetType() != ExpressionNode::LParentheses) + { + m_Status = false; + } + } + else + { + if (ExpressionNode::IsUnitaryNode(type) && (m_PostfixExpression.empty() || + (lastType != ExpressionNode::Unknown && + lastType != ExpressionNode::RParentheses && + lastType != ExpressionNode::Numeric))) + { + expNode.SetUnitary(); + stackOperator.push(expNode); + } + else if (stackOperator.empty()) + { + stackOperator.push(expNode); + } + else + { + ExpressionNode beforeExpNode = stackOperator.top(); + if (beforeExpNode.GetType() != ExpressionNode::LParentheses && + beforeExpNode.GetPriority() >= expNode.GetPriority()) + { + m_PostfixExpression.push_back(beforeExpNode); + stackOperator.pop(); + } + + stackOperator.push(expNode); + } + } + + lastType = type; + } + + while (!stackOperator.empty()) + { + ExpressionNode beforeExpNode = stackOperator.top(); + if (beforeExpNode.GetType() == ExpressionNode::LParentheses) + { + m_Status = false; + } + m_PostfixExpression.push_back(beforeExpNode); + stackOperator.pop(); + } + +#ifdef PARSER_TEST + wxString infix, postfix; + for (InfixVector::size_type i = 0; i < m_InfixExpression.size(); ++i) + infix += m_InfixExpression[i] + _T(" "); + for (PostfixVector::size_type i = 0; i < m_PostfixExpression.size(); ++i) + postfix += m_PostfixExpression[i].GetToken() + _T(" "); + TRACE(_T("ConvertInfixToPostfix() : InfixExpression : %s"), infix.wx_str()); + TRACE(_T("ConvertInfixToPostfix() : PostfixExpression : %s"), postfix.wx_str()); +#endif +} + +bool Expression::CalcPostfix() +{ + std::pair pair; + std::stack stack; + int cntNumeric = 0; + + for (PostfixVector::size_type i = 0; i < m_PostfixExpression.size(); ++i) + { + const ExpressionNode& node = m_PostfixExpression[i]; + const ExpressionNode::ExpressionNodeType type = node.GetType(); + if (type == ExpressionNode::Numeric) + { + ++cntNumeric; + if (cntNumeric == 1) + { + pair.first = node.GetTokenValue(); + } + else if (cntNumeric == 2) + { + pair.second = node.GetTokenValue(); + } + else if (cntNumeric == 3) + { + --cntNumeric; + stack.push(pair.first); + TRACE(_T("CalcPostfix() : stack.push(pair.first) : %d"), pair.first); + pair.first = pair.second; + pair.second = node.GetTokenValue(); + } + } + else + { + if (node.IsUnitary()) + { + if (cntNumeric == 1) + { + pair.first = CalculateUnitary(type, pair.first); + } + else if (cntNumeric == 2) + { + pair.second = CalculateUnitary(type, pair.second); + } + } + else + { + if (cntNumeric == 2) + { + --cntNumeric; + pair.first = Calculate(type, pair.first, pair.second); + } + else if (cntNumeric == 1) + { + if (stack.empty()) + { + m_Status = false; + return false; + } + pair.second = pair.first; + pair.first = stack.top(); + TRACE(_T("CalcPostfix() : stack.pop() : %d"), pair.first); + stack.pop(); + pair.first = Calculate(type, pair.first, pair.second); + } + } + } + + TRACE(_T("CalcPostfix() : pair.first : %d, pair.second : %d"), pair.first, pair.second); + + if (!m_Status) + return false; + } + + if (!stack.empty()) + m_Status = false; + if (m_Status) + m_Result = pair.first ? true : false; + + return true; +} + +long Expression::Calculate(ExpressionNode::ExpressionNodeType type, long first, long second) +{ + switch (type) + { + case ExpressionNode::Plus: + return first + second; + case ExpressionNode::Subtract: + return first - second; + case ExpressionNode::MultiPly: + return first * second; + case ExpressionNode::Divide: + if (second == 0) { m_Status = false; return 0; } + else return first / second; + case ExpressionNode::Mod: + if (second == 0) { m_Status = false; return 0; } + else return first / second; + case ExpressionNode::BitwiseAnd: + return first & second; + case ExpressionNode::BitwiseOr: + return first | second; + case ExpressionNode::And: + return first && second; + case ExpressionNode::Or: + return first || second; + case ExpressionNode::Equal: + return first == second; + case ExpressionNode::Unequal: + return first != second; + case ExpressionNode::GT: + return first > second; + case ExpressionNode::LT: + return first < second; + case ExpressionNode::GTOrEqual: + return first >= second; + case ExpressionNode::LTOrEqual: + return first <= second; + case ExpressionNode::LShift: + return first << second; + case ExpressionNode::RShift: + return first >> second; + default: + return 0; + } +} + +long Expression::CalculateUnitary(ExpressionNode::ExpressionNodeType type, long value) +{ + switch (type) + { + case ExpressionNode::Plus: + return value; + case ExpressionNode::Subtract: + return 0 - value; + case ExpressionNode::Not: + return !value; + default: + return 0; + } +} Index: src/plugins/codecompletion/parser/expression.h =================================================================== --- src/plugins/codecompletion/parser/expression.h (revision 0) +++ src/plugins/codecompletion/parser/expression.h (revision 0) @@ -0,0 +1,97 @@ +/* + * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3 + * http://www.gnu.org/licenses/gpl-3.0.html + * Designed by Loaden (loaden@gmail.com) + */ + +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include +#include + +class ExpressionNode +{ +public: + enum ExpressionNodeType + { + Unknown, // Unknown + Plus, // + + Subtract, // - + MultiPly, // * + Divide, // / + LParentheses, // ( + RParentheses, // ) + Mod, // % + Power, // ^ + BitwiseAnd, // & + BitwiseOr, // | + And, // && + Or, // || + Not, // ! + Equal, // == + Unequal, // != + GT, // > + LT, // < + GTOrEqual, // >= + LTOrEqual, // <= + LShift, // << + RShift, // >> + Numeric, // Numeric + }; + + ExpressionNode(); + void Initialize(wxString token); + + ExpressionNodeType GetType() const { return m_Type; } + + bool IsUnitary() const { return m_Unitary; } + void SetUnitary(bool unitary = true) { m_Unitary = unitary; } + + long GetPriority() const { return m_Priority; } + wxString GetToken() const { return m_Token; } + long GetTokenValue() const + { + long r; + m_Token.ToLong(&r); + return r; + } + + static ExpressionNodeType ParseNodeType(wxString token); + static long GetNodeTypePriority(ExpressionNodeType type); + static bool IsUnitaryNode(ExpressionNodeType type); + static bool IsDoubleOperator(wxString first, wxString second); + +private: + wxString m_Token; + ExpressionNodeType m_Type; + bool m_Unitary; + long m_Priority; +}; + +class Expression +{ +public: + void AddToInfixExpression(wxString token); + void ConvertInfixToPostfix(); + bool CalcPostfix(); + bool GetResult() const { return m_Result; } + bool GetStatus() const { return m_Status; } + void Clear(); + +private: + long Calculate(ExpressionNode::ExpressionNodeType type, long first, long second); + long CalculateUnitary(ExpressionNode::ExpressionNodeType type, long value); + +private: + typedef std::vector PostfixVector; + PostfixVector m_PostfixExpression; + + typedef std::vector InfixVector; + InfixVector m_InfixExpression; + + bool m_Result; + bool m_Status; +}; + +#endif // EXPRESSION_H Index: src/plugins/codecompletion/parser/parserthread.cpp =================================================================== --- src/plugins/codecompletion/parser/parserthread.cpp (revision 6203) +++ src/plugins/codecompletion/parser/parserthread.cpp (working copy) @@ -15,18 +15,25 @@ #include #include "logmanager.h" #include +#include "expression.h" #include #include #define PARSERTHREAD_DEBUG_OUTPUT 0 +#ifdef PARSER_TEST + extern void ParserTrace(const wxChar* format, ...); + #define TRACE(format, args...)\ + ParserTrace(format , ## args) +#else #if PARSERTHREAD_DEBUG_OUTPUT #define TRACE(format, args...)\ Manager::Get()->GetLogManager()->DebugLog(F( format , ## args)) #else #define TRACE(format, args...) #endif +#endif int THREAD_START = wxNewId(); int THREAD_END = wxNewId(); @@ -71,6 +78,7 @@ const wxString kw_ifdef (_T("ifdef")); const wxString kw_ifndef (_T("ifndef")); const wxString kw_elif (_T("elif")); + const wxString kw_el (_T("el")); const wxString kw_endif (_T("endif")); const wxString kw_include (_T("include")); const wxString kw_inline (_T("inline")); @@ -117,7 +125,6 @@ m_EncounteredTypeNamespaces(), m_LastUnnamedTokenName(wxEmptyString), m_ParsingTypedef(false), - m_PreprocessorIfCount(0), m_IsBuffer(parserThreadOptions.useBuffer), m_Buffer(bufferOrFilename), m_IsPointer(false), @@ -1162,40 +1169,78 @@ void ParserThread::HandlePreprocessorBlocks(const wxString& preproc) { - if (preproc.StartsWith(ParserConsts::kw_if)) // #if, #ifdef, #ifndef +#ifndef PARSER_TEST + wxString proc = preproc; + wxString peekToken = m_Tokenizer.PeekToken(); +#endif + + // need to force the tokenizer skip raw expression + TokenizerState oldState = m_Tokenizer.GetState(); + m_Tokenizer.SetState(tsReadRawExpression); + + // #if #ifdef #ifndef + if (preproc.StartsWith(ParserConsts::kw_if)) { - wxString token = preproc; - ++m_PreprocessorIfCount; - - token = m_Tokenizer.GetToken(); - if (token.IsSameAs(_T("0"))) + bool state; + if (preproc == ParserConsts::kw_if) { - // TODO: handle special case "#if 0" - TRACE(_T("HandlePreprocessorBlocks() : Special case \"#if 0\" not skipped.")); + state = CalcConditionExpression(); + m_ExpressionState.push(state); } - m_Tokenizer.SkipToEOL(); + else + { + state = (preproc == ParserConsts::kw_ifdef) ? IsMacroDefined() : !IsMacroDefined(); + m_ExpressionState.push(state); + m_Tokenizer.SkipToEOL(); + } + + if (!state) + SkipToNextPreprocessorBlock(); } - else if (preproc==ParserConsts::kw_else || preproc==ParserConsts::kw_elif) // #else, #elif + + // #elif + else if (preproc == ParserConsts::kw_elif) { - TRACE(_T("HandlePreprocessorBlocks() : Saving nesting level: %d"), m_Tokenizer.GetNestingLevel()); - m_Tokenizer.SaveNestingLevel(); - wxString token = preproc; - while (!token.IsEmpty() && token != ParserConsts::kw_endif) - token = m_Tokenizer.GetToken(); - --m_PreprocessorIfCount; -#if PARSERTHREAD_DEBUG_OUTPUT - int l = m_Tokenizer.GetNestingLevel(); -#endif - m_Tokenizer.RestoreNestingLevel(); - TRACE(_T("HandlePreprocessorBlocks() : Restoring nesting level: %d (was %d)"), m_Tokenizer.GetNestingLevel(), l); + if (!m_ExpressionState.empty() && !m_ExpressionState.top() && CalcConditionExpression()) + m_ExpressionState.top() = true; + else + SkipToNextPreprocessorBlock(); + + if (m_ExpressionState.empty()) + TRACE(_T("HandlePreprocessorBlocks() : #kw_elif : %s, %d"), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()); } - else if (preproc==ParserConsts::kw_endif) // #endif - --m_PreprocessorIfCount; + + // #else + else if (preproc==ParserConsts::kw_else) + { + if (!m_ExpressionState.empty() && !m_ExpressionState.top()) + m_Tokenizer.SkipToEOL(); + else + SkipToEndPreprocessorBlock(); + + if (m_ExpressionState.empty()) + TRACE(_T("HandlePreprocessorBlocks() : #endif : %s, %d"), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()); + } + + // #endif + else if (preproc==ParserConsts::kw_endif) + { + m_Tokenizer.SkipToEOL(false, true); + if (!m_ExpressionState.empty()) + m_ExpressionState.pop(); + else + TRACE(_T("HandlePreprocessorBlocks() : #endif : %s, %d"), m_Tokenizer.GetFilename().wx_str(), m_Tokenizer.GetLineNumber()); + } + + // other else { m_Tokenizer.SkipToEOL(); - TRACE( _T("HandlePreprocessorBlocks() : Skip Unrecognized Preprocessor blocks") ); + TRACE(_T("HandlePreprocessorBlocks() : Skip Unrecognized Preprocessor blocks")); } + + // reset tokenizer's functionality + m_Tokenizer.SetState(oldState); } void ParserThread::HandleNamespace() @@ -2182,3 +2227,135 @@ return stripped_args; } + +void ParserThread::GetPreprocessorValue(const wxString& token, bool& found, long& value) +{ + Token* tk = TokenExists(token, 0, tkPreprocessor); + if (tk != NULL) + { + found = true; + if (tk->m_Type.IsEmpty()) + { + return; + } + + if (!tk->m_Type.IsNumber()) + { + GetPreprocessorValue(tk->m_Type, found, value); + } + else + { + found = tk->m_Type.ToLong(&value, tk->m_Type.StartsWith(_T("0x")) ? 16 : 10); + } + } +} + +bool ParserThread::CalcConditionExpression() +{ + wxString buf(m_Tokenizer.ReadToEOL()); + buf += _T("#"); + + Expression exp; + Tokenizer tk; + tk.SetState(tsReadRawExpression); + tk.InitFromBuffer(buf); + while (tk.NotEOF()) + { + wxString token = tk.GetToken(); + if (token == _T("\\") || token == _T("defined") || token == _T("#")) + continue; + + if (token.Length() > 1 && !token.IsNumber() && token[0] != _T('(')) + { + bool found = false; // Must be initialized to false + long value = -1; // Must be initialized to -1 + GetPreprocessorValue(token, found, value); + if (found) + { + if (value == -1) value = 1; + token.Printf(_T("%d"), value); + } + else + { + value = 0; + token.Printf(_T("%d"), value); + } + } + + exp.AddToInfixExpression(token); + } + + exp.ConvertInfixToPostfix(); + if (exp.CalcPostfix()) + { + bool state = exp.GetStatus() && exp.GetResult(); + TRACE(_T("CalcConditionExpression() : exp.GetStatus() : %d, exp.GetResult() : %d"), exp.GetStatus(), exp.GetResult()); + return state; + } + return true; +} + +void ParserThread::SkipToNextPreprocessorBlock() +{ + wxString token(_T("#")); + wxString prevToken; + do + { + prevToken = token; + token = m_Tokenizer.PeekToken(); + + if (prevToken == _T("#")) + { + if (token.StartsWith(ParserConsts::kw_if)) + { + m_Tokenizer.GetToken(); + SkipToEndPreprocessorBlock(false); + token = m_Tokenizer.PeekToken(); + } + + if (token.StartsWith(ParserConsts::kw_el) || (token == ParserConsts::kw_endif)) + break; + } + } + while (!m_Tokenizer.GetToken().IsEmpty()); + m_Tokenizer.UngetToken(); +} + +void ParserThread::SkipToEndPreprocessorBlock(bool ungetToken) +{ + wxString token(_T("#")); + wxString prevToken; + do + { + prevToken = token; + token = m_Tokenizer.PeekToken(); + + if (prevToken == _T("#")) + { + if (token.StartsWith(ParserConsts::kw_if)) + { + m_Tokenizer.GetToken(); + SkipToEndPreprocessorBlock(false); + token = m_Tokenizer.PeekToken(); + } + + if (token == ParserConsts::kw_endif) + break; + } + } + while (!m_Tokenizer.GetToken().IsEmpty()); + + if (ungetToken) + m_Tokenizer.UngetToken(); + else + m_Tokenizer.GetToken(); +} + +bool ParserThread::IsMacroDefined() +{ + wxString token = m_Tokenizer.GetToken(); + bool found = false; // Must be initialized to false + long value = -1; // Must be initialized to -1 + GetPreprocessorValue(token, found, value); + return found; +} Index: src/plugins/codecompletion/parser/parserthread.h =================================================================== --- src/plugins/codecompletion/parser/parserthread.h (revision 6203) +++ src/plugins/codecompletion/parser/parserthread.h (working copy) @@ -16,6 +16,7 @@ #include #include +#include //extern int THREAD_START; //extern int THREAD_END; @@ -239,6 +240,28 @@ */ wxString GetStrippedArgs(const wxString & args); + /** Get the value of pre-processor + * @param 'found' MUST BE Initialized to false, 'value' MUST BE Initialized to -1 + * @return finded or not) + */ + void GetPreprocessorValue(const wxString& token, bool& found, long& value); + + /** Judge what is the first block + */ + bool CalcConditionExpression(); + + /** Skip to next blocks, To mark #else #elif #endif as the end + */ + void SkipToNextPreprocessorBlock(); + + /** Skip to end blocks, To mark #endif as the end + */ + void SkipToEndPreprocessorBlock(bool ungetToken = true); + + /** If the macro defined, return true + */ + bool IsMacroDefined(); + /** if we regard the parserThread class as a syntax anilyzer, then the Tokenizer class is * regard as the lexer, which always feeds a wxString by calling m_Tokenizer.GetToken() */ @@ -319,6 +342,9 @@ /** holds current template agrument(s) when a template occurs */ wxString m_TemplateArgument; + + /** Expression value */ + std::stack m_ExpressionState; }; #endif // PARSERTHREAD_H Index: src/plugins/codecompletion/parser/tokenizer.cpp =================================================================== --- src/plugins/codecompletion/parser/tokenizer.cpp (revision 6203) +++ src/plugins/codecompletion/parser/tokenizer.cpp (working copy) @@ -15,15 +15,22 @@ #include "manager.h" #include #include +#include "logmanager.h" #define TOKENIZER_DEBUG_OUTPUT 0 +#ifdef PARSER_TEST + extern void ParserTrace(const wxChar* format, ...); + #define TRACE(format, args...)\ + ParserTrace(format , ## args) +#else #if TOKENIZER_DEBUG_OUTPUT #define TRACE(format, args...)\ Manager::Get()->GetLogManager()->DebugLog(F( format , ## args)) #else #define TRACE(format, args...) #endif +#endif namespace TokenizerConsts { @@ -677,12 +684,20 @@ { m_IsOperator = false; - // skip blocks () [] - if (!SkipBlock(CurrentChar())) - return wxEmptyString; + if (m_State & tsReadRawExpression) + { + str= c; + MoveToNextChar(); + } + else + { + // skip blocks () [] + if (!SkipBlock(CurrentChar())) + return wxEmptyString; - str = FixArgument(m_Buffer.Mid(start, m_TokenIndex - start)); - CompactSpaces(str); + str = FixArgument(m_Buffer.Mid(start, m_TokenIndex - start)); + CompactSpaces(str); + } } else { @@ -845,4 +860,3 @@ return str; } - Index: src/plugins/codecompletion/parser/tokenizer.h =================================================================== --- src/plugins/codecompletion/parser/tokenizer.h (revision 6203) +++ src/plugins/codecompletion/parser/tokenizer.h (working copy) @@ -17,6 +17,7 @@ tsSkipQuestion = 0x0002, tsSkipSubScrip = 0x0004, tsSingleAngleBrace = 0x0008, + tsReadRawExpression= 0x0010, tsSkipNone = 0x1000, // convenient masks