Cell* op_floor::eval_op(Cell* operand) const
{
  Cell* operand_ptr;

  no_of_operands(operand,1,1,true,true);

  operand_ptr = car(operand);

  if (listp(operand_ptr))
  {
    operand_ptr = eval(operand_ptr);
  }
  else if (symbolp(operand_ptr))
  {
    operand_ptr = search_symbol(get_symbol(operand_ptr),true);
  }

  if (doublep(operand_ptr))
  {
    return make_int( int(floor(get_double(operand_ptr))) );
  }
  else
  {
    if (operand_ptr != NULL)
       delete operand_ptr;
    throw runtime_error("'floor' only operates with double.");
  }
}
Cell* op_plus::eval_op(Cell* operand) const
{
  // keep adding until reaches nil pointer
  int int_sum = 0;
  double double_sum = 0.0;
  bool double_exist = false;

  //to store the result of car cell if it is a list
  Cell* operand_ptr;

  //check if operand is not empty
  while(!nullp(operand))
  {
    if (nullp(car(operand)))
    {
       if (operand_ptr != NULL)
          delete operand_ptr;
       throw runtime_error("'+' can only deal with integer and double.");
    }
    else if (listp(car(operand)))
    {
       operand_ptr = eval(car(operand));
    }
    else if (symbolp(car(operand)))
    {
       operand_ptr = search_symbol(get_symbol(car(operand)),true);
    }
    else
    {
       operand_ptr = car(operand);
    }

    if (intp(operand_ptr))
    {
       int_sum += get_int(operand_ptr);
    }
    else if (doublep(operand_ptr))
    {
       double_sum += get_double(operand_ptr);
       double_exist = true;
    }
    else
    {
       delete operand_ptr;
       throw runtime_error("'+' can only deal with integer and double.");
    }

    operand = cdr(operand);
  }
  
  if (double_exist)
    return make_double(double_sum+int_sum);
  else
    return make_int(int_sum);
};
Exemple #3
0
Cell* eval(Cell* const c)
{
  // when root cell is empty, throw an error.
  judge_nil_cell(c,"begin");
  
  // when root cell is a int or double cell, return a copy.
  if (intp(c) || doublep(c) || procedurep(c)) {
    return c -> deep_copy();
  }

  //if c is a symbol, there are several situations
  //if c is in the local map, which means c is a procedurecell.
  //if c is in the global map, which menas c is defined as some other value.
  if (symbolp(c)) {
    string var = get_symbol(c);
    // first check if the symbol is defined at a local space
    // if it is, then return a copy of it.
    if (!my_stack.empty()) {
      if (my_stack.top().count(var)) {
	bstmap<string,Cell*> temp = my_stack.top();
	if (nullp(temp[var])) return nil;
	return temp[var] -> deep_copy();
      }
    }
    // then check if the symbol is defined in the global map
    if (symbol_table.count(var)) {
      if (nullp(symbol_table[var])) return nil;
      return symbol_table[var] -> deep_copy();
    }
    throw symbol_undefined_error("the variable " + var + " is not defined in the map");
  }

  // Then we know the 'c' cell must be a root of list
  Cell* oper_cell = NULL;
  string oper;
  if (listp(car(c))) {
    oper_cell = eval(car(c));
    // oper cell should be the operator (primitive or procedure cell)
    // it cannot be an empty operator
    if (nullp(oper_cell)) {
      throw invalid_operator_error("you cannot use an empty operator");
    }
    // if the first element of the expression is a list, the result evaluating it must be a procedure
    if (!procedurep(oper_cell)) {
      throw invalid_operator_error("cannot apply a value that is not a function");
    }
    // then return a copy of this procedure cell
    if (procedurep(oper_cell)) {
      Cell* argu_list = nullp(cdr(c)) ? nil : cdr(c) -> deep_copy();
      return oper_cell -> apply(argu_list);
    }
  }

  oper_cell = car(c) -> deep_copy();
  // the operator cannot be a int or double
  if (!symbolp(oper_cell)) {
    throw invalid_operator_error("The input operator is not a procedure or primitive type");
  }
  oper = get_symbol(oper_cell);

  /**
   * the ceiling operator
   * using oper_ceil(), which is a virtual function in Cell.
   */
  if (oper == "ceiling") {
    judge_num_argu(c,oper); // check validation
    Cell* temp_cell = eval(car(cdr(c)));
    judge_nil_cell(temp_cell,oper); // check validation
    Cell* result = temp_cell -> oper_ceil();
    delete oper_cell;
    delete temp_cell;
    return result;
  }

  /**
   * the floor operator
   * using oper_floor(), which is a virtual function in Cell.
   */
  if (oper == "floor") {
    judge_num_argu(c,oper); // check validation
    Cell* temp_cell = eval(car(cdr(c)));
    judge_nil_cell(temp_cell,oper); //check validation
    Cell* result = temp_cell -> oper_floor();
    delete oper_cell;
    delete temp_cell;
    return result;
  }

  /**
   * the add operator
   * using oper_add(), which is a virtual function in Cell.
   */
  if (oper == "+") {
    // by "+" convention, when evaluate a single plus operator, return 0.
    if (nullp(cdr(c))) {
      delete oper_cell; 
      return make_int(0);
    }
    int size = cdr(c) -> cons_size();
    // use cell:result as a initial cell
    Cell* result = make_int(0);
    Cell* next_elem = cdr(c);
    
    for (int i=1; i<=size; i++) {
      Cell* next_temp = eval(car(next_elem));
      judge_nil_cell(next_temp,oper);
      result = result -> oper_add(next_temp);
      delete next_temp; //delete temporary cell in every step.
      next_elem = cdr(next_elem);
    }
    
    delete oper_cell;
    return result;
  }

  /**
   * the minus operator
   * using oper_minus(), which is a virtual function in Cell.
   */
  if (oper == "-") {
    judge_num_argu(c,oper);
    int size = cdr(c) -> cons_size();
    Cell* result = eval(car(cdr(c)));
    judge_nil_cell(result,oper);
    // by "-" convention, when only one operand, return its inverse.
    if (size == 1) {
      result = result -> oper_minus(nil);
      delete oper_cell;
      return result;
    }
    Cell* next_elem = cdr(cdr(c));
    
    for (int i=1; i<size; i++) {
      Cell* next_temp = eval(car(next_elem));
      judge_nil_cell(next_temp,oper);
      result = result -> oper_minus(next_temp);
      delete next_temp; //delete temporary cell in every step.
      next_elem = cdr(next_elem);
    }

    delete oper_cell;
    return result;
  }

  /**
   * the multiply operator
   * using oper_multiply(), which is a virtual function in Cell.
   */
  if (oper == "*") {
    if (nullp(cdr(c))) {
      delete oper_cell;
      return make_int(1);
    }
    int size = cdr(c) -> cons_size();
    Cell* result = make_int(1);
    Cell* next_elem = cdr(c);

    for (int i=1; i<=size; i++) {
      Cell* next_temp = eval(car(next_elem));
      judge_nil_cell(next_temp,oper);
      result = result -> oper_multiply(next_temp);
      delete next_temp; //delete temporary cell in every step.
      next_elem = cdr(next_elem);
    }

    delete oper_cell;
    return result;
  }

  /**
   * the division operator
   * using oper_divide(), which is a virtual function in Cell.
   */
  if (oper == "/") {
    judge_num_argu(c,oper);
    int size = cdr(c) -> cons_size();
    Cell* result = eval(car(cdr(c)));
    judge_nil_cell(result,oper);
    // by "/" convention, when only one operand, return its inverse.
    if (size == 1) {
      result = result -> oper_divide(nil);
      delete oper_cell;
      return result;
    }
    Cell* next_elem = cdr(cdr(c));
    
    for (int i=1; i<size; i++) {
      Cell* next_temp = eval(car(next_elem));
      judge_nil_cell(next_temp,oper);
      result = result -> oper_divide(next_temp);
      delete next_temp; //delete temporary cell on every step.
      next_elem = cdr(next_elem);
    }
    
    delete oper_cell;
    return result;
  }

  /**
   * the if operator
   * using oper_if(), which is a virtual function in Cell.
   */
  if (oper == "if") {
    judge_num_argu(c,oper); // check validation
    int size = cdr(c) -> cons_size();
    Cell* judge_cell = cdr(c); // the first operand after if
    Cell* judge_cell_temp = eval(car(judge_cell));
    Cell* true_cell = cdr(judge_cell); // the second operand after if
    // if judge cell is a empty list, return true_cell
    if (nullp(judge_cell_temp)) {
      delete judge_cell_temp; 
      delete oper_cell;
      return eval(car(true_cell));
    }
    
    Cell* condition = judge_cell_temp -> oper_if();
    // condition must be an IntCell from the implementation of Cell.cpp
    if (get_int(condition)) {
      Cell* true_cell_temp = eval(car(true_cell));
      delete judge_cell_temp;
      delete oper_cell;
      return true_cell_temp;
    } else {
      Cell* false_cell = nil;
      // if there are only two operand, which is an undefined behavior
      // we will let it return the second operand
      if (size == 2) {
	false_cell = eval(car(true_cell)); 
      } else {
	false_cell = eval(car(cdr(true_cell)));
      }
      delete judge_cell_temp;
      delete oper_cell;
      return false_cell;
    }
  }	  
  
  /**
   * the quote operator
   */
  if (oper == "quote") {
    judge_num_argu(c,oper); // check validation
    delete oper_cell;
    if (nullp(car(cdr(c)))) return nil;
    return car(cdr(c)) -> deep_copy();
  }
 
  /**
   * the cons operator
   * using cons() which is a function in cons.hpp.
   */
  if (oper == "cons") {
    judge_num_argu(c,oper); // check validation
    Cell* car_new = eval(car(cdr(c)));
    Cell* cdr_new = eval(car(cdr(cdr(c))));
    if (!listp(cdr_new)) {
      throw invalid_operator_error("cdr must either be nil or a conspair");
    }
    Cell* result = cons(car_new, cdr_new);
    delete oper_cell;
    return result;
  }

  /**
   * the car operator
   * using car() which is a function in cons.hpp.
   */
  if (oper == "car") {
    judge_num_argu(c,oper);
    Cell* temp = eval(car(cdr(c)));
    Cell* result = nullp(car(temp)) ? nil : car(temp) -> deep_copy();
    delete temp;
    delete oper_cell;
    return result;
  }

  /**
   * the cdr operator
   * using cdr() which is a function in cons.hpp.
   */
  if (oper == "cdr") {
    judge_num_argu(c,oper);
    Cell* temp = eval(car(cdr(c)));
    Cell* result = nullp(cdr(temp)) ? nil : cdr(temp) -> deep_copy();
    delete temp;
    delete oper_cell;
    return result;
  }
  

  /**
   * the nullp operator
   * using nullp() which is a function in cons.hpp.
   */
  if (oper == "nullp") {
    judge_num_argu(c,oper);
    Cell* temp_cell = eval(car(cdr(c)));
    if(nullp(temp_cell)) {
      delete temp_cell;
      delete oper_cell;
      return make_int(1);
    } else {
      delete temp_cell;
      delete oper_cell;
      return make_int(0);
    }
  } 

  /**
   * the define operator
   * using map to record relation between string and cell
   */
  if (oper == "define") {
    judge_num_argu(c,oper);
    Cell* key_cell = car(cdr(c));
    Cell* next_cell = car(cdr(cdr(c)));
    if (!symbolp(key_cell)) {
      throw operate_on_nil_error("define operand must be a symbol");
    }
    Cell* mapped_cell = eval(next_cell);
    string key = get_symbol(key_cell);
    if (symbol_table.count(key)) {
      throw invalid_operand_error("Cannot redefine a variable");
    }
    symbol_table.insert(make_pair(key,mapped_cell));
    delete oper_cell;
    return nil;
  }
  
  /**
   * the less operator
   * using oper_less(), which is a virtual function in Cell.
   */
  if (oper == "<") {
    //by convention, it will return 1 when zero argument.
    if (nullp(cdr(c))) {
      return make_int(1);
    }
    int size = cdr(c) -> cons_size();
    //when one argument, return itself.
    if (size == 1) {
      Cell* result = eval(car(cdr(c)));
      judge_nil_cell(result,oper);
      result = result -> oper_less(nil);
      delete oper_cell;
      return result;
    }
    Cell* this_elem = cdr(c);
    Cell* next_elem = cdr(cdr(c));
    int condition = 1;
    for (int i=1; i<size; i++) {
      Cell* next_temp = eval(car(next_elem));
      judge_nil_cell(next_temp,oper);
      Cell* this_temp = eval(car(this_elem));
      judge_nil_cell(this_temp,oper);
      Cell* judge_cell = this_temp -> oper_less(next_temp);
      // if there is one pair such that 'this' bigger than 'next', condition will be zero
      condition *= get_int(judge_cell); 
      // delete temporary cell
      delete judge_cell;
      delete this_temp;
      delete next_temp;
      this_elem = cdr(this_elem);
      next_elem = cdr(next_elem);
    }
    delete oper_cell;
    return make_int(condition);
  }

  /**
   * the not operator
   * using oper_not(), which is a virtual function in Cell.
   */
  if (oper == "not") {
    judge_num_argu(c,oper);
    Cell* operand = eval(car(cdr(c)));
    if (nullp(operand)) {
      delete oper_cell;
      return make_int(0);
    }
    Cell* result = operand -> oper_not();
    delete operand;
    delete oper_cell;
    return result;
  }

  /**
   * the print operator
   * print the result and return nil cell
   */
  if (oper == "print") {
    judge_num_argu(c,oper);
    Cell* result = eval(car(cdr(c)));
    if (nullp(result)) {
      cout << "()" << endl;
      return nil;
    }
    cout << *result << endl;
    delete oper_cell;
    delete result;
    return nil;
  }

  /**
   * the eval operator
   * evaluate the result and return nil
   */
  if (oper == "eval") {
    judge_num_argu(c,oper);
    Cell* expr = eval(car(cdr(c)));
    Cell* result = eval(expr);
    delete oper_cell;
    return result;
  }

  /**
   * the lambda operator
   * a new function
   */
  if (oper == "lambda") {
    judge_num_argu(c,oper);
    Cell* formal_m = nullp(car(cdr(c))) ? nil : car(cdr(c)) -> deep_copy();
    // since the formal part must be a symbol or list(can be empty)
    if (!listp(formal_m) && !symbolp(formal_m) && !nullp(formal_m)) {
      throw invalid_operand_error("the type of formal part should be list or symbol");
    }
    Cell* body_m = nullp(cdr(cdr(c))) ? nil : cdr(cdr(c)) -> deep_copy();
    delete oper_cell;
    return lambda(formal_m,body_m);
  }

  /**
   * the apply operator
   * followed by a function and a list of arguments
   */
  if (oper == "apply") {
    judge_num_argu(c,oper);
    Cell* procedure = eval(car(cdr(c)));
    if (!procedurep(procedure)) {
      throw invalid_operator_error("cannot apply a value that is not a function");
    }
    Cell* argu_list = eval(car(cdr(cdr(c))));
    if (!listp(argu_list)) {
      throw invalid_operand_error("the second operand after apply function must be a list");
    }
    Cell* result = procedure -> apply(argu_list);
    delete procedure;
    delete argu_list;
    delete oper_cell;
    return result;
  }


  /*
   * the let operator 
   * which allow define local variable before function definition
   */
  if (oper == "let") {
    judge_num_argu(c,oper);
    Cell* var_definition = car(cdr(c));
    Cell* func_body = car(cdr(cdr(c)));
    bstmap<string,Cell*> local_map;
    // According to the specification, the variable definition part must be list 
    if (!listp(var_definition)) {
      throw invalid_operand_error("In let function, the varible definition must be a list");
    }
    int size = car(var_definition) -> cons_size();
    for (int i=0; i<size; i++) {
      Cell* begin_cell = car(var_definition);
      if (!listp(begin_cell)) {
	throw invalid_operand_error("In let function, the varible definition must be a list");
      }
      int sub_size = begin_cell -> cons_size();
      // When you want to define a variable, you can only give a symbol and a value, so the size should be 2
      if (sub_size != 2) {
	throw wrong_num_argu_error("When define local variable, the size of list must be 2");
      }
      string key = get_symbol(car(begin_cell));
      Cell* argu = car(cdr(begin_cell));
      local_map.insert(make_pair(key,argu));
      var_definition = cdr(var_definition);
    }
    my_stack.push(local_map);
    return eval(func_body);
  }

  // If the oper is not the above primitive operator, then check whether they are in the global map
  // If it is, follow the similar step declared above
  if (symbol_table.count(oper)) {
    if (procedurep(symbol_table[oper])) {
      Cell* procedure = symbol_table[oper] -> deep_copy();
      Cell* argu_list = nullp(cdr(c)) ? nil : cdr(c) -> deep_copy();
      Cell* result = procedure -> apply(argu_list);
      delete oper_cell;
      delete procedure;
      delete argu_list;
      return result;
    }
  }
  throw invalid_operator_error("this operator is invalid");
}
Exemple #4
0
/**
 * \brief The evaluation function that calculates the parsed s-expression tree
 * \param c A constant pointer to a Cell instance, which is the root of the tree to be computed
 * \return A pointer to the Cell containing the final answer.
 */
