TPParseTreeNode CFormulaParser::ParseExpression() { int token_ID = _tokenizer.LookAhead(); TPParseTreeNode expression; // Handle brackets before unary, because brackets are also "unary" if (TokenIsBracketOpen(token_ID)) { expression = ParseBracketExpression(); } else if (TokenIsUnary(token_ID)) { expression = ParseUnaryExpression(); } else if ((token_ID == kTokenIdentifier) || (token_ID == kTokenNumber)) { expression = ParseSimpleExpression(); } else { CParseErrors::Error("Unexpected token inside expression.\n" "Expecting: opening bracket, unary operator, identifier or number.\n"); return NULL; } token_ID = _tokenizer.LookAhead(); if (TokenIsBinary(token_ID)) { _tokenizer.GetToken(); // Special handling of percentaged potsized bets, // that look like modulo or percentage operators, // but lack a 2nd operand and have "Force" instead. // When ... RaiseBy 60% Force if (token_ID == kTokenOperatorPercentage) { int next_token_ID = _tokenizer.LookAhead(); if (next_token_ID == kTokenKeywordForce) { // Now we should pushback the *2nd last* token (percentage) _tokenizer.PushBackAdditionalPercentageOperator(); // and return the expression we got so far return expression; } } TPParseTreeNode second_expression = ParseExpression(); TPParseTreeNode binary_node = new CParseTreeNode(_tokenizer.LineRelative()); binary_node->MakeBinaryOperator(token_ID, expression, second_expression); write_log(preferences.debug_parser(), "[FormulaParser] Binary node %i\n", binary_node); return binary_node; } else if (token_ID == kTokenOperatorConditionalIf) { // Ternary condition TPParseTreeNode then_expression; TPParseTreeNode else_expression; ParseConditionalPartialThenElseExpressions( &then_expression, &else_expression); TPParseTreeNode ternary_node = new CParseTreeNode(_tokenizer.LineRelative()); ternary_node->MakeTernaryOperator(token_ID, expression, then_expression, else_expression); write_log(preferences.debug_parser(), "[FormulaParser] Ternary node %i\n", ternary_node); return ternary_node; } else { // We got the complete expression // No complex binary or ternary condition write_log(preferences.debug_parser(), "[FormulaParser] Expression %i\n", expression); return expression; } }
TPParseTreeNode CParseTreeNode::GetLeftMostSibbling() { if (TokenIsUnary(_node_type) || TokenIsBinary(_node_type) || TokenIsTernary(_node_type)) { return _first_sibbling; } // Not an operator return NULL; }
double CParseTreeOperatorNode::Evaluate(bool log /* = false */) { write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] Evaluating node type %i %s\n", _node_type, TokenString(_node_type)); p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); // Actions first, which are "unary". // We have to encode all possible outcomes in a single floating-point, // therefore: // * positive values mean: raise size (by big-blinds, raise-to-semantics) // * negative values mean: elementary actions if (_node_type == kTokenActionRaiseToBigBlinds) { // RaiseTo N Force return EvaluateSibbling(_first_sibbling, log); } else if (_node_type == kTokenActionRaiseByBigBlinds) { // RaiseBy N Force double raise_by_amount_in_bblinds = EvaluateSibbling(_first_sibbling, log); double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] raiseby = %.2f ncallbets = %.2f final = %.2f\n", raise_by_amount_in_bblinds, p_symbol_engine_chip_amounts->ncallbets(), final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionRaiseByPercentagedPotsize) { // RaiseBy X% Force double raise_by_percentage = EvaluateSibbling(_first_sibbling, log); assert(p_symbol_engine_tablelimits->bet() > 0); double pot_size_after_call_in_big_blinds = (p_symbol_engine_chip_amounts->pot() / p_symbol_engine_tablelimits->bet()) + p_symbol_engine_chip_amounts->nbetstocall(); assert(pot_size_after_call_in_big_blinds >= 0); double raise_by_amount_in_bblinds = 0.01 * raise_by_percentage * pot_size_after_call_in_big_blinds; double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeOperatorNode] raiseby percentage = %.2f pot after call = %.2f raiseby = %.2f final = %.2f\n", raise_by_percentage, pot_size_after_call_in_big_blinds, raise_by_amount_in_bblinds, final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (TokenIsElementaryAction(_node_type)) { return (0 - _node_type); } // Finally operators else if (TokenIsUnary(_node_type)) { return EvaluateUnaryExpression(log); } else if (TokenIsBinary(_node_type)) { return EvaluateBinaryExpression(log); } else if (TokenIsTernary(_node_type)) { return EvaluateTernaryExpression(log); } assert(false); return kUndefined; }
TPParseTreeNode CFormulaParser::ParseUnaryExpression() { int unary_operator = _tokenizer.GetToken(); assert(TokenIsUnary(unary_operator)); TPParseTreeNode expression = ParseExpression(); TPParseTreeNode unary_node = new CParseTreeNode(_tokenizer.LineRelative()); unary_node->MakeUnaryOperator(unary_operator, expression); write_log(preferences.debug_parser(), "[FormulaParser] Unary node %i\n", unary_node); return unary_node; }
TPParseTreeNode CParseTreeNode::GetRightMostSibbling() { if (TokenIsTernary(_node_type)) { return _third_sibbling; } else if (TokenIsBinary(_node_type)) { return _second_sibbling; } else if (TokenIsUnary(_node_type)) { return _first_sibbling; } else { // Not an operator return NULL; } }
CString CParseTreeNode::Serialize() { if (_node_type == kTokenIdentifier) { return _terminal_name; } else if (_node_type == kTokenNumber) { return Number2CString(_constant_value); } else if (TokenIsBracketOpen(_node_type)) { return ("(" + _first_sibbling->Serialize() + ")"); } else if (TokenIsUnary(_node_type)) { assert(_first_sibbling != NULL); return TokenString(_node_type) + "(" + _first_sibbling->Serialize() + ")"; } else if (TokenIsBinary(_node_type)) { assert(_first_sibbling != NULL); assert(_second_sibbling != NULL); return "(" + _first_sibbling->Serialize() + " " + TokenString(_node_type) + " " + _second_sibbling->Serialize() + ")"; } else if (_node_type == kTokenOperatorConditionalIf) { assert(_first_sibbling != NULL); assert(_second_sibbling != NULL); assert(_third_sibbling != NULL); return "(" + _first_sibbling->Serialize() + " ? " + _second_sibbling->Serialize() + " : " + _third_sibbling->Serialize() + ")"; } else if (IsOpenEndedWhenCondition()) { return "WHEN: " + _first_sibbling->Serialize() + "\n" + (_second_sibbling? _second_sibbling->Serialize(): "") // No third sibbling to serialize, because this is the next open-ender // and TWO pointers point to it (one from a normal "when") + "WEND"; } else if (IsWhenConditionWithAction()) { return " WHEN: " + _first_sibbling->Serialize() + "WRETURN: " + (_second_sibbling? _second_sibbling->Serialize(): "") + "\n" // Third sibbling: either next when-condition or next open-ended when-condition + (_third_sibbling? _third_sibbling->Serialize(): ""); } else { // Unhandled note-type, probably new and therefore not yet handled write_log(k_always_log_errors, "[CParseTreeNode] ERROR: Unhandled node-tzpe %i in serialiyation of parse-tree\n", _node_type); return ""; } }
double CParseTreeNode::Evaluate(bool log /* = false */){ write_log(preferences.debug_formula(), "[CParseTreeNode] Evaluating node type %i %s\n", _node_type, TokenString(_node_type)); p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); // Most common types first: numbers and identifiers if (_node_type == kTokenNumber) { write_log(preferences.debug_formula(), "[CParseTreeNode] Number evaluates to %6.3f\n", _constant_value); return _constant_value; } else if (_node_type == kTokenIdentifier) { assert(_first_sibbling == NULL); assert(_second_sibbling == NULL); assert(_third_sibbling == NULL); assert(_terminal_name != ""); double value = EvaluateIdentifier(_terminal_name, log); write_log(preferences.debug_formula(), "[CParseTreeNode] Identifier evaluates to %6.3f\n", value); // In case of f$-functions the line changed inbetween, // so we have to set it to the current location (again) // for the next log. p_autoplayer_trace->SetLastEvaluatedRelativeLineNumber(_relative_line_number); return value; } // Actions second, which are also "unary". // We have to encode all possible outcomes in a single floating-point, // therefore: // * positive values mean: raise size (by big-blinds, raise-to-semantics) // * negative values mean: elementary actions else if (_node_type == kTokenActionRaiseToBigBlinds) { // RaiseTo N Force return EvaluateSibbling(_first_sibbling, log); } else if (_node_type == kTokenActionRaiseByBigBlinds) { // RaiseBy N Force double raise_by_amount_in_bblinds = EvaluateSibbling(_first_sibbling, log); double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeNode] raiseby = %.2f ncallbets = %.2f final = %.2f\n", raise_by_amount_in_bblinds, p_symbol_engine_chip_amounts->ncallbets(), final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionRaiseByPercentagedPotsize) { // RaiseBy X% Force double raise_by_percentage = EvaluateSibbling(_first_sibbling, log); assert(p_symbol_engine_tablelimits->bet() > 0); double pot_size_after_call_in_big_blinds = (p_symbol_engine_chip_amounts->pot() / p_symbol_engine_tablelimits->bet()) + p_symbol_engine_chip_amounts->nbetstocall(); assert(pot_size_after_call_in_big_blinds >= 0); double raise_by_amount_in_bblinds = 0.01 * raise_by_percentage * pot_size_after_call_in_big_blinds; double final_betsize_in_bblinds = p_symbol_engine_chip_amounts->ncallbets() + raise_by_amount_in_bblinds; write_log(preferences.debug_formula(), "[CParseTreeNode] raiseby percentage = %.2f pot after call = %.2f raiseby = %.2f final = %.2f\n", raise_by_percentage, pot_size_after_call_in_big_blinds, raise_by_amount_in_bblinds, final_betsize_in_bblinds); return final_betsize_in_bblinds; } else if (_node_type == kTokenActionUserVariableToBeSet) { // User-variables are a special case of elementary actions // Therefore need to be handled first. SetUserVariable(_terminal_name); return kUndefinedZero; } else if (TokenIsElementaryAction(_node_type)) { return (0 - _node_type); } // Finally operators else if (TokenIsUnary(_node_type)) { return EvaluateUnaryExpression(log); } else if (TokenIsBinary(_node_type)) { return EvaluateBinaryExpression(log); } else if (TokenIsTernary(_node_type)) { return EvaluateTernaryExpression(log); } assert(false); return kUndefined; }