work save: cpp parser preprocessor : handle branches

This commit is contained in:
royqh1979@gmail.com 2021-08-10 17:23:15 +08:00
parent b1062f24af
commit 2692d77fb1
2 changed files with 312 additions and 120 deletions

View File

@ -3,23 +3,6 @@
CppPreprocessor::CppPreprocessor(QObject *parent) : QObject(parent) CppPreprocessor::CppPreprocessor(QObject *parent) : QObject(parent)
{ {
mOperators.append("*");
mOperators.append("/");
mOperators.append("+");
mOperators.append("-");
mOperators.append("<");
mOperators.append("<=");
mOperators.append(">");
mOperators.append(">=");
mOperators.append("==");
mOperators.append("!=");
mOperators.append("&");
mOperators.append("^");
mOperators.append("|");
mOperators.append("&&");
mOperators.append("||");
mOperators.append("and");
mOperators.append("or");
} }
QString CppPreprocessor::getNextPreprocessor() QString CppPreprocessor::getNextPreprocessor()
@ -95,7 +78,7 @@ void CppPreprocessor::handleBranch(const QString &line)
constexpr int IF_LEN = 2; //length of if; constexpr int IF_LEN = 2; //length of if;
QString ifLine = line.mid(IF_LEN).trimmed(); QString ifLine = line.mid(IF_LEN).trimmed();
bool testResult = evaludateIf(ifLine); bool testResult = evaluateIf(ifLine);
setCurrentBranch(testResult); setCurrentBranch(testResult);
} }
} else if (line.startsWith("else")) { } else if (line.startsWith("else")) {
@ -110,7 +93,7 @@ void CppPreprocessor::handleBranch(const QString &line)
} else { } else {
constexpr int ELIF_LEN = 4; //length of if; constexpr int ELIF_LEN = 4; //length of if;
QString ifLine = line.mid(ELIF_LEN).trimmed(); QString ifLine = line.mid(ELIF_LEN).trimmed();
bool testResult = evaludateIf(ifLine); bool testResult = evaluateIf(ifLine);
setCurrentBranch(testResult); setCurrentBranch(testResult);
} }
} else if (line.startsWith("endif")) { } else if (line.startsWith("endif")) {
@ -353,7 +336,28 @@ bool CppPreprocessor::isMacroIdentChar(const QChar &ch)
bool CppPreprocessor::isDigit(const QChar &ch) bool CppPreprocessor::isDigit(const QChar &ch)
{ {
return (ch>='0' || ch<='9'); return (ch>='0' && ch<='9');
}
bool CppPreprocessor::isNumberChar(const QChar &ch)
{
if (ch>='0' && ch<='9')
return true;
if (ch>='a' && ch<='f')
return true;
if (ch>='A' && ch<='F')
return true;
switch(ch.unicode()) {
case 'x':
case 'X':
case 'u':
case 'U':
case 'l':
case 'L':
return true;
default:
return false;
}
} }
QString CppPreprocessor::lineBreak() QString CppPreprocessor::lineBreak()
@ -364,7 +368,7 @@ QString CppPreprocessor::lineBreak()
bool CppPreprocessor::evaluateIf(const QString &line) bool CppPreprocessor::evaluateIf(const QString &line)
{ {
QString newLine = expandDefines(line); // replace FOO by numerical value of FOO QString newLine = expandDefines(line); // replace FOO by numerical value of FOO
return removeSuffixes(evaluateExpression(newLine)), -1) > 0; return evaluateExpression(newLine);
} }
QString CppPreprocessor::expandDefines(QString line) QString CppPreprocessor::expandDefines(QString line)
@ -506,6 +510,270 @@ bool CppPreprocessor::skipSpaces(const QString &expr, int &pos)
return pos<expr.length(); return pos<expr.length();
} }
bool CppPreprocessor::evalNumber(const QString &expr, int &result, int &pos)
{
if (!skipSpaces(expr,pos))
return false;
QString s;
while (pos<expr.length() && isNumberChar(expr[pos])) {
s+=expr[pos];
pos++;
}
bool ok;
result = s.toInt(&ok,0);
return ok;
}
bool CppPreprocessor::evalTerm(const QString &expr, int &result, int &pos)
{
if (!skipSpaces(expr,pos))
return false;
if (expr[pos]=='(') {
pos++;
if (!evalExpr(expr,result,pos))
return false;
if (!skipSpaces(expr,pos))
return false;
if (expr[pos]!=')')
return false;
pos++;
} else {
return evalNumber(expr,result,pos);
}
}
/*
* unary_expr = term
| '+' term
| '-' term
| '!' term
| '~' term
*/
bool CppPreprocessor::evalUnaryExpr(const QString &expr, int &result, int &pos)
{
if (!skipSpaces(expr,pos))
return false;
if (expr[pos]=='+') {
pos++;
if (!evalTerm(expr,result,pos))
return false;
} else if (expr[pos]=='-') {
pos++;
if (!evalTerm(expr,result,pos))
return false;
result = -result;
} else if (expr[pos]=='~') {
pos++;
if (!evalTerm(expr,result,pos))
return false;
result = ~result;
} else if (expr[pos]=='!') {
pos++;
if (!evalTerm(expr,result,pos))
return false;
result = !result;
} else {
return evalTerm(expr,result,pos);
}
}
/*
* mul_expr = unary_expr
| mul_expr '*' unary_expr
| mul_expr '/' unary_expr
| mul_expr '%' unary_expr
*/
bool CppPreprocessor::evalMulExpr(const QString &expr, int &result, int &pos)
{
if (!evalUnaryExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
int rightResult;
if (expr[pos]=='*') {
pos++;
if (!evalUnaryExpr(expr,rightResult,pos))
return false;
result *= rightResult;
} else if (expr[pos]=='/') {
pos++;
if (!evalUnaryExpr(expr,rightResult,pos))
return false;
result /= rightResult;
} else if (expr[pos]=='%') {
pos++;
if (!evalUnaryExpr(expr,rightResult,pos))
return false;
result %= rightResult;
} else {
break;
}
}
return true;
}
/*
* add_expr = mul_expr
| add_expr '+' mul_expr
| add_expr '-' mul_expr
*/
bool CppPreprocessor::evalAddExpr(const QString &expr, int &result, int &pos)
{
if (!evalAddExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
int rightResult;
if (expr[pos]=='+') {
pos++;
if (!evalMulExpr(expr,rightResult,pos))
return false;
result += rightResult;
} else if (expr[pos]=='-') {
pos++;
if (!evalMulExpr(expr,rightResult,pos))
return false;
result -= rightResult;
} else {
break;
}
}
return true;
}
/*
* shift_expr = add_expr
| shift_expr "<<" add_expr
| shift_expr ">>" add_expr
*/
bool CppPreprocessor::evalShiftExpr(const QString &expr, int &result, int &pos)
{
if (!evalAddExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
int rightResult;
if (pos+1<expr.length() && expr[pos] == '<' && expr[pos+1]=='<') {
pos += 2;
if (!evalAddExpr(expr,rightResult,pos))
return false;
result = (result << rightResult);
} else if (pos+1<expr.length() && expr[pos] == '>' && expr[pos+1]=='>') {
pos += 2;
if (!evalAddExpr(expr,rightResult,pos))
return false;
result = (result >> rightResult);
} else {
break;
}
}
return true;
}
/*
* relation_expr = shift_expr
| relation_expr ">=" shift_expr
| relation_expr ">" shift_expr
| relation_expr "<=" shift_expr
| relation_expr "<" shift_expr
*/
bool CppPreprocessor::evalRelationExpr(const QString &expr, int &result, int &pos)
{
if (!evalShiftExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
int rightResult;
if (expr[pos]=='<') {
if (pos+1<expr.length() && expr[pos+1]=='=') {
pos+=2;
if (!evalShiftExpr(expr,rightResult,pos))
return false;
result = (result <= rightResult);
} else {
pos++;
if (!evalShiftExpr(expr,rightResult,pos))
return false;
result = (result < rightResult);
}
} else if (expr[pos]=='>') {
if (pos+1<expr.length() && expr[pos+1]=='=') {
pos+=2;
if (!evalShiftExpr(expr,rightResult,pos))
return false;
result = (result >= rightResult);
} else {
pos++;
if (!evalShiftExpr(expr,rightResult,pos))
return false;
result = (result > rightResult);
}
} else {
break;
}
}
return true;
}
/*
* equal_expr = relation_expr
| equal_expr "==" relation_expr
| equal_expr "!=" relation_expr
*/
bool CppPreprocessor::evalEqualExpr(const QString &expr, int &result, int &pos)
{
if (!evalRelationExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
if (pos+1<expr.length() && expr[pos]=='!' && expr[pos+1]=='=') {
pos+=2;
int rightResult;
if (!evalRelationExpr(expr,rightResult,pos))
return false;
result = (result != rightResult);
} else if (pos+1<expr.length() && expr[pos]=='=' && expr[pos+1]=='=') {
pos+=2;
int rightResult;
if (!evalRelationExpr(expr,rightResult,pos))
return false;
result = (result == rightResult);
} else {
break;
}
}
return true;
}
/*
* bit_and_expr = equal_expr
| bit_and_expr "&" equal_expr
*/
bool CppPreprocessor::evalBitAndExpr(const QString &expr, int &result, int &pos)
{
if (!evalEqualExpr(expr,result,pos))
return false;
while (true) {
if (!skipSpaces(expr,pos))
break;
if (expr[pos]=='&') {
pos++;
int rightResult;
if (!evalEqualExpr(expr,rightResult,pos))
return false;
result = result & rightResult;
} else {
break;
}
}
return true;
}
/* /*
* bit_xor_expr = bit_and_expr * bit_xor_expr = bit_and_expr
| bit_xor_expr "^" bit_and_expr | bit_xor_expr "^" bit_and_expr
@ -515,12 +783,12 @@ bool CppPreprocessor::evalBitXorExpr(const QString &expr, int &result, int &pos)
if (!evalBitAndExpr(expr,result,pos)) if (!evalBitAndExpr(expr,result,pos))
return false; return false;
while (true) { while (true) {
if (!skipBraces(expr,result,pos)) if (!skipSpaces(expr,pos))
break; break;
if (expr[pos]=='^') { if (expr[pos]=='^') {
pos++; pos++;
int rightResult; int rightResult;
if (!evalBitAndExpr(expr,result,pos)) if (!evalBitAndExpr(expr,rightResult,pos))
return false; return false;
result = result ^ rightResult; result = result ^ rightResult;
} else { } else {
@ -539,12 +807,12 @@ bool CppPreprocessor::evalBitOrExpr(const QString &expr, int &result, int &pos)
if (!evalBitXorExpr(expr,result,pos)) if (!evalBitXorExpr(expr,result,pos))
return false; return false;
while (true) { while (true) {
if (!skipBraces(expr,result,pos)) if (!skipSpaces(expr,pos))
break; break;
if (expr[pos] == '|') { if (expr[pos] == '|') {
pos++; pos++;
int rightResult; int rightResult;
if (!evalBitXorExpr(expr,result,pos)) if (!evalBitXorExpr(expr,rightResult,pos))
return false; return false;
result = result | rightResult; result = result | rightResult;
} else { } else {
@ -563,7 +831,7 @@ bool CppPreprocessor::evalLogicAndExpr(const QString &expr, int &result, int &po
if (!evalBitOrExpr(expr,result,pos)) if (!evalBitOrExpr(expr,result,pos))
return false; return false;
while (true) { while (true) {
if (!skipBraces(expr,result,pos)) if (!skipSpaces(expr,pos))
break; break;
if (pos+1<expr.length() && expr[pos]=='&' && expr[pos+1] =='&') { if (pos+1<expr.length() && expr[pos]=='&' && expr[pos+1] =='&') {
pos+=2; pos+=2;
@ -587,7 +855,7 @@ bool CppPreprocessor::evalLogicOrExpr(const QString &expr, int &result, int &pos
if (!evalLogicAndExpr(expr,result,pos)) if (!evalLogicAndExpr(expr,result,pos))
return false; return false;
while (true) { while (true) {
if (!skipBraces(expr,result,pos)) if (!skipSpaces(expr,pos))
break; break;
if (pos+1<expr.length() && expr[pos]=='|' && expr[pos+1] =='|') { if (pos+1<expr.length() && expr[pos]=='|' && expr[pos+1] =='|') {
pos+=2; pos+=2;
@ -645,96 +913,16 @@ logic_or_expr = logic_and_expr
| logic_or_expr "||" logic_and_expr | logic_or_expr "||" logic_and_expr
*/ */
QString CppPreprocessor::evaluateExpression(QString line) int CppPreprocessor::evaluateExpression(QString line)
{ {
//todo: improve this int pos = 0;
// Find the first closing brace (this should leave us at the innermost brace pair) int result;
while (true) { bool ok = evalExpr(line,result,pos);
int head = line.indexOf(')'); if (!ok)
if (head<0) return -1;
break; //expr not finished
int tail = head; if (skipSpaces(line,pos))
if (skipBraces(line, tail, -1)) { // find the corresponding opening brace return -1;
QString resultLine = evaluateExpression(line.mid(tail + 1, head - tail - 1)); // evaluate this (without braces) return result;
line.remove(tail, head - tail + 1); // Remove the old part AND braces
line.insert(tail,resultLine); // and replace by result
} else {
return "";
}
}
// Then evaluate braceless part
while (true) {
int operatorPos;
QString operatorToken = getNextOperator(operatorPos);
if (operatorPos < 0)
break;
// Get left operand
int tail = operatorPos - 1;
while ((tail >= 0) && isSpaceChar(line[tail]))
tail--; // skip spaces
Head := Tail;
while (Head >= 0) and (Line[Head] in IdentChars) do
Dec(Head); // step over identifier
LeftOp := Copy(Line, Head + 1, Tail - Head);
EquatStart := Head + 1; // marks begin of equation
// Get right operand
Tail := OperatorPos + Length(OperatorToken) + 1;
while (Tail <= Length(Line)) and (Line[Tail] in SpaceChars) do
Inc(Tail); // skip spaces
Head := Tail;
while (Head <= Length(Line)) and (Line[Head] in IdentChars) do
Inc(Head); // step over identifier
RightOp := Copy(Line, Tail, Head - Tail);
EquatEnd := Head; // marks begin of equation
// Evaluate after removing length suffixes...
LeftOpValue := StrToIntDef(RemoveSuffixes(LeftOp), 0);
RightOpValue := StrToIntDef(RemoveSuffixes(RightOp), 0);
if OperatorToken = '*' then
ResultValue := LeftOpValue * RightOpValue
else if OperatorToken = '/' then begin
if RightOpValue = 0 then
ResultValue := LeftOpValue
else
ResultValue := LeftOpValue div RightOpValue; // int division
end else if OperatorToken = '+' then
ResultValue := LeftOpValue + RightOpValue
else if OperatorToken = '-' then
ResultValue := LeftOpValue - RightOpValue
else if OperatorToken = '<' then
ResultValue := integer(LeftOpValue < RightOpValue)
else if OperatorToken = '<=' then
ResultValue := integer(LeftOpValue <= RightOpValue)
else if OperatorToken = '>' then
ResultValue := integer(LeftOpValue > RightOpValue)
else if OperatorToken = '>=' then
ResultValue := integer(LeftOpValue >= RightOpValue)
else if OperatorToken = '==' then
ResultValue := integer(LeftOpValue = RightOpValue)
else if OperatorToken = '!=' then
ResultValue := integer(LeftOpValue <> RightOpValue)
else if OperatorToken = '&' then // bitwise and
ResultValue := integer(LeftOpValue and RightOpValue)
else if OperatorToken = '|' then // bitwise or
ResultValue := integer(LeftOpValue or RightOpValue)
else if OperatorToken = '^' then // bitwise xor
ResultValue := integer(LeftOpValue xor RightOpValue)
else if (OperatorToken = '&&') or (OperatorToken = 'and') then
ResultValue := integer(LeftOpValue and RightOpValue)
else if (OperatorToken = '||') or (OperatorToken = 'or') then
ResultValue := integer(LeftOpValue or RightOpValue)
else
ResultValue := 0;
// And replace by result in string form
Delete(Line, EquatStart, EquatEnd - EquatStart);
Insert(IntToStr(ResultValue), Line, EquatStart);
end else
break;
end;
Result := Line;
} }

View File

@ -99,6 +99,11 @@ private:
*/ */
bool isDigit(const QChar& ch); bool isDigit(const QChar& ch);
/*
* '0'..'9','x',X','a'..'f','A'..'F','u','U','l','L'
*/
bool isNumberChar(const QChar& ch);
QString lineBreak(); QString lineBreak();
bool evaluateIf(const QString& line); bool evaluateIf(const QString& line);
@ -106,6 +111,7 @@ private:
bool skipBraces(const QString&line, int& index, int step = 1); bool skipBraces(const QString&line, int& index, int step = 1);
QString expandFunction(PDefine define,QString args); QString expandFunction(PDefine define,QString args);
bool skipSpaces(const QString &expr, int& pos); bool skipSpaces(const QString &expr, int& pos);
bool evalNumber(const QString &expr, int& result, int& pos);
bool evalTerm(const QString &expr, int& result, int& pos); bool evalTerm(const QString &expr, int& result, int& pos);
bool evalUnaryExpr(const QString &expr, int& result, int& pos); bool evalUnaryExpr(const QString &expr, int& result, int& pos);
bool evalMulExpr(const QString &expr, int& result, int& pos); bool evalMulExpr(const QString &expr, int& result, int& pos);
@ -120,7 +126,7 @@ private:
bool evalLogicOrExpr(const QString &expr, int& result, int& pos); bool evalLogicOrExpr(const QString &expr, int& result, int& pos);
bool evalExpr(const QString &expr, int& result, int& pos); bool evalExpr(const QString &expr, int& result, int& pos);
QString evaluateExpression(QString line); int evaluateExpression(QString line);
private: private:
int mIndex; // points to current file buffer. do not free int mIndex; // points to current file buffer. do not free
QString mFileName; // idem QString mFileName; // idem
@ -140,8 +146,6 @@ private:
bool mParseLocal; bool mParseLocal;
QSet<QString> mScannedFiles; QSet<QString> mScannedFiles;
QSet<QString> mProcessed; // dictionary to save filename already processed QSet<QString> mProcessed; // dictionary to save filename already processed
QStringList mOperators;
}; };
#endif // CPPPREPROCESSOR_H #endif // CPPPREPROCESSOR_H