From c2f2420a89e103813a3c33e0e8f52de48b60dcbf Mon Sep 17 00:00:00 2001 From: Thunder422 Date: Mon, 5 Jan 2015 20:53:07 -0500 Subject: [PATCH] token: changed conversion code handling changed convert constant to throw error for nonconvertible doubles changed convert code to throw errors for nonconvertible tokens added is data type compatible function for checking references modified table find code for changes to convert constant and code modified translator routines for changes to convert constant and code modified translator get operand to use is data type compatible removed table set token code with data type argument - only caller left was token constructor for string constants --- table.cpp | 21 ++++------ table.h | 1 - token.cpp | 102 ++++++++++++++++++++++++------------------------- token.h | 7 ++++ translator.cpp | 42 +++++++------------- 5 files changed, 78 insertions(+), 95 deletions(-) diff --git a/table.cpp b/table.cpp index 4e50933..3d3e0a9 100644 --- a/table.cpp +++ b/table.cpp @@ -1730,9 +1730,16 @@ Code Table::findCode(TokenPtr &token, TokenPtr &operandToken, int operandIndex) // check if constant should be converted to needed data type if (operandIndex == operandCount(token) - 1 // last operand? && !hasFlag(token, UseConstAsIs_Flag)) + try { operandToken->convertConstant(expectedDataType); } + catch (Status) + { + // don't throw unconvertible doubles to integer errors here + // doubles as is may be acceptable depending on operator + // (will catch if double can't be converted if integer needed below) + } // see if any alternate code's data types match if (setTokenCode(token.get(), token->code(), operandToken->dataType(), @@ -1742,14 +1749,7 @@ Code Table::findCode(TokenPtr &token, TokenPtr &operandToken, int operandIndex) } // get a conversion code if no alternate code was found - Code cvtCode {operandToken->convertCode(expectedDataType)}; - if (operandToken->isType(Type::Constant) - && expectedDataType == DataType::Integer - && operandToken->isDataType(DataType::Double)) - { - operandToken->setDataType(DataType{}); // to report invalid integer - } - return cvtCode; // convert code or invalid + return operandToken->convertCode(expectedDataType); } @@ -1779,11 +1779,6 @@ void Table::setTokenCode(Token *token, Code code, DataType dataType) token->setDataType(dataType); } -void Table::setTokenCode(Token *token, Code baseCode) -{ - setTokenCode(token, baseCode, token->dataType()); -} - // function to set the code for of token for the specified operand // appropriate for the data type specified diff --git a/table.h b/table.h index 1da83fb..c1609b2 100644 --- a/table.h +++ b/table.h @@ -162,7 +162,6 @@ class Table bool setTokenCode(Token *token, Code code, DataType dataType, int operandIndex); void setTokenCode(Token *token, Code code, DataType dataType); - void setTokenCode(Token *token, Code baseCode); std::string name(const TokenPtr &token) const; // TABLE SPECIFIC FUNCTIONS diff --git a/token.cpp b/token.cpp index 18c0abb..609869a 100644 --- a/token.cpp +++ b/token.cpp @@ -91,10 +91,10 @@ Token::Token(DataType dataType, int column, int length, // constructor for string constants Token::Token(int column, int length, const std::string string) : - m_column{column}, m_length{length}, m_dataType{DataType::String}, - m_string{string}, m_code{Invalid_Code}, m_reference{}, m_subCode{} + m_column{column}, m_length{length}, m_string{string}, m_reference{}, + m_subCode{} { - Table::instance().setTokenCode(this, Const_Code); + Table::instance().setTokenCode(this, Const_Code, DataType::String); } @@ -130,8 +130,9 @@ std::string Token::stringWithDataType() const // function to change constant token to desired data type -// - resets integer constant sub-code for numeric desired data types +// - resets integer constant sub-code on double constants // - does nothing if constant is not changed +// - throws error if double cannot be converted to integer bool Token::convertConstant(DataType dataType) { if (!isType(Type::Constant)) @@ -149,77 +150,74 @@ bool Token::convertConstant(DataType dataType) { return false; } + // fall to below and change constant type to double } - else if (dataType == DataType::Integer && m_dataType == DataType::Double - && hasSubCode(IntConst_SubCode)) + else if (dataType == DataType::Integer) { - removeSubCode(IntConst_SubCode); + if (m_dataType == DataType::Double) + { + if (!hasSubCode(IntConst_SubCode)) + { + throw Status::ExpIntConst; + } + removeSubCode(IntConst_SubCode); + // fall to below and change constant type to integer + } + else + { + return m_dataType == DataType::Integer; + } } else { - return false; + return false; // can't convert to number or any } - m_dataType = dataType; - Table::instance().setTokenCode(this, Const_Code); + Table::instance().setTokenCode(this, Const_Code, dataType); return true; } // function to get convert code needed to convert token to data type // - changes number constant tokens to desired data type +// - returns conversion code if needed // - returns null code if no conversion needed -// - returns invalid code if cannot be converted -// - if cannot be converted then sets data type for error reporting +// - throws error status if cannot be converted Code Token::convertCode(DataType dataType) { - if (convertConstant(dataType)) - { - return Null_Code; - } - switch (dataType) + if (!convertConstant(dataType) && m_dataType != dataType) { - case DataType::Double: - if (m_dataType == DataType::Integer) + switch (dataType) { + case DataType::Double: + if (m_dataType != DataType::Integer) + { + throw Status::ExpNumExpr; + } return CvtDbl_Code; - } - else if (m_dataType == DataType::Double) - { - return Null_Code; - } - break; - case DataType::Integer: - if (m_dataType == DataType::Double) - { - return isType(Type::Constant) ? Invalid_Code : CvtInt_Code; - } - else if (m_dataType == DataType::Integer) - { - return Null_Code; - } - break; + case DataType::Integer: + if (m_dataType != DataType::Double) + { + throw Status::ExpNumExpr; + } + return CvtInt_Code; - case DataType::String: - if (m_dataType == DataType::String) - { - return Null_Code; - } - break; + case DataType::String: + throw Status::ExpStrExpr; - case DataType::Number: - if (m_dataType != DataType::String) - { - return Null_Code; - } - break; + case DataType::Number: + if (m_dataType == DataType::String) + { + throw Status::ExpNumExpr; + } + break; - case DataType::None: - case DataType::Any: - return Null_Code; + case DataType::None: + case DataType::Any: + break; + } } - m_dataType = dataType; - return Invalid_Code; + return Null_Code; } diff --git a/token.h b/token.h index 32eb422..d887e5c 100644 --- a/token.h +++ b/token.h @@ -110,6 +110,13 @@ class Token { return dataType == m_dataType; } + bool isDataTypeCompatible(DataType dataType) + { + // check if token data type is compatible with desired data type + return dataType == m_dataType + || (dataType == DataType::Number && m_dataType != DataType::String) + || dataType == DataType::Any || dataType == DataType::None; + } // string access function std::string string(void) const diff --git a/translator.cpp b/translator.cpp index 2dae696..846cec8 100644 --- a/translator.cpp +++ b/translator.cpp @@ -297,26 +297,19 @@ void Translator::getExpression(DataType dataType, int level) if (!processOperator()) { if (level == 0) + try { // add convert code if needed or report error TokenPtr doneToken {m_doneStack.top().rpnItem->token()}; - Code cvtCode {doneToken->convertCode(dataType)}; - if (cvtCode == Invalid_Code) - { - if (doneToken->isType(Type::Constant) - && dataType == DataType::Integer - && doneToken->isDataType(DataType::Double)) - { - // constant could not be converted - throw doneStackTopTokenError(Status::ExpIntConst); - } - throw doneStackTopTokenError(expectedErrorStatus(dataType)); - } - else if (cvtCode != Null_Code) + if (Code cvtCode = doneToken->convertCode(dataType)) { m_output.append(std::make_shared(cvtCode)); } } + catch (Status status) + { + throw doneStackTopTokenError(status); + } break; } @@ -423,8 +416,7 @@ bool Translator::getOperand(DataType dataType, Reference reference) } // for reference, check data type if (reference != Reference::None - && m_doneStack.top().rpnItem->token()->convertCode(dataType) - != Null_Code) + && !m_doneStack.top().rpnItem->token()->isDataTypeCompatible(dataType)) { throw doneStackTopTokenError(expectedErrorStatus(dataType, reference)); } @@ -845,16 +837,12 @@ void Translator::processDoneStackTop(TokenPtr &token, int operandIndex, { *last = localLast; } + m_doneStack.pop(); // remove from done stack // see if main code's data type matches - Code cvtCode {m_table.findCode(token, topToken, operandIndex)}; - - if (cvtCode != Invalid_Code) + try { - m_doneStack.pop(); // remove from done stack - - // is there an actual conversion code to insert? - if (cvtCode != Null_Code) + if (Code cvtCode = m_table.findCode(token, topToken, operandIndex)) { // INSERT CONVERSION CODE // create convert token with convert code @@ -862,15 +850,11 @@ void Translator::processDoneStackTop(TokenPtr &token, int operandIndex, m_output.append(std::make_shared(cvtCode)); } } - else // no match found, throw error + catch (Status status) { - // use main code's expected data type for operand - // (if no data type, then double constant can't be converted to integer) // report entire expression from first token through last - throw TokenError {topToken->isDataType(DataType{}) - ? Status::ExpIntConst : expectedErrorStatus(topToken->dataType()), - localFirst->column(), localLast->column() + localLast->length() - - localFirst->column()}; + throw TokenError {status, localFirst->column(), localLast->column() + + localLast->length() - localFirst->column()}; } }