Example #1
0
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);
  }
}
Example #2
0
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());
}
Example #3
0
/*
** 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;
}
Example #4
0
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;
}