/// <devdoc> /// Builds expression tree for higher-precedence operator to be used as left /// operand of current operator. May cause errors - always do ErrorCheck() upin return. /// </devdoc> private void BuildExpression(int pri) { ExpressionNode expr = null; Debug.Assert(pri > Operators.priStart && pri <= Operators.priMax, "Invalid priority value"); /* For all operators of higher or same precedence (we are always left-associative) */ while (true) { Debug.Assert(topOperator > 0, "Empty operator stack!!"); OperatorInfo opInfo = ops[topOperator - 1]; if (opInfo.priority < pri) goto end_loop; Debug.Assert(opInfo.priority >= pri, "Invalid prioriry value"); topOperator--; ExpressionNode nodeLeft; ExpressionNode nodeRight; switch (opInfo.type) { case Nodes.Binop: { // get right, left operands. Bind them. nodeRight = NodePop(); nodeLeft = NodePop(); /* This is the place to do type and other checks */ switch (opInfo.op) { case Operators.Between: case Operators.BetweenAnd: case Operators.BitwiseAnd: case Operators.BitwiseOr: case Operators.BitwiseXor: case Operators.BitwiseNot: throw ExprException.UnsupportedOperator(opInfo.op); case Operators.Is: // case Operators.Or: case Operators.And: case Operators.EqualTo: case Operators.NotEqual: case Operators.Like: case Operators.LessThen: case Operators.LessOrEqual: case Operators.GreaterThen: case Operators.GreaterOrEqual: case Operators.In: break; default: Debug.Assert(opInfo.op == Operators.Plus || opInfo.op == Operators.Minus || opInfo.op == Operators.Multiply || opInfo.op == Operators.Divide || opInfo.op == Operators.Modulo, "Invalud Binary operation"); break; } Debug.Assert(nodeLeft != null, "Invalid left operand"); Debug.Assert(nodeRight != null, "Invalid right operand"); if (opInfo.op == Operators.Like) { expr = new LikeNode(_table, opInfo.op, nodeLeft, nodeRight); } else { expr = new BinaryNode(_table, opInfo.op, nodeLeft, nodeRight); } break; } case Nodes.Unop: /* Unary operator: Pop and bind right op. */ nodeLeft = null; nodeRight = NodePop(); /* Check for special cases */ switch (opInfo.op) { case Operators.Not: break; case Operators.BitwiseNot: throw ExprException.UnsupportedOperator(opInfo.op); case Operators.Negative: break; } Debug.Assert(nodeLeft == null, "Invalid left operand"); Debug.Assert(nodeRight != null, "Invalid right operand"); expr = new UnaryNode(_table, opInfo.op, nodeRight); break; case Nodes.Zop: /* Intrinsic constant: just create node. */ expr = new ZeroOpNode(opInfo.op); break; default: Debug.Assert(false, "Unhandled operator type"); goto end_loop; } Debug.Assert(expr != null, "Failed to create expression"); NodePush(expr); // countinue while loop; } end_loop: ; }
// Gathers all linear expressions in to this.linearExpression and all binary expressions in to their respective candidate columns expressions private void AnalyzeExpression(BinaryNode expr) { if (_linearExpression == _expression) { return; } if (expr._op == Operators.Or) { _linearExpression = _expression; return; } else if (expr._op == Operators.And) { bool isLeft = false, isRight = false; if (expr._left is BinaryNode) { AnalyzeExpression((BinaryNode)expr._left); if (_linearExpression == _expression) { return; } isLeft = true; } else { UnaryNode unaryNode = expr._left as UnaryNode; if (unaryNode != null) { while (unaryNode._op == Operators.Noop && unaryNode._right is UnaryNode && ((UnaryNode)unaryNode._right)._op == Operators.Noop) { unaryNode = (UnaryNode)unaryNode._right; } if (unaryNode._op == Operators.Noop && unaryNode._right is BinaryNode) { AnalyzeExpression((BinaryNode)(unaryNode._right)); if (_linearExpression == _expression) { return; } isLeft = true; } } } if (expr._right is BinaryNode) { AnalyzeExpression((BinaryNode)expr._right); if (_linearExpression == _expression) { return; } isRight = true; } else { UnaryNode unaryNode = expr._right as UnaryNode; if (unaryNode != null) { while (unaryNode._op == Operators.Noop && unaryNode._right is UnaryNode && ((UnaryNode)unaryNode._right)._op == Operators.Noop) { unaryNode = (UnaryNode)unaryNode._right; } if (unaryNode._op == Operators.Noop && unaryNode._right is BinaryNode) { AnalyzeExpression((BinaryNode)(unaryNode._right)); if (_linearExpression == _expression) { return; } isRight = true; } } } if (isLeft && isRight) { return; } ExpressionNode e = isLeft ? expr._right : expr._left; _linearExpression = (_linearExpression == null ? e : new BinaryNode(_table, Operators.And, e, _linearExpression)); return; } else if (IsSupportedOperator(expr._op)) { if (expr._left is NameNode && expr._right is ConstNode) { ColumnInfo canColumn = _candidateColumns[((NameNode)(expr._left))._column.Ordinal]; canColumn.expr = (canColumn.expr == null ? expr : new BinaryNode(_table, Operators.And, expr, canColumn.expr)); if (expr._op == Operators.EqualTo) { canColumn.equalsOperator = true; } _candidatesForBinarySearch = true; return; } else if (expr._right is NameNode && expr._left is ConstNode) { ExpressionNode temp = expr._left; expr._left = expr._right; expr._right = temp; switch (expr._op) { case Operators.GreaterThen: expr._op = Operators.LessThen; break; case Operators.LessThen: expr._op = Operators.GreaterThen; break; case Operators.GreaterOrEqual: expr._op = Operators.LessOrEqual; break; case Operators.LessOrEqual: expr._op = Operators.GreaterOrEqual; break; default: break; } ColumnInfo canColumn = _candidateColumns[((NameNode)(expr._left))._column.Ordinal]; canColumn.expr = (canColumn.expr == null ? expr : new BinaryNode(_table, Operators.And, expr, canColumn.expr)); if (expr._op == Operators.EqualTo) { canColumn.equalsOperator = true; } _candidatesForBinarySearch = true; return; } } _linearExpression = (_linearExpression == null ? expr : new BinaryNode(_table, Operators.And, expr, _linearExpression)); return; }
// internal ExpressionNode Parse() { // free all nodes expression = null; StartScan(); int cParens = 0; OperatorInfo opInfo; while (token != Tokens.EOS) { loop: Scan(); switch (token) { case Tokens.EOS: // End of string: must be operand; force out expression; // check for bomb; check nothing left on stack. if (prevOperand == Empty) { if (topNode == 0) { // we have an empty expression break; } // set error missing operator // read the last operator info opInfo = ops[topOperator - 1]; throw ExprException.MissingOperand(opInfo); } // collect all nodes BuildExpression(Operators.priLow); if (topOperator != 1) { throw ExprException.MissingRightParen(); } break; case Tokens.Name: case Tokens.Parent: case Tokens.Numeric: case Tokens.Decimal: case Tokens.Float: case Tokens.StringConst: case Tokens.Date: ExpressionNode node = null; string str = null; /* Constants and identifiers: create leaf node */ if (prevOperand != Empty) { // set error missing operator throw ExprException.MissingOperator(new string(text, start, pos - start)); } if (topOperator > 0) { // special check for IN without parentheses opInfo = ops[topOperator-1]; if (opInfo.type == Nodes.Binop && opInfo.op == Operators.In && token != Tokens.Parent) { throw ExprException.InWithoutParentheses(); } } prevOperand = Scalar; switch (token) { case Tokens.Parent: string relname; string colname; // parsing Parent[(relation_name)].column_name) try { // expecting an '(' or '.' Scan(); if (token == Tokens.LeftParen) { //read the relation name ScanToken(Tokens.Name); relname = NameNode.ParseName(text, start, pos); ScanToken(Tokens.RightParen); ScanToken(Tokens.Dot); } else { relname = null; CheckToken(Tokens.Dot); } } catch (Exception e){ // if (!Common.ADP.IsCatchableExceptionType(e)) { throw; } throw ExprException.LookupArgument(); } ScanToken(Tokens.Name); colname = NameNode.ParseName(text, start, pos); opInfo = ops[topOperator - 1]; node = new LookupNode(_table, colname, relname); break; case Tokens.Name: /* Qualify name now for nice error checking */ opInfo = ops[topOperator - 1]; /* Create tree element - */ // node = new NameNode(_table, text, start, pos); break; case Tokens.Numeric: str = new string(text, start, pos - start); node = new ConstNode(_table, ValueType.Numeric, str); break; case Tokens.Decimal: str = new string(text, start, pos - start); node = new ConstNode(_table, ValueType.Decimal, str); break; case Tokens.Float: str = new string(text, start, pos - start); node = new ConstNode(_table, ValueType.Float, str); break; case Tokens.StringConst: Debug.Assert(text[start] == '\'' && text[pos-1] == '\'', "The expression contains an invalid string constant"); Debug.Assert(pos - start > 1, "The expression contains an invalid string constant"); // Store string without quotes.. str = new string(text, start+1, pos - start-2); node = new ConstNode(_table, ValueType.Str, str); break; case Tokens.Date: Debug.Assert(text[start] == '#' && text[pos-1] == '#', "The expression contains invalid date constant."); Debug.Assert(pos - start > 2, "The expression contains invalid date constant '{0}'."); // Store date without delimiters(#s).. str = new string(text, start+1, pos - start-2); node = new ConstNode(_table, ValueType.Date, str); break; default: Debug.Assert(false, "unhandled token"); break; } NodePush(node); goto loop; case Tokens.LeftParen: cParens++; if (prevOperand == Empty) { // Check for ( following IN/IFF. if not, we have a normal (. // Peek: take a look at the operators stack Debug.Assert(topOperator > 0, "Empty operator stack!!"); opInfo = ops[topOperator - 1]; if (opInfo.type == Nodes.Binop && opInfo.op == Operators.In) { /* IN - handle as procedure call */ node = new FunctionNode(_table, "In"); NodePush(node); /* Push operator decriptor */ ops[topOperator++] = new OperatorInfo(Nodes.Call, Operators.Noop, Operators.priParen); } else { /* Normal ( */ /* Push operator decriptor */ ops[topOperator++] = new OperatorInfo(Nodes.Paren, Operators.Noop, Operators.priParen); } } else { // This is a procedure call or () qualification // Force out any dot qualifiers; check for bomb BuildExpression(Operators.priProc); prevOperand = Empty; ExpressionNode nodebefore = NodePeek(); if (nodebefore == null || nodebefore.GetType() != typeof(NameNode)) { // this is more like an assert, so we not care about "nice" exception text.. // throw ExprException.SyntaxError(); } /* Get the proc name */ NameNode name = (NameNode)NodePop(); // Make sure that we can bind the name as a Function // then get the argument count and types, and parse arguments.. node = new FunctionNode(_table, name.name); // check to see if this is an aggregate function Aggregate agg = (Aggregate)(int)((FunctionNode)node).Aggregate; if (agg != Aggregate.None) { node = ParseAggregateArgument((FunctionId)(int)agg); NodePush(node); prevOperand = Expr; goto loop; } NodePush(node); ops[topOperator++] = new OperatorInfo(Nodes.Call, Operators.Noop, Operators.priParen); } goto loop; case Tokens.RightParen: { /* Right parentheses: Build expression if we have an operand. */ if (prevOperand != Empty) { BuildExpression(Operators.priLow); } /* We must have Tokens.LeftParen on stack. If no operand, must be procedure call. */ if (topOperator <= 1) { // set error, syntax: too many right parens.. throw ExprException.TooManyRightParentheses(); } Debug.Assert(topOperator > 1, "melformed operator stack."); topOperator--; opInfo = ops[topOperator]; if (prevOperand == Empty && opInfo.type != Nodes.Call) { // set error, syntax: missing operand. throw ExprException.MissingOperand(opInfo); } Debug.Assert(opInfo.priority == Operators.priParen, "melformed operator stack."); if (opInfo.type == Nodes.Call) { /* add argument to the function call. */ if (prevOperand != Empty) { // read last function argument ExpressionNode argument = NodePop(); /* Get the procedure name and append argument */ Debug.Assert(topNode > 0 && NodePeek().GetType() == typeof(FunctionNode), "The function node should be created on '('"); FunctionNode func = (FunctionNode)NodePop(); func.AddArgument(argument); func.Check(); NodePush(func); } } else { /* Normal parentheses: create tree node */ // Construct & Put the Nodes.Paren node on node stack node = NodePop(); node = new UnaryNode(_table, Operators.Noop, node); NodePush(node); } prevOperand = Expr; cParens--; goto loop; } case Tokens.ListSeparator: { /* Comma encountered: Must be operand; force out subexpression */ if (prevOperand == Empty) { throw ExprException.MissingOperandBefore(","); } /* We are be in a procedure call */ /* build next argument */ BuildExpression(Operators.priLow); opInfo = ops[topOperator - 1]; if (opInfo.type != Nodes.Call) // throw ExprException.SyntaxError(); ExpressionNode argument2 = NodePop(); /* Get the procedure name */ FunctionNode func = (FunctionNode)NodePop(); func.AddArgument(argument2); NodePush(func); prevOperand = Empty; goto loop; } case Tokens.BinaryOp: if (prevOperand == Empty) { /* Check for unary plus/minus */ if (op == Operators.Plus) { op = Operators.UnaryPlus; // fall through to UnaryOperator; } else if (op == Operators.Minus) { /* Unary minus */ op = Operators.Negative; // fall through to UnaryOperator; } else { // Error missing operand: throw ExprException.MissingOperandBefore(Operators.ToString(op)); } } else { prevOperand = Empty; /* CNSIDER: If we are going to support BETWEEN Translate AND to special BetweenAnd if it is. */ /* Force out to appropriate precedence; push operator. */ BuildExpression(Operators.Priority(op)); // PushOperator descriptor ops[topOperator++] = new OperatorInfo(Nodes.Binop, op, Operators.Priority(op)); goto loop; } goto case Tokens.UnaryOp; // fall through to UnaryOperator; case Tokens.UnaryOp: /* Must be no operand. Push it. */ ops[topOperator++] = new OperatorInfo(Nodes.Unop, op, Operators.Priority(op)); goto loop; case Tokens.ZeroOp: // check the we have operator on the stack if (prevOperand != Empty) { // set error missing operator throw ExprException.MissingOperator(new string(text, start, pos - start)); } // PushOperator descriptor ops[topOperator++] = new OperatorInfo(Nodes.Zop, op, Operators.priMax); prevOperand = Expr; goto loop; case Tokens.Dot: //if there is a name on the stack append it. ExpressionNode before = NodePeek(); if (before != null && before.GetType() == typeof(NameNode)) { Scan(); if (token == Tokens.Name) { NameNode nameBefore = (NameNode)NodePop(); //Debug.WriteLine("Before name '" + nameBefore.name + "'"); string newName = nameBefore.name + "." + NameNode.ParseName(text, start, pos); //Debug.WriteLine("Create new NameNode " + newName); NodePush(new NameNode(_table, newName)); goto loop; } } // fall through to default goto default; default: throw ExprException.UnknownToken(new string(text, start, pos - start), start+1); } } goto end_loop; end_loop: Debug.Assert(topNode == 1 || topNode == 0, "Invalid Node Stack"); expression = NodeStack[0]; return expression; }
/// <summary> /// Builds expression tree for higher-precedence operator to be used as left /// operand of current operator. May cause errors - always do ErrorCheck() upin return. /// </summary> private void BuildExpression(int pri) { ExpressionNode expr = null; Debug.Assert(pri > Operators.priStart && pri <= Operators.priMax, "Invalid priority value"); /* For all operators of higher or same precedence (we are always * left-associative) */ while (true) { Debug.Assert(_topOperator > 0, "Empty operator stack!!"); OperatorInfo opInfo = _ops[_topOperator - 1]; if (opInfo._priority < pri) { goto end_loop; } Debug.Assert(opInfo._priority >= pri, "Invalid prioriry value"); _topOperator--; ExpressionNode nodeLeft; ExpressionNode nodeRight; switch (opInfo._type) { case Nodes.Binop: { // get right, left operands. Bind them. nodeRight = NodePop(); nodeLeft = NodePop(); /* This is the place to do type and other checks */ switch (opInfo._op) { case Operators.Between: case Operators.BetweenAnd: case Operators.BitwiseAnd: case Operators.BitwiseOr: case Operators.BitwiseXor: case Operators.BitwiseNot: throw ExprException.UnsupportedOperator(opInfo._op); case Operators.Is: case Operators.Or: case Operators.And: case Operators.EqualTo: case Operators.NotEqual: case Operators.Like: case Operators.LessThen: case Operators.LessOrEqual: case Operators.GreaterThen: case Operators.GreaterOrEqual: case Operators.In: break; default: Debug.Assert(opInfo._op == Operators.Plus || opInfo._op == Operators.Minus || opInfo._op == Operators.Multiply || opInfo._op == Operators.Divide || opInfo._op == Operators.Modulo, "Invalud Binary operation"); break; } Debug.Assert(nodeLeft != null, "Invalid left operand"); Debug.Assert(nodeRight != null, "Invalid right operand"); if (opInfo._op == Operators.Like) { expr = new LikeNode(_table, opInfo._op, nodeLeft, nodeRight); } else { expr = new BinaryNode(_table, opInfo._op, nodeLeft, nodeRight); } break; } case Nodes.Unop: /* Unary operator: Pop and bind right op. */ nodeLeft = null; nodeRight = NodePop(); /* Check for special cases */ switch (opInfo._op) { case Operators.Not: break; case Operators.BitwiseNot: throw ExprException.UnsupportedOperator(opInfo._op); case Operators.Negative: break; } Debug.Assert(nodeLeft == null, "Invalid left operand"); Debug.Assert(nodeRight != null, "Invalid right operand"); expr = new UnaryNode(_table, opInfo._op, nodeRight); break; case Nodes.Zop: /* Intrinsic constant: just create node. */ expr = new ZeroOpNode(opInfo._op); break; default: Debug.Assert(false, "Unhandled operator type"); goto end_loop; } Debug.Assert(expr != null, "Failed to create expression"); NodePush(expr); // countinue while loop; } end_loop: ; }
// CONSIDER: configure the scanner : local info internal ExpressionNode Parse() { // free all nodes _expression = null; StartScan(); int cParens = 0; OperatorInfo opInfo; while (_token != Tokens.EOS) { loop: Scan(); switch (_token) { case Tokens.EOS: // End of string: must be operand; force out expression; // check for bomb; check nothing left on stack. if (_prevOperand == Empty) { if (_topNode == 0) { // we have an empty expression break; } // set error missing operator // read the last operator info opInfo = _ops[_topOperator - 1]; throw ExprException.MissingOperand(opInfo); } // collect all nodes BuildExpression(Operators.priLow); if (_topOperator != 1) { throw ExprException.MissingRightParen(); } break; case Tokens.Name: case Tokens.Parent: case Tokens.Numeric: case Tokens.Decimal: case Tokens.Float: case Tokens.StringConst: case Tokens.Date: ExpressionNode node = null; string str = null; /* Constants and identifiers: create leaf node */ if (_prevOperand != Empty) { // set error missing operator throw ExprException.MissingOperator(new string(_text, _start, _pos - _start)); } if (_topOperator > 0) { // special check for IN without parentheses opInfo = _ops[_topOperator - 1]; if (opInfo._type == Nodes.Binop && opInfo._op == Operators.In && _token != Tokens.Parent) { throw ExprException.InWithoutParentheses(); } } _prevOperand = Scalar; switch (_token) { case Tokens.Parent: string relname; string colname; // parsing Parent[(relation_name)].column_name) try { // expecting an '(' or '.' Scan(); if (_token == Tokens.LeftParen) { //read the relation name ScanToken(Tokens.Name); relname = NameNode.ParseName(_text, _start, _pos); ScanToken(Tokens.RightParen); ScanToken(Tokens.Dot); } else { relname = null; CheckToken(Tokens.Dot); } } catch (Exception e) when(Common.ADP.IsCatchableExceptionType(e)) { throw ExprException.LookupArgument(); } ScanToken(Tokens.Name); colname = NameNode.ParseName(_text, _start, _pos); opInfo = _ops[_topOperator - 1]; node = new LookupNode(_table, colname, relname); break; case Tokens.Name: /* Qualify name now for nice error checking */ opInfo = _ops[_topOperator - 1]; /* Create tree element - */ // CONSIDER: Check for reserved proc names here node = new NameNode(_table, _text, _start, _pos); break; case Tokens.Numeric: str = new string(_text, _start, _pos - _start); node = new ConstNode(_table, ValueType.Numeric, str); break; case Tokens.Decimal: str = new string(_text, _start, _pos - _start); node = new ConstNode(_table, ValueType.Decimal, str); break; case Tokens.Float: str = new string(_text, _start, _pos - _start); node = new ConstNode(_table, ValueType.Float, str); break; case Tokens.StringConst: Debug.Assert(_text[_start] == '\'' && _text[_pos - 1] == '\'', "The expression contains an invalid string constant"); Debug.Assert(_pos - _start > 1, "The expression contains an invalid string constant"); // Store string without quotes.. str = new string(_text, _start + 1, _pos - _start - 2); node = new ConstNode(_table, ValueType.Str, str); break; case Tokens.Date: Debug.Assert(_text[_start] == '#' && _text[_pos - 1] == '#', "The expression contains invalid date constant."); Debug.Assert(_pos - _start > 2, "The expression contains invalid date constant '{0}'."); // Store date without delimiters(#s).. str = new string(_text, _start + 1, _pos - _start - 2); node = new ConstNode(_table, ValueType.Date, str); break; default: Debug.Assert(false, "unhandled token"); break; } NodePush(node); goto loop; case Tokens.LeftParen: cParens++; if (_prevOperand == Empty) { // Check for ( following IN/IFF. if not, we have a normal (. // Peek: take a look at the operators stack Debug.Assert(_topOperator > 0, "Empty operator stack!!"); opInfo = _ops[_topOperator - 1]; if (opInfo._type == Nodes.Binop && opInfo._op == Operators.In) { /* IN - handle as procedure call */ node = new FunctionNode(_table, "In"); NodePush(node); /* Push operator decriptor */ _ops[_topOperator++] = new OperatorInfo(Nodes.Call, Operators.Noop, Operators.priParen); } else { /* Normal ( */ /* Push operator decriptor */ _ops[_topOperator++] = new OperatorInfo(Nodes.Paren, Operators.Noop, Operators.priParen); } } else { // This is a procedure call or () qualification // Force out any dot qualifiers; check for bomb BuildExpression(Operators.priProc); _prevOperand = Empty; ExpressionNode nodebefore = NodePeek(); if (nodebefore == null || nodebefore.GetType() != typeof(NameNode)) { // this is more like an assert, so we not care about "nice" exception text.. throw ExprException.SyntaxError(); } /* Get the proc name */ NameNode name = (NameNode)NodePop(); // Make sure that we can bind the name as a Function // then get the argument count and types, and parse arguments.. node = new FunctionNode(_table, name._name); // check to see if this is an aggregate function Aggregate agg = (Aggregate)(int)((FunctionNode)node).Aggregate; if (agg != Aggregate.None) { node = ParseAggregateArgument((FunctionId)(int)agg); NodePush(node); _prevOperand = Expr; goto loop; } NodePush(node); _ops[_topOperator++] = new OperatorInfo(Nodes.Call, Operators.Noop, Operators.priParen); } goto loop; case Tokens.RightParen: { /* Right parentheses: Build expression if we have an operand. */ if (_prevOperand != Empty) { BuildExpression(Operators.priLow); } /* We must have Tokens.LeftParen on stack. If no operand, must be procedure call. */ if (_topOperator <= 1) { // set error, syntax: too many right parens.. throw ExprException.TooManyRightParentheses(); } Debug.Assert(_topOperator > 1, "melformed operator stack."); _topOperator--; opInfo = _ops[_topOperator]; if (_prevOperand == Empty && opInfo._type != Nodes.Call) { // set error, syntax: missing operand. throw ExprException.MissingOperand(opInfo); } Debug.Assert(opInfo._priority == Operators.priParen, "melformed operator stack."); if (opInfo._type == Nodes.Call) { /* add argument to the function call. */ if (_prevOperand != Empty) { // read last function argument ExpressionNode argument = NodePop(); /* Get the procedure name and append argument */ Debug.Assert(_topNode > 0 && NodePeek().GetType() == typeof(FunctionNode), "The function node should be created on '('"); FunctionNode func = (FunctionNode)NodePop(); func.AddArgument(argument); func.Check(); NodePush(func); } } else { /* Normal parentheses: create tree node */ // Construct & Put the Nodes.Paren node on node stack node = NodePop(); node = new UnaryNode(_table, Operators.Noop, node); NodePush(node); } _prevOperand = Expr; cParens--; goto loop; } case Tokens.ListSeparator: { /* Comma encountered: Must be operand; force out subexpression */ if (_prevOperand == Empty) { throw ExprException.MissingOperandBefore(","); } /* We are be in a procedure call */ /* build next argument */ BuildExpression(Operators.priLow); opInfo = _ops[_topOperator - 1]; if (opInfo._type != Nodes.Call) { throw ExprException.SyntaxError(); } ExpressionNode argument2 = NodePop(); /* Get the procedure name */ FunctionNode func = (FunctionNode)NodePop(); func.AddArgument(argument2); NodePush(func); _prevOperand = Empty; goto loop; } case Tokens.BinaryOp: if (_prevOperand == Empty) { /* Check for unary plus/minus */ if (_op == Operators.Plus) { _op = Operators.UnaryPlus; // fall through to UnaryOperator; } else if (_op == Operators.Minus) { /* Unary minus */ _op = Operators.Negative; // fall through to UnaryOperator; } else { // Error missing operand: throw ExprException.MissingOperandBefore(Operators.ToString(_op)); } } else { _prevOperand = Empty; /* CNSIDER: If we are going to support BETWEEN Translate AND to special BetweenAnd if it is. */ /* Force out to appropriate precedence; push operator. */ BuildExpression(Operators.Priority(_op)); // PushOperator descriptor _ops[_topOperator++] = new OperatorInfo(Nodes.Binop, _op, Operators.Priority(_op)); goto loop; } goto case Tokens.UnaryOp; // fall through to UnaryOperator; case Tokens.UnaryOp: /* Must be no operand. Push it. */ _ops[_topOperator++] = new OperatorInfo(Nodes.Unop, _op, Operators.Priority(_op)); goto loop; case Tokens.ZeroOp: // check the we have operator on the stack if (_prevOperand != Empty) { // set error missing operator throw ExprException.MissingOperator(new string(_text, _start, _pos - _start)); } // PushOperator descriptor _ops[_topOperator++] = new OperatorInfo(Nodes.Zop, _op, Operators.priMax); _prevOperand = Expr; goto loop; case Tokens.Dot: //if there is a name on the stack append it. ExpressionNode before = NodePeek(); if (before != null && before.GetType() == typeof(NameNode)) { Scan(); if (_token == Tokens.Name) { NameNode nameBefore = (NameNode)NodePop(); string newName = nameBefore._name + "." + NameNode.ParseName(_text, _start, _pos); NodePush(new NameNode(_table, newName)); goto loop; } } // fall through to default goto default; default: throw ExprException.UnknownToken(new string(_text, _start, _pos - _start), _start + 1); } } goto end_loop; end_loop: Debug.Assert(_topNode == 1 || _topNode == 0, "Invalid Node Stack"); _expression = _nodeStack[0]; return(_expression); }
internal override ExpressionNode Optimize() { left = left.Optimize(); if (op == Operators.Is) { // only 'Is Null' or 'Is Not Null' are valid if (right is UnaryNode) { UnaryNode un = (UnaryNode)right; if (un.op != Operators.Not) { throw ExprException.InvalidIsSyntax(); } op = Operators.IsNot; right = un.right; } if (right is ZeroOpNode) { if (((ZeroOpNode)right).op != Operators.Null) { throw ExprException.InvalidIsSyntax(); } } else { throw ExprException.InvalidIsSyntax(); } } else { right = right.Optimize(); } #if DEBUG if (CompModSwitches.BinaryNode.TraceVerbose) { Debug.WriteLine("Optimizing " + this.ToString()); } #endif if (this.IsConstant()) { object val = this.Eval(); #if DEBUG if (CompModSwitches.BinaryNode.TraceVerbose) { Debug.WriteLine("the node value is " + val.ToString()); } #endif if (val == DBNull.Value) { return(new ZeroOpNode(Operators.Null)); } if (val is bool) { if ((bool)val) { return(new ZeroOpNode(Operators.True)); } else { return(new ZeroOpNode(Operators.False)); } } #if DEBUG if (CompModSwitches.BinaryNode.TraceVerbose) { Debug.WriteLine(val.GetType().ToString()); } #endif return(new ConstNode(ValueType.Object, val, false)); } else { return(this); } }
private void BuildExpression(int pri) { OperatorInfo info; ExpressionNode node = null; Label_0002: info = this.ops[this.topOperator - 1]; if (info.priority >= pri) { ExpressionNode node2; ExpressionNode node3; this.topOperator--; switch (info.type) { case Nodes.Unop: node3 = null; node2 = this.NodePop(); switch (info.op) { case 0x19: throw ExprException.UnsupportedOperator(info.op); } node = new UnaryNode(this._table, info.op, node2); goto Label_016C; case Nodes.UnopSpec: case Nodes.BinopSpec: return; case Nodes.Binop: node2 = this.NodePop(); node3 = this.NodePop(); switch (info.op) { case 4: case 6: case 0x16: case 0x17: case 0x18: case 0x19: throw ExprException.UnsupportedOperator(info.op); } if (info.op == 14) { node = new LikeNode(this._table, info.op, node3, node2); } else { node = new BinaryNode(this._table, info.op, node3, node2); } goto Label_016C; case Nodes.Zop: node = new ZeroOpNode(info.op); goto Label_016C; } } return; Label_016C: this.NodePush(node); goto Label_0002; }
internal ExpressionNode Parse() { ExpressionNode node; OperatorInfo info; this.expression = null; this.StartScan(); int num = 0; goto Label_078F; Label_0014: this.Scan(); switch (this.token) { case Tokens.Name: case Tokens.Numeric: case Tokens.Decimal: case Tokens.Float: case Tokens.StringConst: case Tokens.Date: case Tokens.Parent: { node = null; string constant = null; if (this.prevOperand != 0) { throw ExprException.MissingOperator(new string(this.text, this.start, this.pos - this.start)); } if (this.topOperator > 0) { info = this.ops[this.topOperator - 1]; if (((info.type == Nodes.Binop) && (info.op == 5)) && (this.token != Tokens.Parent)) { throw ExprException.InWithoutParentheses(); } } this.prevOperand = 1; switch (this.token) { case Tokens.Name: info = this.ops[this.topOperator - 1]; node = new NameNode(this._table, this.text, this.start, this.pos); goto Label_0338; case Tokens.Numeric: constant = new string(this.text, this.start, this.pos - this.start); node = new ConstNode(this._table, System.Data.ValueType.Numeric, constant); goto Label_0338; case Tokens.Decimal: constant = new string(this.text, this.start, this.pos - this.start); node = new ConstNode(this._table, System.Data.ValueType.Decimal, constant); goto Label_0338; case Tokens.Float: constant = new string(this.text, this.start, this.pos - this.start); node = new ConstNode(this._table, System.Data.ValueType.Float, constant); goto Label_0338; case Tokens.StringConst: constant = new string(this.text, this.start + 1, (this.pos - this.start) - 2); node = new ConstNode(this._table, System.Data.ValueType.Str, constant); goto Label_0338; case Tokens.Date: constant = new string(this.text, this.start + 1, (this.pos - this.start) - 2); node = new ConstNode(this._table, System.Data.ValueType.Date, constant); goto Label_0338; case Tokens.Parent: { string str2; try { this.Scan(); if (this.token == Tokens.LeftParen) { this.ScanToken(Tokens.Name); str2 = NameNode.ParseName(this.text, this.start, this.pos); this.ScanToken(Tokens.RightParen); this.ScanToken(Tokens.Dot); } else { str2 = null; this.CheckToken(Tokens.Dot); } } catch (Exception exception) { if (!ADP.IsCatchableExceptionType(exception)) { throw; } throw ExprException.LookupArgument(); } this.ScanToken(Tokens.Name); string columnName = NameNode.ParseName(this.text, this.start, this.pos); info = this.ops[this.topOperator - 1]; node = new LookupNode(this._table, columnName, str2); goto Label_0338; } } break; } case Tokens.ListSeparator: { if (this.prevOperand == 0) { throw ExprException.MissingOperandBefore(","); } this.BuildExpression(3); info = this.ops[this.topOperator - 1]; if (info.type != Nodes.Call) { throw ExprException.SyntaxError(); } ExpressionNode argument = this.NodePop(); FunctionNode node4 = (FunctionNode) this.NodePop(); node4.AddArgument(argument); this.NodePush(node4); this.prevOperand = 0; goto Label_0014; } case Tokens.LeftParen: num++; if (this.prevOperand != 0) { this.BuildExpression(0x16); this.prevOperand = 0; ExpressionNode node5 = this.NodePeek(); if ((node5 == null) || (node5.GetType() != typeof(NameNode))) { throw ExprException.SyntaxError(); } NameNode node9 = (NameNode) this.NodePop(); node = new FunctionNode(this._table, node9.name); Aggregate aggregate = (Aggregate) ((FunctionNode) node).Aggregate; if (aggregate != Aggregate.None) { node = this.ParseAggregateArgument((FunctionId) aggregate); this.NodePush(node); this.prevOperand = 2; } else { this.NodePush(node); this.ops[this.topOperator++] = new OperatorInfo(Nodes.Call, 0, 2); } } else { info = this.ops[this.topOperator - 1]; if ((info.type != Nodes.Binop) || (info.op != 5)) { this.ops[this.topOperator++] = new OperatorInfo(Nodes.Paren, 0, 2); } else { node = new FunctionNode(this._table, "In"); this.NodePush(node); this.ops[this.topOperator++] = new OperatorInfo(Nodes.Call, 0, 2); } } goto Label_0014; case Tokens.RightParen: if (this.prevOperand != 0) { this.BuildExpression(3); } if (this.topOperator <= 1) { throw ExprException.TooManyRightParentheses(); } this.topOperator--; info = this.ops[this.topOperator]; if ((this.prevOperand == 0) && (info.type != Nodes.Call)) { throw ExprException.MissingOperand(info); } if (info.type == Nodes.Call) { if (this.prevOperand != 0) { ExpressionNode node8 = this.NodePop(); FunctionNode node2 = (FunctionNode) this.NodePop(); node2.AddArgument(node8); node2.Check(); this.NodePush(node2); } } else { node = this.NodePop(); node = new UnaryNode(this._table, 0, node); this.NodePush(node); } this.prevOperand = 2; num--; goto Label_0014; case Tokens.ZeroOp: if (this.prevOperand != 0) { throw ExprException.MissingOperator(new string(this.text, this.start, this.pos - this.start)); } this.ops[this.topOperator++] = new OperatorInfo(Nodes.Zop, this.op, 0x18); this.prevOperand = 2; goto Label_0014; case Tokens.UnaryOp: goto Label_0647; case Tokens.BinaryOp: if (this.prevOperand != 0) { this.prevOperand = 0; this.BuildExpression(Operators.Priority(this.op)); this.ops[this.topOperator++] = new OperatorInfo(Nodes.Binop, this.op, Operators.Priority(this.op)); goto Label_0014; } if (this.op != 15) { if (this.op != 0x10) { throw ExprException.MissingOperandBefore(Operators.ToString(this.op)); } this.op = 1; } else { this.op = 2; } goto Label_0647; case Tokens.Dot: { ExpressionNode node3 = this.NodePeek(); if ((node3 == null) || !(node3.GetType() == typeof(NameNode))) { goto Label_0763; } this.Scan(); if (this.token != Tokens.Name) { goto Label_0763; } NameNode node6 = (NameNode) this.NodePop(); string name = node6.name + "." + NameNode.ParseName(this.text, this.start, this.pos); this.NodePush(new NameNode(this._table, name)); goto Label_0014; } case Tokens.EOS: if (this.prevOperand != 0) { this.BuildExpression(3); if (this.topOperator != 1) { throw ExprException.MissingRightParen(); } } else if (this.topNode != 0) { info = this.ops[this.topOperator - 1]; throw ExprException.MissingOperand(info); } goto Label_078F; default: goto Label_0763; } Label_0338: this.NodePush(node); goto Label_0014; Label_0647: this.ops[this.topOperator++] = new OperatorInfo(Nodes.Unop, this.op, Operators.Priority(this.op)); goto Label_0014; Label_0763: throw ExprException.UnknownToken(new string(this.text, this.start, this.pos - this.start), this.start + 1); Label_078F: if (this.token != Tokens.EOS) { goto Label_0014; } this.expression = this.NodeStack[0]; return this.expression; }