parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
                               uint8_t min_prec_treshold) /**< minimal precedence of tokens */
{
  while (true)
  {
    uint8_t token = context_p->stack_top_uint8;
    uint16_t opcode;

    /* For left-to-right operators (all binary operators except assignment
     * and logical operators), the byte code is flushed if the precedence
     * of the next operator is less or equal than the current operator. For
     * assignment and logical operators, we add 1 to the min precendence to
     * force right-to-left evaluation order. */

    if (!LEXER_IS_BINARY_OP_TOKEN (token)
        || parser_binary_precedence_table[token - LEXER_FIRST_BINARY_OP] < min_prec_treshold)
    {
      return;
    }

    parser_push_result (context_p);
    parser_stack_pop_uint8 (context_p);

    if (token == LEXER_ASSIGN)
    {
      uint16_t index = PARSER_INVALID_LITERAL_INDEX;
      opcode = context_p->stack_top_uint8;

#if JERRY_ESNEXT
      if (JERRY_UNLIKELY (opcode == CBC_EXT_OPCODE))
      {
        parser_stack_pop_uint8 (context_p);
        JERRY_ASSERT (context_p->stack_top_uint8 == CBC_EXT_ASSIGN_SUPER);
        opcode = PARSER_TO_EXT_OPCODE (context_p->stack_top_uint8);
        parser_stack_pop_uint8 (context_p);
      }
      else
#endif /* JERRY_ESNEXT */
      {
        parser_stack_pop_uint8 (context_p);

        if (cbc_flags[opcode] & CBC_HAS_LITERAL_ARG)
        {
          JERRY_ASSERT (opcode == CBC_ASSIGN_SET_IDENT
                        || opcode == CBC_ASSIGN_PROP_LITERAL
                        || opcode == CBC_ASSIGN_PROP_THIS_LITERAL
                        || opcode == CBC_ASSIGN_LET_CONST
                        || opcode == CBC_INIT_ARG_OR_CATCH
                        || opcode == CBC_INIT_LET
                        || opcode == CBC_INIT_CONST);

          index = parser_stack_pop_uint16 (context_p);
        }
      }

#if JERRY_ESNEXT
      bool group_expr_assingment = false;

      if (JERRY_UNLIKELY (context_p->stack_top_uint8 == LEXER_ASSIGN_GROUP_EXPR))
      {
        group_expr_assingment = true;
        parser_stack_pop_uint8 (context_p);
      }

      if (JERRY_UNLIKELY (context_p->stack_top_uint8 == LEXER_ASSIGN_CONST))
      {
        parser_stack_pop_uint8 (context_p);
        parser_emit_cbc_ext (context_p, CBC_EXT_THROW_ASSIGN_CONST_ERROR);
      }
#endif /* JERRY_ESNEXT */

      if (index != PARSER_INVALID_LITERAL_INDEX)
      {
#if JERRY_ESNEXT
        if (!group_expr_assingment)
        {
          uint16_t function_literal_index = parser_check_anonymous_function_declaration (context_p);

          if (function_literal_index == PARSER_ANONYMOUS_CLASS)
          {
            uint16_t name_index = scanner_save_literal (context_p, index);
            parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_CLASS_NAME, name_index);
          }
          else if (function_literal_index < PARSER_NAMED_FUNCTION)
          {
            parser_set_function_name (context_p, function_literal_index, (uint16_t) index, 0);
          }
        }
#endif /* JERRY_ESNEXT */

        if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
            && opcode == CBC_ASSIGN_SET_IDENT)
        {
          JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT,
                                     CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));

          context_p->last_cbc.value = index;
          context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT;
          continue;
        }

        parser_emit_cbc_literal (context_p, (uint16_t) opcode, index);

        if (opcode == CBC_ASSIGN_PROP_THIS_LITERAL
            && (context_p->stack_depth >= context_p->stack_limit))
        {
          /* Stack limit is increased for VM_OC_ASSIGN_PROP_THIS. Needed by vm.c. */
          JERRY_ASSERT (context_p->stack_depth == context_p->stack_limit);

          context_p->stack_limit++;

          if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
          {
            parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
          }
        }
        continue;
      }
    }
    else if (LEXER_IS_BINARY_LVALUE_OP_TOKEN (token))
    {
      parser_stack_push_uint8 (context_p, CBC_ASSIGN);
      parser_stack_push_uint8 (context_p, LEXER_ASSIGN);
      parser_stack_push_uint8 (context_p, lexer_convert_binary_lvalue_token_to_binary (token));
      continue;
    }
    else if (token == LEXER_LOGICAL_OR || token == LEXER_LOGICAL_AND)
    {
      parser_branch_t branch;
      parser_stack_pop (context_p, &branch, sizeof (parser_branch_t));
      parser_set_branch_to_current_position (context_p, &branch);
      continue;
    }
#if JERRY_ESNEXT
    else if (token == LEXER_NULLISH_COALESCING)
    {
      parser_branch_t branch;
      parser_stack_pop (context_p, &branch, sizeof (parser_branch_t));
      parser_set_branch_to_current_position (context_p, &branch);
      continue;
    }
#endif /* JERRY_ESNEXT */
    else
    {
      opcode = LEXER_BINARY_OP_TOKEN_TO_OPCODE (token);

      if (PARSER_IS_PUSH_NUMBER (context_p->last_cbc_opcode))
      {
        lexer_convert_push_number_to_push_literal (context_p);
      }

      if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
      {
        JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, opcode + CBC_BINARY_WITH_LITERAL));
        context_p->last_cbc_opcode = (uint16_t) (opcode + CBC_BINARY_WITH_LITERAL);
        continue;
      }
      else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
      {
        JERRY_ASSERT (CBC_ARGS_EQ (opcode + CBC_BINARY_WITH_TWO_LITERALS,
                                   CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
        context_p->last_cbc_opcode = (uint16_t) (opcode + CBC_BINARY_WITH_TWO_LITERALS);
        continue;
      }
    }
    parser_emit_cbc (context_p, opcode);
  }
} /* parser_process_binary_opcodes */