Cell* eval(Cell* const c)
{
  if (nullp(c)) {
    error_handler("s-expression invalid: root of tree is nil");
  }

  if (intp(c) || doublep(c) || symbolp(c)){
    return deep_copy(c);
  }
  
  if (listp(c)) {
    //get car of c
    //using eval will automatically evaluate the subtree, if car(c) is itself a conspair
    Cell* car_value = eval(car(c));
    
    //if car is a symbol cell (it must, otherwise the eval() begins at wrong place)
    if (symbolp(car_value)){
      //get the symbol
      //case 1: +
      if (get_symbol(car_value) == "+"){
	
	//delete car_value as it's not needed any more
	delete car_value;

	//temporary sums variables
	double double_sum = 0;
	int int_sum = 0;
	bool sum_is_double = false;

	//Cell pointer to the current working cell
	Cell* current_cell = cdr(c);

	//iterate every cons pair until meet a nil cdr
	while (!nullp(current_cell)) {

	  //current_cell is not nil, and it should be a conspair
	  if (!listp(current_cell)) {
	    error_handler("cdr must be nil or conspair");
	  }

	  //pointer to the cell that contains the value to be added
	  //here eval could be used against a conspair or a int/double cell
	  Cell* value_cell = eval(car(current_cell));
	  
	  //deal with value_cell, see if it's int or not
	  if (intp(value_cell)) {
	    if (sum_is_double) {
	      double_sum += get_int(value_cell);
	    } else {
	      int_sum += get_int(value_cell);
	    }
	  } else if (doublep(value_cell)) {
	    //if value_cell is not a double cell
	    if (sum_is_double) {
	      double_sum += get_double(value_cell);
	    } else {
	      //migrate int_sum to double_sum and do related clean-ups
	      double_sum = int_sum;
	      int_sum = 0;
	      sum_is_double = true;
	      
	      double_sum += get_double(value_cell);
	    }
	  } else {
	    if (!nullp(value_cell)) delete value_cell;
	    error_handler("s-expression invalid: + operands invalid");
	  }
	  if (!nullp(value_cell)) delete value_cell;
	  //move current_cell forward;
	  current_cell = cdr(current_cell);
	}
	
	return sum_is_double ? make_double(double_sum) : make_int(int_sum);
      }
      //case 2: ceiling
      else if (get_symbol(car_value) == "ceiling") {
	//delete car_value as it's no longer needed
	delete car_value;

	//current working cell
	Cell* current_cell = cdr(c);

	if (nullp(current_cell) || !listp(current_cell)) error_handler("s-expression invalid: invalid ceiling operand!");

	if (!nullp(cdr(current_cell))) error_handler("s-expression invalid: ceiling on more than one operands");
	
	//take the ceiling and return
	Cell* returned_value = eval(car(current_cell));
	if (intp(returned_value)){
	  delete returned_value;
	  error_handler("s-expression invalid: ceiling on integer!");
	} else if (doublep(returned_value)){
	  int ceilinged_value = int(get_double(returned_value));
	  if (ceilinged_value < get_double(returned_value)) ++ceilinged_value;
	  delete returned_value;
	  return make_int(ceilinged_value);
	} else {
	  if(!nullp(returned_value)) delete returned_value;
	  error_handler("s-expression invalid: ceiling on symbol!");
	}
      }
      //case 3: if
      else if (get_symbol(car_value) == "if") {
	//delete car_value as it's no longer needed
	delete car_value;
	
	//temporary Cell pointers;
	Cell* condition = cdr(c);
	if (nullp(condition) || !listp(condition)) error_handler("s-expression invalid: condition is not a conspair");
	Cell* if_true = cdr(condition);
	if (nullp(if_true) || !listp(if_true)) error_handler("s-expression invalid: the true return value is not a cospair");
	Cell* if_false = cdr(if_true); 

	//directly return the second parameter if the third doesn't exist
	if (nullp(if_false)) {
	  return eval(car(if_true));
	} else {
	  if (!nullp(cdr(if_false))) error_handler("s-expression invalid: if operator on more than three operands");
	  
	  Cell* condition_cell = eval(car(condition));
	  bool flag = false;
	  
	  //retrieve values according to their types
	  if (intp(condition_cell)){
	    flag = get_int(condition_cell) ? true : false;
	  } else if (doublep(condition_cell)) {
	    flag = get_double(condition_cell) ? true : false;
	  } else if (symbolp(condition_cell)) {
	    flag = get_symbol(condition_cell)!="" ? true : false;
	  } else {
	    if(!nullp(car_value)) delete condition_cell;
	    error_handler("s-expression invalid: condition operand invalid to if");
	  }

	  if(!nullp(car_value)) delete condition_cell;
	  
	  return flag ? eval(car(if_true)) : eval(car(if_false));
	}
      } else {
	//delete car_value as it's no longer needed
	delete car_value;
	
	error_handler("s-expression invalid: operator not one of +, ceiling or if");
      }
    } else {
      //delete car_value as it's no longer needed
      if(!nullp(car_value)) delete car_value;
	
      //value_car is not a symbol cell
      error_handler("s-expression invalid: the first element of the tree/subtree is not a proper operator");
    }
  }
}