Skip to content

Commit

Permalink
handle parser errors properly in new translator
Browse files Browse the repository at this point in the history
for parser errors, the get token function differentiates between
parser errors and number constant errors by considering if getting an
operand and the data type of the error token (set to none for parser
errors, or double for number constant errors)

the parser setOperandState() function was removed and the operand state
now passed in as an argument to the token() function

the loop in the get expression function was rearranged to remove
duplicated code before and at the end of the loop

added several parser error tests to expression test #1
  • Loading branch information
thunder422 committed Jul 2, 2013
1 parent a194cdb commit 348ec22
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 36 deletions.
3 changes: 2 additions & 1 deletion parser.cpp
Expand Up @@ -32,8 +32,9 @@
// - the token must be deallocated when it is no longer needed
// - the token may contain an error message if an error was found

Token *Parser::token(void)
Token *Parser::token(bool operandState)
{
m_operandState = operandState;
skipWhitespace();
m_token = new Token(m_pos); // allocate new token to return
if (m_input[m_pos].isNull())
Expand Down
6 changes: 1 addition & 5 deletions parser.h
Expand Up @@ -61,11 +61,7 @@ class Parser
m_pos = 0;
m_operandState = false;
}
Token *token(void);
void setOperandState(bool operandState)
{
m_operandState = operandState;
}
Token *token(bool operandState = false);
};


Expand Down
9 changes: 9 additions & 0 deletions test/expression1.dat
Expand Up @@ -48,3 +48,12 @@ a print
a a
a + else
a + +
# parser error tests
..
A ..
A + ..
A + B ..
%
A %
A$ + %
A + B %
24 changes: 24 additions & 0 deletions test/expression1.txt
Expand Up @@ -125,3 +125,27 @@ Input: a + else
Input: a + +
^-- expected numeric expression

Input: ..
^^-- expected digits or single decimal point in floating point constant

Input: A ..
^-- expected operator or end-of-statement

Input: A + ..
^^-- expected digits or single decimal point in floating point constant

Input: A + B ..
^-- expected operator or end-of-statement

Input: %
^-- expected expression

Input: A %
^-- expected operator or end-of-statement

Input: A$ + %
^-- expected string expression

Input: A + B %
^-- expected operator or end-of-statement

76 changes: 47 additions & 29 deletions translator.cpp
Expand Up @@ -103,10 +103,9 @@ RpnList *Translator::translate(const QString &input, bool exprMode)

do {
// set parser operand state from translator
m_parser->setOperandState(m_state == Operand_State
token = parsedToken = m_parser->token(m_state == Operand_State
|| m_state == OperandOrEnd_State
|| m_state == Initial_State && m_exprMode);
token = parsedToken = m_parser->token();
if (token->isType(Error_TokenType))
{
if (m_mode == Command_TokenMode)
Expand Down Expand Up @@ -1809,11 +1808,12 @@ RpnList *Translator::translate2(const QString &input, bool exprMode)
{
// error token is in the output list - don't delete it
m_output->setError(token);
m_output->setErrorMessage(status == Parser_TokenStatus
? token->string() : token->message(status));
if (token->isSubCode(UnUsed_SubCode))
{
delete token; // token not in output list, needs to be deleted
}
m_output->setErrorMessage(token->message(status));
cleanUp();
}
RpnList *output = m_output;
Expand All @@ -1824,55 +1824,59 @@ RpnList *Translator::translate2(const QString &input, bool exprMode)

// function to get an expression from the input line
//
// - takes an already obtained token (gets a token if none)
// - takes a data type argument for the desired data type of the expression
// - returns Done_TokenStatus upon success
// - returns an error status if an error was detected
// - returns the token that terminated the expression
// - will recursively call itself for processing sub-parts of the expression

TokenStatus Translator::getExpression(Token *&token, DataType dataType)
{
// get a token if no token was passed in
TokenStatus status;

if (token == NULL && (status = getToken(token, true)) != Good_TokenStatus)
{
return status;
}

forever
{
if (token == NULL
&& (status = getToken(token, dataType)) != Good_TokenStatus)
{
break;
}

Code unaryCode;
if (token->isOperator()
&& (unaryCode = m_table.unaryCode(token->code())) != Null_Code)
{
token->setCode(unaryCode); // change token to unary operator
}
// get operand and next token
else if ((status = getOperand(token, dataType)) != Good_TokenStatus
|| (status = getToken(token)) != Good_TokenStatus)
else if ((status = getOperand(token, dataType)) != Good_TokenStatus)
{
return status;
break;
}
else if ((status = getToken(token)) != Good_TokenStatus)
{
// if parser error then expected binary operator or end
// (this error needs to be changed appropriately by caller)
status = ExpOpOrEnd_TokenStatus;
break;
}

// check for and process operator (unary or binary)
if ((status = processOperator2(token)) == Done_TokenStatus)
{
// TODO check expression data type (level == 0 only?)
return status;
break;
}
else if (status != Good_TokenStatus)
{
return status;
break;
}

// get operator's expected data type and get next token
// get operator's expected data type, reset token and loop back
dataType = m_table.expectedDataType(token);
if ((status = getToken(token, true)) != Good_TokenStatus)
{
return status;
}
token = NULL;
}
return status;
}


Expand Down Expand Up @@ -1950,7 +1954,7 @@ TokenStatus Translator::getOperand(Token *&token, DataType dataType)

if (token == NULL)
{
status = getToken(token, true); // get a token if none was passed in
status = getToken(token, dataType); // get token if none was passed
if (status != Good_TokenStatus)
{
return status;
Expand Down Expand Up @@ -1989,19 +1993,33 @@ TokenStatus Translator::getOperand(Token *&token, DataType dataType)

// function to get a token from the parser
//
// - data type argument determines if token to get is an operand
// - returns Parser_TokenStatus if the parser returned an error

TokenStatus Translator::getToken(Token *&token, bool operand)
TokenStatus Translator::getToken(Token *&token, DataType dataType)
{
// set parser operand state from translator
m_parser->setOperandState(operand);
token = m_parser->token();
// if data type is not none, then getting an operand token
bool operand = dataType != None_DataType;
token = m_parser->token(operand);
if (token->isType(Error_TokenType))
{
// TODO only do this for non-number errors
token->setLength(1); // just point to first character
// TODO how to differentiate between parser errors and number errors?
return Parser_TokenStatus;
token->setSubCodeMask(UnUsed_SubCode);

if (!operand && token->dataType() == Double_DataType)
{
// only do this for non-operand number constant errors
token->setLength(1); // just point to first character
}
if (operand && token->dataType() != Double_DataType)
{
// non-number constant error, return expected expression error
return expectedErrStatus(dataType);
}
else
{
// caller needs to convert this error to the appropriate error
return Parser_TokenStatus;
}
}
return Good_TokenStatus;
}
Expand Down
2 changes: 1 addition & 1 deletion translator.h
Expand Up @@ -157,7 +157,7 @@ class Translator
TokenStatus getExpression(Token *&token, DataType dataType);
TokenStatus processOperator2(Token *&token);
TokenStatus getOperand(Token *&token, DataType dataType);
TokenStatus getToken(Token *&token, bool operand = false);
TokenStatus getToken(Token *&token, DataType dataType = None_DataType);

// Main Processing Functions
TokenStatus addToken(Token *&token);
Expand Down

0 comments on commit 348ec22

Please sign in to comment.