Skip to content

Commit

Permalink
parser: changed get number to create new token
Browse files Browse the repository at this point in the history
modified get number function to create new token and return a token
pointer (shared pointer) only when a valid token is found else a default
token pointer is returned; parts of handling creation of double constant
token moved to new token double constant constructor

changed call to get number function in function operator function
added integer and double constant token constructors
put double constructor in source using standard numerical limits
removed get command function definition (function was deleted long ago)
  • Loading branch information
thunder422 committed Oct 28, 2014
1 parent e34fbcc commit d328c0a
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 43 deletions.
64 changes: 23 additions & 41 deletions parser.cpp
Expand Up @@ -52,9 +52,15 @@ TokenPtr Parser::operator()(Number number)
{
return token;
}
if (number == Number::Yes)
{
if (TokenPtr token = getNumber())
{
return token;
}
}
m_token = std::make_shared<Token>(m_pos); // create new token to return
if ((number == Number::No || !getNumber())
&& !getString() && !getOperator())
if (!getString() && !getOperator())
{
// not a valid token, create error token
throw Error {Status::UnknownToken, m_pos, 1};
Expand Down Expand Up @@ -226,13 +232,13 @@ void Parser::skipWhitespace(void)
// double.
//
// - numbers starting with zero must be followed by a decimal point
// - returns false if no number (position not changed)
// - returns true if there is and token is filled
// - returns true for errors and special error token is set
// - returns default token pointer if no number (position not changed)
// - returns token if there is a valid number
// - throws an expection for errors
// - string of the number is converted to a value
// - string of the number is saved so it can be later reproduced

bool Parser::getNumber(void)
TokenPtr Parser::getNumber()
{
bool digits {}; // digits were found flag
bool decimal {}; // decimal point was found flag
Expand Down Expand Up @@ -287,7 +293,7 @@ bool Parser::getNumber(void)
{
// if there is a '-E' then not a number
// (need to interprete '-' as unary operator)
return false;
return TokenPtr{};
}
// if there were no digits before 'E' then error
// (only would happen if mantissa contains only '.')
Expand Down Expand Up @@ -324,7 +330,7 @@ bool Parser::getNumber(void)
}
else
{
return false; // not a numeric constant
return TokenPtr{}; // not a numeric constant
}
}
else if (!digits) // only a decimal point found?
Expand All @@ -343,56 +349,32 @@ bool Parser::getNumber(void)
int len {pos - m_pos};
QString numStr {m_input.mid(m_pos, len)};

// save string of number so it later can be reproduced
m_token->setString(numStr);
m_token->setLength(len);

m_token->setType(Token::Type::Constant);

// FIXME hack for memory issue reported against QString::toInt()/toDouble()
QByteArray numBytes;
numBytes.append(numStr);
if (!decimal) // no decimal or exponent?
{
// try to convert to integer first
m_token->setValue(numBytes.toInt(&ok));
int value {numBytes.toInt(&ok)};
if (ok)
{
m_token->setDataType(DataType::Integer);
// convert to double in case double is needed
m_token->setValue((double)m_token->valueInt());
m_pos = pos; // move to next character after constant
return true;
std::swap(m_pos, pos); // swap begin and end positions
// save string of number so it later can be reproduced
return std::make_shared<Token>(pos, len, numStr, value);
}
// else overflow or underflow, won't fit into an integer
// fall thru and try as double
}
m_token->setValue(numBytes.toDouble(&ok));

double value {numBytes.toDouble(&ok)};
if (!ok)
{
// overflow or underflow, constant is not valid
throw Error {Status::FPOutOfRange, m_pos, len};
}
m_pos = pos; // move to next character after constant

// if double in range of integer, then set as integer
if (m_token->value() > (double)INT_MIN - 0.5
&& m_token->value() < (double)INT_MAX + 0.5)
{
m_token->setDataType(DataType::Integer);
// convert to integer in case integer is needed
m_token->setValue((int)m_token->value());
if (decimal) // decimal point or exponent?
{
// indicate number is a double value
m_token->addSubCode(Double_SubCode);
}
}
else // number can't be converted to integer
{
m_token->setDataType(DataType::Double);
}
return true;
std::swap(m_pos, pos); // swap begin and end positions
// save string of number so it later can be reproduced
return std::make_shared<Token>(pos, len, numStr, value, decimal);
}


Expand Down
3 changes: 1 addition & 2 deletions parser.h
Expand Up @@ -45,9 +45,8 @@ class Parser

private:
// main functions
bool getCommand(void);
TokenPtr getIdentifier();
bool getNumber(void);
TokenPtr getNumber();
bool getString(void);
bool getOperator(void);

Expand Down
24 changes: 24 additions & 0 deletions token.cpp
Expand Up @@ -22,6 +22,8 @@
//
// 2012-11-03 initial version (parts removed from ibcp.cpp)

#include <limits>

#include "token.h"


Expand All @@ -46,6 +48,28 @@ std::unordered_map<Token::Type, int, EnumClassHash> Token::s_precendence {
};


// constructor to set double constants
Token::Token(int column, int length, QString string, double value,
bool decimal) : m_column{column}, m_length{length},
m_type{Token::Type::Constant}, m_string{string}, m_code{Invalid_Code},
m_reference{}, m_value{value}
{
if (value > std::numeric_limits<int>::min() - 0.5
&& value < std::numeric_limits<int>::max() + 0.5)
{
m_dataType = DataType::Integer;
// 'double' if decimal pointer present
m_subCode = decimal ? Double_SubCode : None_SubCode;
m_valueInt = value; // convert to integer in case needed
}
else // number can't be converted to integer
{
m_dataType = DataType::Double;
m_subCode = None_SubCode; // ignore sub-code argument
}
}


// function to set the default data type of the token
void Token::setDataType(void)
{
Expand Down
14 changes: 14 additions & 0 deletions token.h
Expand Up @@ -60,17 +60,31 @@ class Token
m_length{length}, m_type{}, m_code{Invalid_Code}, m_reference{},
m_subCode{None_SubCode} {}

// constructor for codes
Token(int column, int length, Type type, DataType dataType, Code code,
QString string = {}) : m_column{column}, m_length{length}, m_type{type},
m_dataType{dataType}, m_string{string}, m_code{code}, m_reference{},
m_subCode{None_SubCode} {}

// constructor for identifiers
Token(int column, int length, Type type, DataType dataType,
const QString &inputString) : m_column{column}, m_length{length},
m_type{type}, m_dataType{dataType}, m_string{inputString.mid(column,
length)}, m_code{Invalid_Code}, m_reference{}, m_subCode{None_SubCode}
{}

// constructor for integer constants
Token(int column, int length, QString string, int value) : m_column{column},
m_length{length}, m_type{Token::Type::Constant},
m_dataType{DataType::Integer}, m_string{string}, m_code{Invalid_Code},
m_reference{}, m_subCode{None_SubCode}, m_valueInt{value}
{
m_value = value; // convert to double in case needed
}

// constructor for double constants
Token(int column, int length, QString string, double value, bool decimal);

Token(const Token &token) // copy constructor
{
*this = token;
Expand Down

0 comments on commit d328c0a

Please sign in to comment.