- Enhancement: Better support for macros.

This commit is contained in:
Roy Qu 2023-11-26 15:44:13 +08:00
parent d75f550742
commit bfd00957eb
5 changed files with 134 additions and 115 deletions

View File

@ -32,6 +32,7 @@ Red Panda C++ Version 2.26
- change: Use qt.conf to use freetype font engine. User can use the windows default font engine by remove this file. - change: Use qt.conf to use freetype font engine. User can use the windows default font engine by remove this file.
- fix: Click on the line begin may toggle breakpoint. - fix: Click on the line begin may toggle breakpoint.
- change: Don't auto add; when completing '{' for lines starting with 'struct/union/enum' and ending with ')' - change: Don't auto add; when completing '{' for lines starting with 'struct/union/enum' and ending with ')'
- Enhancement: Better support for macros.
Red Panda C++ Version 2.25 Red Panda C++ Version 2.25

View File

@ -499,6 +499,7 @@ PEvalStatement CppParser::evalExpression(
pos, pos,
currentScope, currentScope,
PEvalStatement(), PEvalStatement(),
true,
true); true);
} }
@ -537,7 +538,7 @@ PStatement CppParser::doFindStatementOf(const QString &fileName, const QStringLi
pos, pos,
currentScope, currentScope,
PEvalStatement(), PEvalStatement(),
true); true,false);
if (!ownerEvalStatement) { if (!ownerEvalStatement) {
return PStatement(); return PStatement();
} }
@ -4126,7 +4127,7 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
pos, pos,
getCurrentScope(), getCurrentScope(),
PEvalStatement(), PEvalStatement(),
true); true,false);
if(aliasStatement && aliasStatement->effectiveTypeStatement) { if(aliasStatement && aliasStatement->effectiveTypeStatement) {
if (STLMaps.contains(aliasStatement->effectiveTypeStatement->fullName)) { if (STLMaps.contains(aliasStatement->effectiveTypeStatement->fullName)) {
addedVar->type = "std::pair"+aliasStatement->templateParams; addedVar->type = "std::pair"+aliasStatement->templateParams;
@ -4194,7 +4195,7 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
pos, pos,
getCurrentScope(), getCurrentScope(),
PEvalStatement(), PEvalStatement(),
true); true,false);
if(aliasStatement) { if(aliasStatement) {
if (aliasStatement->effectiveTypeStatement) { if (aliasStatement->effectiveTypeStatement) {
addedVar->type = aliasStatement->effectiveTypeStatement->fullName; addedVar->type = aliasStatement->effectiveTypeStatement->fullName;
@ -4294,7 +4295,7 @@ void CppParser::handleVar(const QString& typePrefix,bool isExtern,bool isStatic)
pos, pos,
getCurrentScope(), getCurrentScope(),
PEvalStatement(), PEvalStatement(),
true); true,false);
if(aliasStatement && aliasStatement->effectiveTypeStatement) { if(aliasStatement && aliasStatement->effectiveTypeStatement) {
if (aliasStatement->effectiveTypeStatement) { if (aliasStatement->effectiveTypeStatement) {
addedVar->type = aliasStatement->effectiveTypeStatement->fullName; addedVar->type = aliasStatement->effectiveTypeStatement->fullName;
@ -4544,8 +4545,7 @@ PStatement CppParser::findMacro(const QString &phrase, const QString &fileName)
PFileIncludes includes = mPreprocessor.findFileIncludes(fileName); PFileIncludes includes = mPreprocessor.findFileIncludes(fileName);
foreach (const PStatement& s, statements) { foreach (const PStatement& s, statements) {
if (s->kind == StatementKind::skPreprocessor) { if (s->kind == StatementKind::skPreprocessor) {
if (includes && !includes->includeFiles.contains(s->fileName) if (includes && fileName != s->fileName && !includes->includeFiles.contains(s->fileName))
&& !includes->includeFiles.contains(s->definitionFileName))
continue; continue;
return s; return s;
} }
@ -4687,13 +4687,35 @@ PStatement CppParser::findStatementInNamespace(const QString &name, const QStrin
} }
PEvalStatement CppParser::doEvalExpression(const QString& fileName, PEvalStatement CppParser::doEvalExpression(const QString& fileName,
QStringList& phraseExpression, QStringList phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const bool freeScoped,
bool expandMacros) const
{ {
//dummy function to easy later upgrades if (expandMacros) {
QList<QSet<QString>> usedMacros;
usedMacros.reserve(phraseExpression.length());
for(int i=0;i<phraseExpression.length();i++) {
usedMacros.append(QSet<QString>());
}
int i=pos;
while(i<phraseExpression.length()) {
QString word = phraseExpression[i];
if (isIdentifier(word)) {
QSet<QString> used = usedMacros[i];
if (!used.contains(word)) {
PStatement macro = findMacro(word, fileName);
if (macro) {
if(!expandMacro(phraseExpression, i, macro, usedMacros))
continue;
}
}
}
i++;
}
}
return doEvalPointerArithmetic(fileName, return doEvalPointerArithmetic(fileName,
phraseExpression, phraseExpression,
pos, pos,
@ -4702,7 +4724,7 @@ PEvalStatement CppParser::doEvalExpression(const QString& fileName,
freeScoped); freeScoped);
} }
PEvalStatement CppParser::doEvalPointerArithmetic(const QString &fileName, QStringList &phraseExpression, int &pos, const PStatement &scope, const PEvalStatement &previousResult, bool freeScoped) const PEvalStatement CppParser::doEvalPointerArithmetic(const QString &fileName, const QStringList &phraseExpression, int &pos, const PStatement &scope, const PEvalStatement &previousResult, bool freeScoped) const
{ {
if (pos>=phraseExpression.length()) if (pos>=phraseExpression.length())
return PEvalStatement(); return PEvalStatement();
@ -4753,7 +4775,7 @@ PEvalStatement CppParser::doEvalPointerArithmetic(const QString &fileName, QStri
PEvalStatement CppParser::doEvalPointerToMembers( PEvalStatement CppParser::doEvalPointerToMembers(
const QString &fileName, const QString &fileName,
QStringList &phraseExpression, const QStringList &phraseExpression,
int &pos, int &pos,
const PStatement &scope, const PStatement &scope,
const PEvalStatement &previousResult, const PEvalStatement &previousResult,
@ -4796,7 +4818,7 @@ PEvalStatement CppParser::doEvalPointerToMembers(
} }
PEvalStatement CppParser::doEvalCCast(const QString &fileName, PEvalStatement CppParser::doEvalCCast(const QString &fileName,
QStringList &phraseExpression, const QStringList &phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
@ -4901,7 +4923,8 @@ PEvalStatement CppParser::doEvalCCast(const QString &fileName,
pos, pos,
scope, scope,
PEvalStatement(), PEvalStatement(),
true); true,
false);
// qDebug()<<pos; // qDebug()<<pos;
if (pos >= phraseExpression.length() || phraseExpression[pos]!=")") { if (pos >= phraseExpression.length() || phraseExpression[pos]!=")") {
return PEvalStatement(); return PEvalStatement();
@ -4945,7 +4968,7 @@ PEvalStatement CppParser::doEvalCCast(const QString &fileName,
} }
PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName,
QStringList &phraseExpression, const QStringList &phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
@ -4979,7 +5002,8 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName,
pos, pos,
scope, scope,
PEvalStatement(), PEvalStatement(),
true); true,
false);
if (newResult) if (newResult)
newResult->assignType(result); newResult->assignType(result);
pos++; // skip ")" pos++; // skip ")"
@ -5163,7 +5187,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName,
} }
PEvalStatement CppParser::doEvalScopeResolution(const QString &fileName, PEvalStatement CppParser::doEvalScopeResolution(const QString &fileName,
QStringList &phraseExpression, const QStringList &phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
@ -5218,7 +5242,7 @@ PEvalStatement CppParser::doEvalScopeResolution(const QString &fileName,
} }
PEvalStatement CppParser::doEvalTerm(const QString &fileName, PEvalStatement CppParser::doEvalTerm(const QString &fileName,
QStringList &phraseExpression, const QStringList &phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
@ -5235,7 +5259,7 @@ PEvalStatement CppParser::doEvalTerm(const QString &fileName,
// qDebug()<<"eval term"<<phraseExpression[pos]; // qDebug()<<"eval term"<<phraseExpression[pos];
if (phraseExpression[pos]=="(") { if (phraseExpression[pos]=="(") {
pos++; pos++;
result = doEvalExpression(fileName,phraseExpression,pos,scope,PEvalStatement(),freeScoped); result = doEvalExpression(fileName,phraseExpression,pos,scope,PEvalStatement(),freeScoped,false);
if (pos >= phraseExpression.length() || phraseExpression[pos]!=")") if (pos >= phraseExpression.length() || phraseExpression[pos]!=")")
return PEvalStatement(); return PEvalStatement();
else { else {
@ -5329,15 +5353,6 @@ PEvalStatement CppParser::doEvalTerm(const QString &fileName,
result = doCreateEvalFunction(fileName,statement); result = doCreateEvalFunction(fileName,statement);
} }
break; break;
case StatementKind::skPreprocessor:
// qDebug()<<"before"<<phraseExpression;
pos--;
if (expandMacro(phraseExpression,pos,statement)) {
// qDebug()<<"after"<<phraseExpression;
result = doEvalExpression(fileName,phraseExpression,pos,scope,previousResult,freeScoped);
} else
result = PEvalStatement();
break;
default: default:
result = PEvalStatement(); result = PEvalStatement();
} }
@ -5395,12 +5410,14 @@ PEvalStatement CppParser::doEvalTerm(const QString &fileName,
return result; return result;
} }
bool CppParser::expandMacro(QStringList &phraseExpression, int &pos, const PStatement &macro) const bool CppParser::expandMacro(QStringList &phraseExpression, int pos, PStatement macro, QList< QSet<QString> > &usedMacros) const
{ {
QString s; QString s;
QSet<QString> used = usedMacros[pos];
if (macro->args.isEmpty()) { if (macro->args.isEmpty()) {
s=macro->value; s=macro->value;
phraseExpression.removeAt(pos); phraseExpression.removeAt(pos);
usedMacros.removeAt(pos);
} else { } else {
QString args=macro->args.mid(1,macro->args.length()-2).trimmed(); // remove '(' ')' QString args=macro->args.mid(1,macro->args.length()-2).trimmed(); // remove '(' ')'
@ -5480,13 +5497,14 @@ bool CppParser::expandMacro(QStringList &phraseExpression, int &pos, const PStat
} }
for (int j=pos;j<=i;j++) { for (int j=pos;j<=i;j++) {
phraseExpression.removeAt(pos); phraseExpression.removeAt(pos);
usedMacros.removeAt(pos);
} }
} }
used.insert(macro->command);
QSynedit::CppSyntaxer syntaxer; QSynedit::CppSyntaxer syntaxer;
syntaxer.resetState(); syntaxer.resetState();
syntaxer.setLine(s,0); syntaxer.setLine(s,0);
int i=0;
while (!syntaxer.eol()) { while (!syntaxer.eol()) {
QString token=syntaxer.getToken(); QString token=syntaxer.getToken();
QSynedit::PTokenAttribute attr = syntaxer.getTokenAttribute(); QSynedit::PTokenAttribute attr = syntaxer.getTokenAttribute();
@ -5495,15 +5513,14 @@ bool CppParser::expandMacro(QStringList &phraseExpression, int &pos, const PStat
case QSynedit::TokenType::Comment: case QSynedit::TokenType::Comment:
break; break;
case QSynedit::TokenType::Identifier: case QSynedit::TokenType::Identifier:
if (token!=macro->command) phraseExpression.insert(pos,token);
phraseExpression.insert(pos+i,token); usedMacros.insert(pos,used);
else pos++;
phraseExpression.insert(pos+i,token+"_expanded");
i++;
break; break;
default: default:
phraseExpression.insert(pos+i,token); phraseExpression.insert(pos,token);
i++; usedMacros.insert(pos,used);
pos++;
} }
syntaxer.next(); syntaxer.next();
} }
@ -5541,7 +5558,8 @@ PEvalStatement CppParser::doFindAliasedNamespace(const PStatement &namespaceAlia
pos, pos,
namespaceAlias->parentScope.lock(), namespaceAlias->parentScope.lock(),
PEvalStatement(), PEvalStatement(),
true true,
false
); );
} }

View File

@ -319,57 +319,58 @@ private:
* @return * @return
*/ */
PEvalStatement doEvalExpression(const QString& fileName, PEvalStatement doEvalExpression(const QString& fileName,
QStringList& phraseExpression, QStringList phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped,
bool expandMacros) const;
PEvalStatement doEvalPointerArithmetic( PEvalStatement doEvalPointerArithmetic(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
PEvalStatement doEvalPointerToMembers( PEvalStatement doEvalPointerToMembers(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
PEvalStatement doEvalCCast( PEvalStatement doEvalCCast(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
PEvalStatement doEvalMemberAccess( PEvalStatement doEvalMemberAccess(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
PEvalStatement doEvalScopeResolution( PEvalStatement doEvalScopeResolution(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
PEvalStatement doEvalTerm( PEvalStatement doEvalTerm(
const QString& fileName, const QString& fileName,
QStringList& phraseExpression, const QStringList& phraseExpression,
int &pos, int &pos,
const PStatement& scope, const PStatement& scope,
const PEvalStatement& previousResult, const PEvalStatement& previousResult,
bool freeScoped) const; bool freeScoped) const;
bool expandMacro(QStringList& phraseExpression,int &pos, bool expandMacro(QStringList& phraseExpression,int pos,
const PStatement& macro) const; PStatement macro, QList< QSet<QString> > &usedMacros) const;
PEvalStatement doCreateEvalNamespace(const PStatement& namespaceStatement) const; PEvalStatement doCreateEvalNamespace(const PStatement& namespaceStatement) const;

View File

@ -515,11 +515,8 @@ void CppPreprocessor::handleUndefine(const QString &line)
} }
} }
QString CppPreprocessor::expandMacros(const QString &line, int depth) QString CppPreprocessor::expandMacros(const QString &line, QSet<QString> usedMacros)
{ {
//prevent infinit recursion
if (depth > MAX_DEFINE_EXPAND_DEPTH)
return line;
QString word; QString word;
QString newLine; QString newLine;
int lenLine = line.length(); int lenLine = line.length();
@ -530,7 +527,7 @@ QString CppPreprocessor::expandMacros(const QString &line, int depth)
word += ch; word += ch;
} else { } else {
if (!word.isEmpty()) { if (!word.isEmpty()) {
expandMacro(line,newLine,word,i,depth); expandMacro(line,newLine,word,i,usedMacros);
} }
word = ""; word = "";
if (i< lenLine) { if (i< lenLine) {
@ -540,7 +537,7 @@ QString CppPreprocessor::expandMacros(const QString &line, int depth)
i++; i++;
} }
if (!word.isEmpty()) { if (!word.isEmpty()) {
expandMacro(line,newLine,word,i,depth); expandMacro(line,newLine,word,i, usedMacros);
} }
return newLine; return newLine;
} }
@ -551,6 +548,7 @@ QString CppPreprocessor::expandMacros()
QString word; QString word;
QString newLine; QString newLine;
QString line = mBuffer[mIndex]; QString line = mBuffer[mIndex];
QSet<QString> usedMacros;
int i=0; int i=0;
while (mIndex < mBuffer.size() && i<line.length()) { while (mIndex < mBuffer.size() && i<line.length()) {
QChar ch=line[i]; QChar ch=line[i];
@ -558,7 +556,7 @@ QString CppPreprocessor::expandMacros()
word += ch; word += ch;
} else { } else {
if (!word.isEmpty()) { if (!word.isEmpty()) {
expandMacro(newLine,word,i,1); expandMacro(newLine,word,i,usedMacros);
if (mIndex>=mBuffer.length()) if (mIndex>=mBuffer.length())
return newLine; return newLine;
line = mBuffer[mIndex]; line = mBuffer[mIndex];
@ -571,21 +569,23 @@ QString CppPreprocessor::expandMacros()
i++; i++;
} }
if (!word.isEmpty()) { if (!word.isEmpty()) {
expandMacro(newLine,word,i,1); expandMacro(newLine,word,i,usedMacros);
} }
return newLine; return newLine;
} }
void CppPreprocessor::expandMacro(const QString &line, QString &newLine, QString &word, int &i, int depth) void CppPreprocessor::expandMacro(const QString &line, QString &newLine, QString &word, int &i, QSet<QString> usedMacros)
{ {
if (usedMacros.contains(word))
return;
int lenLine = line.length(); int lenLine = line.length();
PDefine define = getDefine(word); PDefine define = getDefine(word);
if (define && define->args=="" ) { if (define && define->args=="" ) {
if (define->value != word ) usedMacros.insert(word);
newLine += expandMacros(define->value,depth+1); if (define->value != word ) {
else newLine += expandMacros(define->value,usedMacros);
} else
newLine += word; newLine += word;
} else if (define && (define->args!="")) { } else if (define && (define->args!="")) {
while ((i<lenLine) && (line[i] == ' ' || line[i]=='\t')) while ((i<lenLine) && (line[i] == ' ' || line[i]=='\t'))
i++; i++;
@ -620,7 +620,8 @@ void CppPreprocessor::expandMacro(const QString &line, QString &newLine, QString
argEnd = i-2; argEnd = i-2;
QString args = line.mid(argStart,argEnd-argStart+1).trimmed(); QString args = line.mid(argStart,argEnd-argStart+1).trimmed();
QString formattedValue = expandFunction(define,args); QString formattedValue = expandFunction(define,args);
newLine += expandMacros(formattedValue,depth+1); usedMacros.insert(word);
newLine += expandMacros(formattedValue,usedMacros);
} }
} }
} else { } else {
@ -629,15 +630,16 @@ void CppPreprocessor::expandMacro(const QString &line, QString &newLine, QString
// } // }
} }
void CppPreprocessor::expandMacro(QString &newLine, QString &word, int &i, int depth) void CppPreprocessor::expandMacro(QString &newLine, QString &word, int &i, QSet<QString> usedMacros)
{ {
if (usedMacros.contains(word))
return;
QString line = mBuffer[mIndex]; QString line = mBuffer[mIndex];
PDefine define = getDefine(word); PDefine define = getDefine(word);
// if (define && define->name == "DEFHOOKPODX")
// qDebug()<<define->args<<define->argList<<define->formatValue;
if (define && define->args=="" ) { if (define && define->args=="" ) {
usedMacros.insert(word);
if (define->value != word ) if (define->value != word )
newLine += expandMacros(define->value,depth+1); newLine += expandMacros(define->value,usedMacros);
else else
newLine += word; newLine += word;
} else if (define && (define->args!="")) { } else if (define && (define->args!="")) {
@ -709,13 +711,10 @@ void CppPreprocessor::expandMacro(QString &newLine, QString &word, int &i, int d
args += mBuffer[i]; args += mBuffer[i];
} }
args += mBuffer[argLineEnd].left(argEnd); args += mBuffer[argLineEnd].left(argEnd);
// if (define && define->name == "DEFHOOK")
// qDebug()<<args;
} }
QString formattedValue = expandFunction(define,args); QString formattedValue = expandFunction(define,args);
// if (define && define->name == "DEFHOOKPODX") usedMacros.insert(word);
// qDebug()<<formattedValue; newLine += expandMacros(formattedValue,usedMacros);
newLine += expandMacros(formattedValue,depth+1);
} }
} else { } else {
newLine+=word; newLine+=word;

View File

@ -135,10 +135,10 @@ private:
void handleInclude(const QString& line, bool fromNext=false); void handleInclude(const QString& line, bool fromNext=false);
void handlePreprocessor(const QString& value); void handlePreprocessor(const QString& value);
void handleUndefine(const QString& line); void handleUndefine(const QString& line);
QString expandMacros(const QString& line, int depth); QString expandMacros(const QString& line, QSet<QString> usedMacros);
QString expandMacros(); QString expandMacros();
void expandMacro(const QString& line, QString& newLine, QString& word, int& i, int depth); void expandMacro(const QString& line, QString& newLine, QString& word, int& i, QSet<QString> usedMacros);
void expandMacro(QString& newLine, QString& word, int& i, int depth); void expandMacro(QString& newLine, QString& word, int& i, QSet<QString> usedMacros);
QString removeGCCAttributes(const QString& line); QString removeGCCAttributes(const QString& line);
void removeGCCAttribute(const QString&line, QString& newLine, int &i, const QString& word); void removeGCCAttribute(const QString&line, QString& newLine, int &i, const QString& word);
PDefine getDefine(const QString& name) const{ PDefine getDefine(const QString& name) const{