void tree_display (NODE *node) { if (node->type == N_OP) { if (node->left) { if (PRECEDENCE(node, node->left)) { printf("("); } tree_display(node->left); if (PRECEDENCE(node, node->left)) { printf(")"); } printf(" %c ", node->val.ch); } else { printf("%c", node->val.ch); } if (PRECEDENCE(node, node->right)) { printf("("); } tree_display(node->right); if (PRECEDENCE(node, node->right)) { printf(")"); } } else { printf("%s", node->val.name); } }
const char * tree_string (NODE *node, int init) { static char buf[1024]; static int len; if (init) { len = 0; } if (node->type == N_OP) { if (node->left) { if (PRECEDENCE(node, node->left)) { len += sprintf(&buf[len], "("); } tree_string(node->left, 0); if (PRECEDENCE(node, node->left)) { len += sprintf(&buf[len], ")"); } len += sprintf(&buf[len], " %c ", node->val.ch); } else { len += sprintf(&buf[len], "%c", node->val.ch); } if (PRECEDENCE(node, node->right)) { len += sprintf(&buf[len], "("); } tree_string(node->right, 0); if (PRECEDENCE(node, node->right)) { len += sprintf(&buf[len], ")"); } } else { len += sprintf(&buf[len], "%s", node->val.name); } return buf; }
static expr *parse_rhs(expr *lhs, int priority) { for(;;){ int this_pri, next_pri; e_op op; expr *rhs; op = tok_cur; if(!is_op(op)) return lhs; /* eof, rparen and colon covered here */ this_pri = PRECEDENCE(op); if(this_pri > priority) return lhs; /* eat the op */ tok_next(); /* special case for ternary */ if(op == tok_question){ expr *if_t = parse(); if(tok_cur != tok_colon) CPP_DIE("colon expected for ternary-? operator"); tok_next(); rhs = parse(); lhs = expr_new_top(lhs, if_t, rhs); }else{ rhs = parse_primary(); /* now on the next op, or eof (in which case, precedence returns -1 */ next_pri = PRECEDENCE(tok_cur); if(next_pri < this_pri) { /* next is tighter, give it our rhs as its lhs */ rhs = parse_rhs(rhs, next_pri); } lhs = expr_op(op, lhs, rhs); } } }
/**************************************************************************** Desc : Adds an operator to the selection criteria of a given cursor. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddOp( HFCURSOR hCursor, QTYPES eOperator, FLMBOOL bResolveUnknown ) { RCODE rc = FERR_OK; CURSOR * pCursor = (CURSOR *)hCursor; FQNODE * pTmpQNode; FQNODE * pTmpGraftNode; FQNODE * pTmpChildNode; FLMBOOL bDecrementNestLvl = FALSE; FLMUINT uiFlags = bResolveUnknown ? FLM_RESOLVE_UNK : 0; if (!pCursor) { flmAssert( 0); rc = RC_SET( FERR_INVALID_PARM); goto Exit; } if (RC_BAD( rc = pCursor->rc)) { goto Exit; } // If a read operation has already been performed on this query, no // selection criteria may be added. if (pCursor->bOptimized) { rc = RC_SET( FERR_ILLEGAL_OP); goto Exit; } // If the operator is a left paren, link it as the last sibling in the // argument list of the current operator. if (eOperator == FLM_LPAREN_OP) { (pCursor->QTInfo.uiNestLvl)++; goto Exit; } // If it is a right paren, find the left paren and close it out if (eOperator == FLM_RPAREN_OP) { if (!pCursor->QTInfo.uiNestLvl) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } (pCursor->QTInfo.uiNestLvl)--; goto Exit; } // If it is not an operator, return an error if (!IS_OP( eOperator)) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } // If an operator is not expected, bail out if (!(pCursor->QTInfo.uiExpecting & FLM_Q_OPERATOR) && eOperator != FLM_NEG_OP && eOperator != FLM_NOT_OP) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } // Make a QNODE and find a place for it in the query tree if (RC_BAD( rc = flmCurMakeQNode( &pCursor->QueryPool, eOperator, NULL, 0, uiFlags, &pTmpQNode))) { goto Exit; } pTmpQNode->uiNestLvl = pCursor->QTInfo.uiNestLvl; // If this is the first operator in the query, set the current operator // to it and graft in the current operand as its child. NOTE: there // should always be a current operand at this point. if (!pCursor->QTInfo.pTopNode) { pCursor->QTInfo.pTopNode = pTmpQNode; pCursor->QTInfo.pCurOpNode = pTmpQNode; if (pCursor->QTInfo.pCurAtomNode) { // If the current operand node is a user predicate, the only // thing that can become its parent is a logical operator. if (GET_QNODE_TYPE( pCursor->QTInfo.pCurAtomNode) == FLM_USER_PREDICATE && !IS_LOG_OP( eOperator)) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } flmCurLinkLastChild( pTmpQNode, pCursor->QTInfo.pCurAtomNode); } pCursor->QTInfo.uiExpecting = FLM_Q_OPERAND; goto Exit; } // Go up the stack until an operator whose nest level or precedence is < // this one's is encountered, then link this one in as the last child for (pTmpChildNode = NULL, pTmpGraftNode = pCursor->QTInfo.pCurOpNode; ; pTmpChildNode = pTmpGraftNode, pTmpGraftNode = pTmpGraftNode->pParent) { if (pTmpGraftNode->uiNestLvl < pTmpQNode->uiNestLvl || (pTmpGraftNode->uiNestLvl == pTmpQNode->uiNestLvl && PRECEDENCE( pTmpGraftNode->eOpType) < PRECEDENCE( eOperator))) { // If the node under which this operator is to be grafted already // has two children, or if its child is at a greater nesting level, // link the child as the last child of this operator. Example: // ((A - B) == C) && (((D + E) * F) == G). // When the '*' operator in this expression is added, it will be // grafted as the last child of the '&&' operator. But the '+' // must first be unlinked from the '&&' and then linked as the child // of the '*'. Otherwise, they will be siblings, and the expression // will be evaluated incorrectly. if (pTmpChildNode && (pTmpChildNode->uiNestLvl > pTmpQNode->uiNestLvl || pTmpChildNode->pPrevSib != NULL || pTmpGraftNode->eOpType == FLM_NEG_OP || pTmpGraftNode->eOpType == FLM_NOT_OP)) { flmCurLinkLastChild( pTmpQNode, pTmpChildNode); } // If this operator is to be grafted into the query tree at the leaf // level, link the current operand as its last child. Examples: // in A * (B + C), we want B to be linked to +; // in A + B * C, we want B linked to *. if (pTmpGraftNode == pCursor->QTInfo.pCurOpNode && eOperator != FLM_NEG_OP && eOperator != FLM_NOT_OP) { // If the current operand node is a user predicate, the only // thing that can become its parent is a logical operator. if (pCursor->QTInfo.pCurAtomNode && GET_QNODE_TYPE( pCursor->QTInfo.pCurAtomNode) == FLM_USER_PREDICATE && !IS_LOG_OP( eOperator)) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } flmCurLinkLastChild( pTmpQNode, pCursor->QTInfo.pCurAtomNode); } flmCurLinkLastChild( pTmpGraftNode, pTmpQNode); break; } if (!pTmpGraftNode->pParent) { pCursor->QTInfo.pTopNode = pTmpQNode; flmCurLinkLastChild( pTmpQNode, pTmpGraftNode); break; } } pCursor->QTInfo.pCurOpNode = pTmpQNode; pCursor->QTInfo.uiExpecting = FLM_Q_OPERAND; Exit: if (bDecrementNestLvl) { (pCursor->QTInfo.uiNestLvl)--; } if (pCursor) { pCursor->rc = rc; } return( rc); }