/*******************************************************************\

Module: ANSI-C Conversion / Type Checking

Author: Daniel Kroening, kroening@kroening.com

\*******************************************************************/

#include <arith_tools.h>
#include <expr_util.h>

#include "c_typecheck_base.h"

/*******************************************************************\

Function: c_typecheck_baset::add_argc_argv

  Inputs:

 Outputs:

 Purpose:

\*******************************************************************/

void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol)
{
  const irept &arguments=
    main_symbol.type.find("arguments");

  if(arguments.get_sub().size()==0)
    return;

  if(arguments.get_sub().size()!=2)
  {
    err_location(main_symbol.location);
    throw "main expected to have no or two arguments";
  }

  symbolt *argc_new_symbol;
  
  const exprt &op0=(exprt &)arguments.get_sub().front();
  const exprt &op1=(exprt &)arguments.get_sub().back();

  {
    symbolt argc_symbol;

    argc_symbol.base_name="argc";
    argc_symbol.name="c::argc'";
    argc_symbol.type=op0.type();
    argc_symbol.static_lifetime=true;

    if(argc_symbol.type.id()!="signedbv" &&
       argc_symbol.type.id()!="unsignedbv")
    {
      err_location(main_symbol.location);
      err << "argc argument expected to be integer type, but got `"
          << to_string(argc_symbol.type) << "'";
      throw 0;
    }

    move_symbol(argc_symbol, argc_new_symbol);
  }

  {
    symbolt argv_symbol;

    argv_symbol.base_name="argv";
    argv_symbol.name="c::argv'";
    argv_symbol.type=op1.type();
    argv_symbol.static_lifetime=true;

    if(argv_symbol.type.id()!="pointer")
    {
      err_location(main_symbol.location);
      err << "argv argument expected to be pointer type, but got `"
          << to_string(argv_symbol.type) << "'";
      throw 0;
    }
    
    // need to add one -- the array is terminated
    // with NULL

    exprt one_expr=from_integer(1, argc_new_symbol->type);
    
    exprt size_expr("+", argc_new_symbol->type);
    size_expr.copy_to_operands(symbol_expr(*argc_new_symbol));
    size_expr.move_to_operands(one_expr);

    argv_symbol.type.id("array");
    argv_symbol.type.add("size").swap(size_expr);

    symbolt *argv_new_symbol;
    move_symbol(argv_symbol, argv_new_symbol);
  }
}
