HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Monster token parser function

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
monstertokenparserfunction

Problem

This function will read an expression (made up of tokens) from the vector of tokens passed into it. It will remove the tokens that make up the expression from the vector and return them.

A token is added to the expression if

  • it is the first token



  • it has an operator before it



Brackets are handled in parseBracketTokens (which calls this function)

```
RawExpression *parseExpressionTokens(
vector &tokens, bool brackets = false) {

// This is a vector of elements that make up an expression
vector elements;

while(tokens.size() > 0) {

// Operands must be at the start of an expression or after an operator
if(tokenIsOperand(tokens[0])) {

if(elements.size() == 0 ||
eElementIsRelationalOperator(elements.back())) {
elements.push_back(makeEElementFromToken(tokens[0]));
removeToken(tokens, 0);
continue;
}

// This token is part of the next expression, break from the loop
break;
}

if(tokenIsRelationalOperator(tokens[0])) {

// Make sure we have an operand left of it

if(tokens[0]->type == TOKEN_MINUS) {
if(elements.size() == 0 ||
!eElementIsOperand(elements.back())) {

// handle the minus number or symbol :O

}
}

if(elements.size() != 0 &&
eElementIsOperand(elements.back())) {
elements.push_back(makeEElementFromToken(tokens[0]));
removeToken(tokens, 0);
continue;
}

throw(string("Operator has bad lhand:") + tokenToString(tokens[0]));
}

// A closing bracket marks the end of an expression

if(tokens[0]->type == TOKEN_CLOSEBRACKET) {
if(!brackets)
throw(string("Unmatched closing bracket"));

break;
}

Solution

My first thought is that parsers should be implemented as table driven state machines for exactly the reason you see in the code :-)

Actually, I think breaking this into a set of separate functions is one good approach, and adding a new enum to support it makes it very clear the state of the expression after each step.

Another option I would consider is determining the paths through the code and possibly doing some optimizations around them at the expense of clarity. There appear to be several places where once you first entered a conditional block, you have committed to not doing any other code in the loop. Re-arranging these may eliminate some of the separate continue/break statements and allow easier refactoring.

Context

StackExchange Code Review Q#1564, answer score: 8

Revisions (0)

No revisions yet.