ast::Expr *parseBinOpRHS(int exprPrecendence, ast::Expr *lhs, TokenIt &it, const TokenIt &end) { while(1) { Token *current = currentToken(it, end); char binOp = current ? current->value.c_str()[0] : 0; int precendence = opPrecedence(binOp); if(precendence < exprPrecendence) return lhs; nextToken(it, end); ast::Expr *rhs = parsePrimary(it, end); if(!rhs) return NULL; current = currentToken(it, end); int nextPrecedence = opPrecedence(current ? current->value.c_str()[0] : 0); if(precendence < nextPrecedence) { rhs = parseBinOpRHS(precendence + 1, rhs, it, end); if(!rhs) return NULL; } lhs = new ast::BinaryExpr(binOp, lhs, rhs); } }
void calculator::compile(const char* expr, TokenMap vars, const char* delim, const char** rest) { // Make sure it is empty: rpnBuilder::cleanRPN(&this->RPN); this->RPN = calculator::toRPN(expr, vars, delim, rest, opPrecedence(), rWordMap()); }
/* ** Argument ppHead contains a pointer to the current head of a query ** expression tree being parsed. pPrev is the expression node most recently ** inserted into the tree. This function adds pNew, which is always a binary ** operator node, into the expression tree based on the relative precedence ** of pNew and the existing nodes of the tree. This may result in the head ** of the tree changing, in which case *ppHead is set to the new root node. */ static void insertBinaryOperator( Fts3Expr **ppHead, /* Pointer to the root node of a tree */ Fts3Expr *pPrev, /* Node most recently inserted into the tree */ Fts3Expr *pNew /* New binary node to insert into expression tree */ ){ Fts3Expr *pSplit = pPrev; while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){ pSplit = pSplit->pParent; } if( pSplit->pParent ){ assert( pSplit->pParent->pRight==pSplit ); pSplit->pParent->pRight = pNew; pNew->pParent = pSplit->pParent; }else{ *ppHead = pNew; } pNew->pLeft = pSplit; pSplit->pParent = pNew; }
bool KoEnhancedPathFormula::compile( const TokenList & tokens ) { // sanity check if( tokens.count() == 0 ) return false; FormulaTokenStack syntaxStack; QStack<int> argStack; unsigned argCount = 1; for( int i = 0; i <= tokens.count(); i++ ) { // helper token: InvalidOp is end-of-formula FormulaToken token = ( i < tokens.count() ) ? tokens[i] : FormulaToken( FormulaToken::TypeOperator ); FormulaToken::Type tokenType = token.type(); // unknown token is invalid if( tokenType == FormulaToken::TypeUnknown ) break; // for constants, push immediately to stack // generate code to load from a constant if( tokenType == FormulaToken::TypeNumber ) { syntaxStack.push( token ); m_constants.append( QVariant( token.asNumber() ) ); m_codes.append( Opcode( Opcode::Load, m_constants.count()-1 ) ); } // for identifier, push immediately to stack // generate code to load from reference if( tokenType == FormulaToken::TypeFunction || tokenType == FormulaToken::TypeReference ) { syntaxStack.push( token ); m_constants.append( QVariant( token.text() ) ); m_codes.append( Opcode( Opcode::Ref, m_constants.count()-1 ) ); } // are we entering a function ? // if token is operator, and stack already has: id ( arg if( tokenType == FormulaToken::TypeOperator && syntaxStack.itemCount() >= 3 ) { FormulaToken arg = syntaxStack.top(); FormulaToken par = syntaxStack.top( 1 ); FormulaToken id = syntaxStack.top( 2 ); if( !arg.isOperator() && par.asOperator() == FormulaToken::OperatorLeftPar && id.isFunction() ) { argStack.push( argCount ); argCount = 1; } } // for any other operator, try to apply all parsing rules if( tokenType == FormulaToken::TypeOperator ) { // repeat until no more rule applies for( ; ; ) { bool ruleFound = false; // rule for function arguments, if token is , or ) // id ( arg1 , arg2 -> id ( arg if( !ruleFound ) if( syntaxStack.itemCount() >= 5 ) if( ( token.asOperator() == FormulaToken::OperatorRightPar ) || ( token.asOperator() == FormulaToken::OperatorComma ) ) { FormulaToken arg2 = syntaxStack.top(); FormulaToken sep = syntaxStack.top( 1 ); FormulaToken arg1 = syntaxStack.top( 2 ); FormulaToken par = syntaxStack.top( 3 ); FormulaToken id = syntaxStack.top( 4 ); if( !arg2.isOperator() ) if( sep.asOperator() == FormulaToken::OperatorComma ) if( !arg1.isOperator() ) if( par.asOperator() == FormulaToken::OperatorLeftPar ) if( id.isFunction() ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); argCount++; } } // rule for function last argument: // id ( arg ) -> arg if( !ruleFound ) if( syntaxStack.itemCount() >= 4 ) { FormulaToken par2 = syntaxStack.top(); FormulaToken arg = syntaxStack.top( 1 ); FormulaToken par1 = syntaxStack.top( 2 ); FormulaToken id = syntaxStack.top( 3 ); if( par2.asOperator() == FormulaToken::OperatorRightPar ) if( !arg.isOperator() ) if( par1.asOperator() == FormulaToken::OperatorLeftPar ) if( id.isFunction() ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); syntaxStack.pop(); syntaxStack.pop(); syntaxStack.push( arg ); m_codes.append( Opcode( Opcode::Function, argCount ) ); argCount = argStack.empty() ? 0 : argStack.pop(); } } // rule for parenthesis: ( Y ) -> Y if( !ruleFound ) if( syntaxStack.itemCount() >= 3 ) { FormulaToken right = syntaxStack.top(); FormulaToken y = syntaxStack.top( 1 ); FormulaToken left = syntaxStack.top( 2 ); if( right.isOperator() ) if( !y.isOperator() ) if( left.isOperator() ) if( right.asOperator() == FormulaToken::OperatorRightPar ) if( left.asOperator() == FormulaToken::OperatorLeftPar ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); syntaxStack.pop(); syntaxStack.push( y ); } } // rule for binary operator: A (op) B -> A // conditions: precedence of op >= precedence of token // action: push (op) to result // e.g. "A * B" becomes 'A' if token is operator '+' if( !ruleFound ) if( syntaxStack.itemCount() >= 3 ) { FormulaToken b = syntaxStack.top(); FormulaToken op = syntaxStack.top( 1 ); FormulaToken a = syntaxStack.top( 2 ); if( !a.isOperator() ) if( !b.isOperator() ) if( op.isOperator() ) if( token.asOperator() != FormulaToken::OperatorLeftPar ) if( opPrecedence( op.asOperator() ) >= opPrecedence( token.asOperator() ) ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); syntaxStack.pop(); syntaxStack.push( b ); switch( op.asOperator() ) { // simple binary operations case FormulaToken::OperatorAdd: m_codes.append( Opcode::Add ); break; case FormulaToken::OperatorSub: m_codes.append( Opcode::Sub ); break; case FormulaToken::OperatorMul: m_codes.append( Opcode::Mul ); break; case FormulaToken::OperatorDiv: m_codes.append( Opcode::Div ); break; default: break; }; } } // rule for unary operator: (op1) (op2) X -> (op1) X // conditions: op2 is unary, token is not '(' // action: push (op2) to result // e.g. "* - 2" becomes '*' if( !ruleFound ) if( token.asOperator() != FormulaToken::OperatorLeftPar ) if( syntaxStack.itemCount() >= 3 ) { FormulaToken x = syntaxStack.top(); FormulaToken op2 = syntaxStack.top( 1 ); FormulaToken op1 = syntaxStack.top( 2 ); if( !x.isOperator() ) if( op1.isOperator() ) if( op2.isOperator() ) if( ( op2.asOperator() == FormulaToken::OperatorAdd ) || ( op2.asOperator() == FormulaToken::OperatorSub ) ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); syntaxStack.push( x ); if( op2.asOperator() == FormulaToken::OperatorSub ) m_codes.append( Opcode( Opcode::Neg ) ); } } // auxiliary rule for unary operator: (op) X -> X // conditions: op is unary, op is first in syntax stack, token is not '(' // action: push (op) to result if( !ruleFound ) if( token.asOperator() != FormulaToken::OperatorLeftPar ) if( syntaxStack.itemCount() == 2 ) { FormulaToken x = syntaxStack.top(); FormulaToken op = syntaxStack.top( 1 ); if( !x.isOperator() ) if( op.isOperator() ) if( ( op.asOperator() == FormulaToken::OperatorAdd ) || ( op.asOperator() == FormulaToken::OperatorSub ) ) { ruleFound = true; syntaxStack.pop(); syntaxStack.pop(); syntaxStack.push( x ); if( op.asOperator() == FormulaToken::OperatorSub ) m_codes.append( Opcode( Opcode::Neg ) ); } } if( !ruleFound ) break; } syntaxStack.push( token ); } } // syntaxStack must left only one operand and end-of-formula (i.e. InvalidOp) m_valid = false; if( syntaxStack.itemCount() == 2 ) if( syntaxStack.top().isOperator() ) if( syntaxStack.top().asOperator() == FormulaToken::OperatorInvalid ) if( !syntaxStack.top(1).isOperator() ) m_valid = true; // bad parsing ? clean-up everything if( ! m_valid ) { m_constants.clear(); m_codes.clear(); kWarning() << "compiling of "<< m_text << " failed"; } return m_valid; }