我正在研究一个 RPN 计算器,现在我的 main.cpp 以及这些其他类文件应该接受一串代数运算,例如“3 + 4 / 2.34”,它可以采用算术运算符并且可以读取双精度数,整数、分数和混合分数(一个整数、一个空格,然后是一个分数)。
在命令控制台中,我收到此错误:
ASSERT: "uint(i) < uint(size())" in file c:\QtSDK\Desktop\Qt\4.8.1\mingw\include
/QtCore/qstring.h, line 701
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Press <RETURN> to close this window...
我对 QT 的理解不够好,无法找出这个错误的来源,所以除了显示我的代码并希望有人能帮助我之外,我没有其他选择。有很多代码:/我已经排除了 Fraction 和 Mixed 类的头文件和源代码,因为它们不使用编译器似乎在抱怨的 qstring.h。如果您认为这些是必需的,我可以发布它们。
据我所知,它与将无符号整数与整数进行比较有关,可能试图将负整数分配给 uint?这是奇怪的部分,在 main.cpp 文件中,输入字符串是“1345/43143 - 2”,这会导致错误。此外,“3+4”也会导致错误。奇怪的是,如果我将输入字符串设置为“2341 + (23 ^ 4.421) / 23/321 - 5 6/7”,它确实有效,但似乎没有其他输入字符串有效。
令牌.h
#ifndef TOKEN_H
#define TOKEN_H
#include "Mixed.h"
#include "Fraction.h"
class Token
{
public:
Token();
Token(const QString& Substring);
void SetIntPart(const QString& Substring);
void SetDoublePart(const QString& Substring);
void SetFractionPart(const QString& Substring);
void SetMixedPart(const QString& Substring);
void SetOperatorPart(const QString& Substring);
bool isDouble(const QString& Substring);
bool isInt(const QString& Substring);
bool isFraction(const QString& Substring);
bool isMixed(const QString& Substring);
bool isOperator(const QString& Substring);
bool isNumber()
{ return (inttoken || doubletoken || fractiontoken || mixedtoken); }
bool isLeftParen();
bool isRightParen();
bool isOperator();
int IntPart() { return intpart; }
double DoublePart() { return doublepart; }
Fraction FractionPart() { return fractionpart; }
Mixed MixedPart() { return mixedpart; }
char OperatorPart() { return operatorpart; }
bool IntToken() { return inttoken; }
bool DoubleToken() { return doubletoken; }
bool FractionToken() { return fractiontoken; }
bool MixedToken() { return mixedtoken; }
bool OperatorToken() { return operatortoken; }
QString toQString();
void Print(ostream& out) const;
friend ostream& operator<<(ostream& out, const Token& T);
private:
int intpart;
double doublepart;
Fraction fractionpart;
Mixed mixedpart;
char operatorpart;
bool inttoken;
bool doubletoken;
bool fractiontoken;
bool operatortoken;
bool mixedtoken;
void ClearBools();
void ClearParts();
void ClearAll() { ClearBools(); ClearParts(); }
};
#endif // TOKEN_H
解析器.h
#ifndef PARSER_H
#define PARSER_H
#include <iostream>
#include <cstdlib>
#include "Fraction.h"
#include "Mixed.h"
#include "Queue.h"
#include "Stack.h"
#include "Token.h"
class Parser
{
public:
Parser();
void LoadInputQueue(const QString& QS);
void LoadOutputQueue();
void CopyInputToString(QString &QS);
void CopyOutputToString(QString &QS);
bool isOperator(const QChar& Qch);
bool isSpace(const QChar& Qch);
bool isRightParen(const QChar& Qch);
bool isLeftParen(const QChar& Qch);
bool isParen(const QChar& Qch);
bool isDigit(const QChar& Qch);
void PrintInputQueue(ostream& out);
void PrintOutputQueue(ostream& out);
void PrintOperatorStack(ostream& out);
int precedence(Token T);
private:
Queue<Token> InputQueue;
Queue<Token> OutputQueue;
Stack<Token> OperatorStack;
void Tokenize(const QString& InputString, int n);
};
#endif // PARSER_H
主文件
#include <QtCore/QCoreApplication>
#include <cstdlib>
#include <iostream>
#include "Token.h"
#include "Parser.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
/*cout << "Fractiontoken: " << A.FractionToken() << endl;
cout << "Fraction part: " << A.FractionPart() << endl;
cout << "Inttoken: " << A.IntToken() << endl;
cout << "Int part: " << A.IntPart() << endl;
cout << "Doubletoken: " << A.DoubleToken() << endl;
cout << "Double part: " << A.DoublePart() << endl;
cout << "Mixedtoken: " << A.MixedToken() << endl;
cout << "Mixed part: " << A.MixedPart() << endl;
cout << "Operatortoken: " << A.OperatorToken() << endl;
cout << "Operator part: " << A.OperatorPart() << endl;*/
QString inputstring = "1345/43143 - 2";
Parser P;
QString displaystring;
P.LoadInputQueue(inputstring);
P.CopyInputToString(displaystring);
cout << qPrintable(displaystring);
cout << endl;
P.LoadOutputQueue();
P.CopyOutputToString(displaystring);
cout << qPrintable(displaystring);
cout << endl;
return a.exec();
}
解析器.cpp
#include "Parser.h"
enum PARENTHESIS_1{P1};
enum PARENTHESIS_2{P2};
bool Parser::isOperator(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == '+' ||
ch == '-' ||
ch == '*' ||
ch == '/' ||
ch == '(' ||
ch == ')' ||
ch == '^' )
return 1;
return 0;
}
bool Parser::isSpace(const QChar& Qch)
{
if (Qch.toAscii() == ' ')
return 1;
return 0;
}
bool Parser::isLeftParen(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == '(')
return 1;
return 0;
}
bool Parser::isRightParen(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == ')')
return 1;
return 0;
}
bool Parser::isParen(const QChar& Qch)
{
if (isRightParen(Qch) || isLeftParen(Qch))
return 1;
return 0;
}
bool Parser::isDigit(const QChar &Qch)
{
char ch = Qch.toAscii();
if (ch > 47 && ch < 58)
return 1;
return 0;
}
Parser::Parser() : InputQueue(100), OutputQueue(100)
{
}
void Parser::Tokenize(const QString& InputString, int n)
{
if (n >= InputString.size())
return;
else
{
if (isOperator(InputString[n]))
{
QString temp;
temp.append(InputString[n]);
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n+1);
}
else if (isSpace(InputString[n]))
Tokenize(InputString, n+1);
else
{
QString temp;
while (n < InputString.size() && !isSpace(InputString[n]) && !isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
if (isSpace(InputString[n]))
{
if (isDigit(InputString[n+1]))
{
temp.append(' ');
n++;
while (n < InputString.size() && !isSpace(InputString[n]) &&
!isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n);
}
else if (isOperator(InputString[n+1]))
{
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n+1);
}
}
else if (isParen(InputString[n]))
{
Token temptoken(temp);
InputQueue.enqueue(temptoken);
temp.clear();
temp.append(InputString[n]);
Token temptoken2(temp);
InputQueue.enqueue(temptoken2);
Tokenize(InputString, n+1);
}
}
}
}
int Parser::precedence(Token T)
{
if (T.OperatorToken())
{
char temp = T.OperatorPart();
if (temp == '^')
return 4;
if (temp == '*' || temp == '/')
return 3;
if (temp == '+' || temp == '-')
return 2;
}
return 1;
}
void Parser::LoadOutputQueue()
{
while (!InputQueue.empty())
{
Token temptoken;
InputQueue.dequeue(temptoken);
if (temptoken.isNumber())
OutputQueue.enqueue(temptoken);
else if (temptoken.isLeftParen())
OperatorStack.push(temptoken);
else if (temptoken.isRightParen())
{
while (!OperatorStack.empty() && !(OperatorStack.Peek()).isLeftParen())
{
Token temp;
OperatorStack.pop(temp);
OutputQueue.enqueue(temp);
}
if (!OperatorStack.empty() && (OperatorStack.Peek()).isLeftParen())
OperatorStack.pop(temptoken);
else if (OperatorStack.empty())
throw P1;
}
else if (temptoken.isOperator())
{
while (!OperatorStack.empty() && precedence(temptoken) < precedence(OperatorStack.Peek()))
{
Token temp;
OperatorStack.pop(temp);
OutputQueue.enqueue(temp);
}
OperatorStack.push(temptoken);
}
}
while (!OperatorStack.empty())
{
Token temptoken;
OperatorStack.pop(temptoken);
if (temptoken.isLeftParen())
throw P2;
OutputQueue.enqueue(temptoken);
}
}
//this function takes a QString (of chars) and from that builds its queue of tokens
void Parser::LoadInputQueue(const QString &QS)
{
Tokenize(QS,0);
}
void Parser::CopyOutputToString(QString &QS)
{
QString tempstring;
Token temptoken;
for (int i=OutputQueue.Size()-1; i>=0; i--)
{
temptoken = OutputQueue.Element(i);
tempstring.append(temptoken.toQString());
}
QS = tempstring;
}
void Parser::CopyInputToString(QString& QS)
{
QString tempstring;
Token temptoken;
for (int i=InputQueue.Size()-1; i>=0; i--)
{
temptoken = InputQueue.Element(i);
tempstring.append(temptoken.toQString());
}
QS = tempstring;
}
void Parser::PrintInputQueue(ostream& out)
{
out << InputQueue << endl;
}
void Parser::PrintOutputQueue(ostream& out)
{
out << OutputQueue << endl;
}
void Parser::PrintOperatorStack(ostream& out)
{
out << OperatorStack << endl;
}
令牌.cpp
#include "Token.h"
#include <QStringList>
enum TOKEN_EXCEPTIONS{UNKNOWN_TOKEN};
Token::Token()
{
}
Token::Token(const QString& Substring)
{
if (isInt(Substring))
SetIntPart(Substring);
else if (isDouble(Substring))
SetDoublePart(Substring);
else if (isFraction(Substring))
SetFractionPart(Substring);
else if (isMixed(Substring))
SetMixedPart(Substring);
else if (isOperator(Substring))
SetOperatorPart(Substring);
else
{
cout << qPrintable(Substring) << endl;
throw UNKNOWN_TOKEN;
}
}
void Token::SetIntPart(const QString& Substring)
{
ClearAll();
intpart = Substring.toInt();
inttoken = 1;
}
void Token::SetDoublePart(const QString& Substring)
{
ClearAll();
doublepart = Substring.toDouble();
doubletoken = 1;
}
void Token::SetFractionPart(const QString& Substring)
{
ClearAll();
QStringList Q;
Q = Substring.split('/');
Fraction frac(Q[0].toInt(),Q[1].toInt());
fractionpart = frac;
fractiontoken = 1;
}
void Token::SetMixedPart(const QString& Substring)
{
ClearAll();
QStringList Q1, Q2;
Q1 = Substring.split(' ');
QString wholepart = Q1[0];
Q2 = Q1[1].split('/');
QString numeratorstring = Q2[0];
QString denominatorstring = Q2[1];
Mixed M(wholepart.toInt(),numeratorstring.toInt(),denominatorstring.toInt());
mixedpart = M;
mixedtoken = 1;
}
void Token::SetOperatorPart(const QString& Substring)
{
ClearAll();
operatorpart = Substring[0].toAscii();
operatortoken = 1;
}
bool Token::isDouble(const QString& Substring)
{
int pointcount=0;
int intcount=0;
int pointloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (isdigit(Substring[i].toAscii()))
intcount++;
if (Substring[i].toAscii() == '.')
{
pointcount++;
pointloc = i;
}
}
if (pointcount != 1)
return 0;
if (intcount != Substring.size() - 1)
return 0;
return 1;
}
bool Token::isInt(const QString& Substring)
{
if (Substring[0].toAscii() == '0')
return 0;
for (int i=0; i<Substring.size(); i++)
{
if (!isdigit(Substring[i].toAscii()))
return 0;
}
return 1;
}
bool Token::isFraction(const QString& Substring)
{
int slashcount=0;
int intcount=0;
int slashloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (Substring[i].toAscii() == '/')
{
slashcount++;
slashloc = i;
}
if (isdigit(Substring[i].toAscii()))
intcount++;
}
if (slashcount != 1) // if there is not exactly 1 slash in substring
return 0;
if (intcount != Substring.size() - 1) //if the rest of the chars are not integers
return 0;
if (slashloc == 0 || slashloc == Substring.size() - 1) //if slash is at wrong location
return 0;
if (Substring[slashloc+1].toAscii() == '0' ||
Substring[0].toAscii() == '0')
return 0;
return 1;
}
bool Token::isMixed(const QString& Substring)
{
if (Substring[0].toAscii() == '0')
return 0;
int spacecount=0;
int slashcount=0;
int intcount=0;
int slashloc=0;
int spaceloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (isspace(Substring[i].toAscii()))
{
spacecount++;
spaceloc = i;
}
if (isdigit(Substring[i].toAscii()))
intcount++;
if (Substring[i].toAscii() == '/')
{
slashcount++;
slashloc = i;
}
}
// cout << "spacecount: " << spacecount << endl;
// cout << "slashcount: " << slashcount << endl;
// cout << "intcount: " << intcount << endl;
// cout << "slashloc: " << slashloc << endl;
// cout << "spaceloc: " << spaceloc << endl;
if (spacecount != 1)
return 0;
if (slashcount != 1)
return 0;
if (intcount != Substring.size() - 2)
return 0;
if (slashloc == 0 || slashloc == Substring.size()-1)
return 0;
if (spaceloc == 0 || spaceloc == Substring.size()-1)
return 0;
if (slashloc < spaceloc)
return 0;
if (!isdigit(Substring[slashloc-1].toAscii()) || !isdigit(Substring[slashloc+1].toAscii()))
return 0;
if (!isdigit(Substring[spaceloc-1].toAscii()) || !isdigit(Substring[slashloc+1].toAscii()))
return 0;
return 1;
}
bool Token::isOperator(const QString& Substring)
{
if (Substring.size() != 1)
return 0;
if (Substring[0] == '+' ||
Substring[0] == '-' ||
Substring[0] == '*' ||
Substring[0] == '^' ||
Substring[0] == '/' ||
Substring[0] == '(' ||
Substring[0] == ')')
return 1;
return 0;
}
void Token::ClearBools()
{
mixedtoken = 0;
inttoken = 0;
doubletoken = 0;
fractiontoken = 0;
operatortoken = 0;
}
void Token::ClearParts()
{
intpart = 0;
doublepart = 0;
Fraction f(0);
fractionpart = f;
Mixed m(0);
mixedpart = m;
operatorpart = NULL;
}
QString Token::toQString()
{
QString tempstring;
if (inttoken)
{
QString temp;
temp.setNum(intpart);
tempstring.append('[');
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (doubletoken)
{
QString temp;
temp.setNum(doublepart);
tempstring.append('[');
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (fractiontoken)
{
Fraction F = fractionpart;
QString temp;
tempstring.append('[');
temp.setNum(F.Numerator());
tempstring.append(temp);
tempstring.append('/');
temp.setNum(F.Denominator());
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (mixedtoken)
{
Mixed M = mixedpart;
QString temp;
tempstring.append('[');
temp.setNum(M.WholePart());
tempstring.append(temp);
tempstring.append(' ');
temp.setNum(M.Numerator());
tempstring.append(temp);
tempstring.append('/');
temp.setNum(M.Denominator());
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (operatortoken)
{
tempstring.append('[');
tempstring.append(operatorpart);
tempstring.append(']');
}
else
throw UNKNOWN_TOKEN;
}
void Token::Print(ostream& out) const
{
if (inttoken)
{
out << intpart;
}
else if (doubletoken)
{
out << doublepart;
}
else if (fractiontoken)
{
out << fractionpart;
}
else if (mixedtoken)
{
out << mixedpart;
}
else if (operatortoken)
{
out << operatorpart;
}
else
throw 1;
}
ostream& operator<<(ostream& out, const Token& T)
{
T.Print(out);
return out;
}
bool Token::isLeftParen()
{
if (operatortoken && operatorpart == '(')
return 1;
return 0;
}
bool Token::isRightParen()
{
if (operatortoken && operatorpart == ')')
return 1;
return 0;
}
bool Token::isOperator()
{
if (operatortoken)
return 1;
return 0;
}