/*

SIMPLE x86 16 BIT C COMPILER...

Author: Matthew W. Coan
Date: Tue Oct  1 20:49:22 EDT 2013

*/

#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <sstream>


namespace cc16 {


using namespace std;


enum token_type {
   T_KEYWORD,
   T_OPERATOR, 
   T_IDENTIFIER,  
   T_INT,
   T_FLOAT,
   T_DOUBLE,
   T_LONG,
   T_SHORT,
   T_CHAR,
   T_STRING,
   T_UNKNOWN,
};


enum { DATA_WORD_SIZE = 2 };


class syntax_exception {
public:
   int line_number;
   const char * message;
   syntax_exception(int ln, const char * msg) { 
      line_number = ln; 
      message = msg;
   }
};


class io_exception { 
public:
   const char * message;
   io_exception(const char * msg) {
      message = msg;
   }
};


class lex_exception { 
public:
   int line_number;
   lex_exception(int ln) {
      line_number = ln;
   }
};


class token {
public:
   string value;
   token_type type;
   int lineno;
   string file;
 
   token() { type = T_UNKNOWN; }
   token(const token & tok) { file = tok.file; value = tok.value; type = tok.type; lineno = tok.lineno; }
   token(const string & v, token_type t, int lno, const string & f) { file = f; value = v; type = t; lineno = lno; }
   ~token() { }


   token & operator=(const token & right) {
      value = right.value;
      type = right.type;
      lineno = right.lineno;
      file = right.file;
      return *this;
   }
};


class instruction {
public:
   string label;
   string op;
   string arg1;
   string arg2;


   instruction() {
   }


   instruction(const string & op,
               const string & arg1,
               const string & arg2) {
      this->op = op;
      this->arg1 = arg1;
      this->arg2 = arg2;
   }


   instruction(const string & label,
               const string & op,
               const string & arg1,
               const string & arg2) {
     this->label = label;
     this->op = op;
     this->arg1 = arg1;
     this->arg2 = arg2;
   }
};


class struc;


map< string, struc * > * p_struc_map = 0;


typedef vector< instruction* > instruction_vector_type;


int get_struct_size(const string & name);

typedef vector< size_t > size_vector_type;

class var {
public:
   string type;
   string name;
   string value;
   size_t address;
   size_vector_type size_vec;
   size_t array_size() {
      size_t sz = 1, i;
      for(i = 0; i < size_vec.size(); i++) {
         sz *= size_vec[i];
      }
      return sz;
   }
   var() { address = 0; }
   var(const string & type,
       const string & name) {
      address = 0;
      this->type = type;
      this->name = name;
   }
   size_t size() {
      size_t sz = 0;
      if(type.find("*") != string::npos) {
         sz = 2;
      }
      else if(type.find("char") != string::npos) {
         sz = 1;
      }
      else if(type.find("short") != string::npos) {
         sz = 2;
      }
      else if(type.find("int") != string::npos) {
         sz = 4;
      }
      else if(type.find("float") != string::npos) {
         sz = 4;
      }
      else if(type.find("long") != string::npos) {
         sz = 8;
      }
      else if(type.find("double") != string::npos) {
         sz = 8;
      }
      else if(type.find("struct") != string::npos) {
         sz = get_struct_size(type);
      }
      else {
         sz = 2;
      }
      return sz;
   }
};


typedef map< string, var* > var_map_type;
typedef vector< var* > var_vector_type;

class function {
public:
   string name;
   string return_type;
   var_map_type var_map;
   var_vector_type var_vec;
   var_map_type param_map;
   var_vector_type param_vec;
   instruction_vector_type code;
};


class struc {
public:
   string name;
   var_vector_type var_vec;
   size_t size() {
      size_t ret = 0;
      for(size_t i = 0; i < var_vec.size(); i++) {
         ret += var_vec[i]->size() * var_vec[i]->array_size();
      }
      return ret;
   }
   string get_type(const string & str) {
      string ret;
      for(size_t i = 0; i < var_vec.size(); i++) {
         if(var_vec[i]->name == str) {
            ret = var_vec[i]->type;
            break;
         }
      }
      return ret;
   }
   var * get_var(const string & str) {
      var * ret;
      for(size_t i = 0; i < var_vec.size(); i++) {
         if(str == var_vec[i]->name) {
            ret = var_vec[i];
            break;
         }
      }
      return ret;
   }
};

string get_struct_name(const string & name);

int get_struct_size(const string & name) 
{
   int index = name.find(" ");
   index++;
   string nam = name.substr(index);
   nam = get_struct_name(nam);
   struc * p_struc = (*p_struc_map)[nam];
   size_t sz = 0;
   if(p_struc) {
      sz = p_struc->size();
   }
   if(sz == 0) {
      sz = 1;
   }
   return sz;
}

string get_struct_name(const string & name) 
{
   char * buffer = new char [ name.size() + 1 ];
   memset(buffer, 0, name.size() + 1);
   strcpy(buffer, name.c_str());
   string ret;
   char * ptr = strtok(buffer, " ");
   while(ptr != NULL) {
      if(strcmp(ptr, "struct") != 0 && strcmp(ptr, "*") != 0) {
         ret += ptr;
      }
      ptr = strtok(NULL, " ");
   }
   delete [] buffer;
   return ret;
}

typedef vector< string > string_vector_type;
typedef vector< token* > token_vector_type;
typedef vector< instruction* > instruction_vector_type;
typedef map< string, function* > function_map_type;
typedef map< string, struc* > struc_map_type;
typedef map< string, string > const_map_type;
typedef map< string, string > string_map_type;
typedef map< string, bool > pf_map_type;

enum { MAX_ERROR_MESSAGES = 10 };

class c_compiler {
   string infile;
   string outfile;
   const_map_type const_map;
   var_map_type var_map;
   var_map_type global_map;
   var_vector_type global_var_vec;
   function_map_type function_map;
   instruction_vector_type code;
   struc_map_type struc_map;
   token_vector_type token_vec;
   string_vector_type const_data;
   size_t count;
   size_t temp_count;
   size_t allocate_index;
   string_vector_type extern_vec;
   string_vector_type global_vec;
   size_t stk_size;
   size_t label_count;
   string loop_end;
   string loop_cond;
   struc * p_struct;
   bool get_addr;
   bool get_value;
   bool on_right;
   function * p_fun;
   string_map_type typedef_map;
   pf_map_type pf_map;
   string last_type;
   bool in_expression_list;
   string_vector_type error_vec;
   string_vector_type warning_vec;
   bool l_val;
   bool r_val;
   //bool in_expression;
   int n_expr;

   void error(const size_t offset, const char * message) {
      string file = token_vec[offset]->file;
      int lineno = token_vec[offset]->lineno;
      error_vec.push_back(
      "error: " + file + ": " + to_string(lineno) + ": " + message);
      if(error_vec.size() >= MAX_ERROR_MESSAGES) {
         throw syntax_exception(lineno,message);
      }
   }

   void warning(const size_t offset, const char * message) {
      string file = token_vec[offset]->file;
      int lineno = token_vec[offset]->lineno;
      error_vec.push_back(
      "warning: " + file + ": " + to_string(lineno) + ": " + message);
      if(error_vec.size() >= MAX_ERROR_MESSAGES) {
         throw syntax_exception(lineno,message);
      }
   }

   bool is_keyword(const string & id) {
      bool ret = false;
      if(id == "case"
         || id == "break"
         || id == "while"
         || id == "for"
         || id == "do"
         || id == "if"
         || id == "else"
         || id == "switch"
         || id == "struct"
         || id == "union"
         || id == "typedef"
         || id == "goto"
         || id == "return"
         || id == "continue"
         || id == "default"
         || id == "sizeof") {
         ret = true;
      }
      else if(id == "void"
         || id == "char"
         || id == "short"
         || id == "int"
         || id == "long"
         || id == "float"
         || id == "double"
         || id == "unsigned"
         || id == "register"
         || id == "signed"
         || id == "volatile"
         || id == "static"
         || id == "extern"
         || id == "const") {
         ret = true;
      }
      return ret;
   }


   string remove(const string & str, 
                 const string & tok) {
      char * buffer = new char[str.size()+1];
      memset(buffer, 0, str.size()+1); 
      strcpy(buffer, str.c_str());
      char * ptr;
      while((ptr = strstr(buffer, tok.c_str())) != NULL) {
         strcpy(ptr, ptr + tok.size());
      }
      string ret = buffer;
      delete [] buffer;
      return ret;
   }


   string to_code(const string & str) {
      string ret;
      for(size_t i = 0; i < str.size(); i++) {
         if(str[i] == '\"' && (i == str.size()-1 || i == 0)) {
            ret += '\'';
         }
         else if(str[i] == '\"') {
            ret += "\"";
         }
         else if(str[i] == '\\' && str[i+1] == 'n') {
            ret += "\',10,\'";
            i++;
         }
         else if(str[i] == '\\' && str[i+1] == 'r') {
            ret += "\',13,\'";
            i++;
         }
         else {
            ret += str[i];
         }
      }
      ret += ",0";
      ret = remove(ret, "\'\',");
      return ret;
   }
   string get_string_const(const string & str) {
      if(const_map.find(str) != const_map.end()) {
         return const_map[str];
      }
      stringstream s;
      s << "C";
      s << count;
      count++;
      string ret;
      s >> ret;
      const_map[str] = ret;
      const_data.push_back(ret + ": db " + to_code(str));
      return ret;
   }


public:
   c_compiler(const string & infile, 
              const string & outfile) {
      count = 0;
      this->infile = infile;
      this->outfile = outfile;
      label_count = 0;
      p_struct = 0;
      p_struc_map = &struc_map;
      get_addr = false;
      get_value = false;
      on_right = false;
      p_fun = 0;
      temp_count = 0;
      allocate_index = 0;
      in_expression_list = false;
      //in_expression = false;
      stk_size = 0;
      l_val = false;
      r_val = false;
   }
   bool match(const string & value, const size_t offset) {
      if(offset < token_vec.size()) {
         return token_vec[offset]->value == value;
      }
      return false;
   }
   bool match(const token_type type, const size_t offset) {
      if(offset < token_vec.size()) {
         return token_vec[offset]->type == type;
      }
      return false;
   }
   void add_instruction(const string & label, const string & op, const string & arg1, const string & arg2) {
      code.push_back(new instruction(label, op, arg1, arg2));
      if(p_fun) {
         p_fun->code.push_back(code[code.size()-1]);
      }
   }
   void add_instruction(const string & op, const string & arg1, const string & arg2 = "") {
      code.push_back(new instruction(op, arg1, arg2));
      if(p_fun) {
         p_fun->code.push_back(code[code.size()-1]);
      }
   }
   void add_instruction(instruction * inst) {
      code.push_back(inst);
      if(p_fun) {
         p_fun->code.push_back(code[code.size()-1]);
      }
   }
   bool is_register(const string & reg) {
      bool ret = false;
      if(reg == "sp"
         || reg == "bp"
         || reg == "ax"
         || reg == "dx"
         || reg == "bx"
         || reg == "di"
         || reg == "si"
         || reg == "al"
         || reg == "ah"
         || reg == "cl"
         || reg == "cx"
         || reg == "gs"
         || reg == "cs"
         || reg == "ds") {
         ret = true;
      }
      return ret;
   }
   void optimize() {
      bool reduce = true;
      instruction_vector_type temp;


      reduce = true;
      string label;


      while(reduce) {
         reduce = false;
         temp.clear();
         for(function_map_type::iterator ptr = function_map.begin(); ptr != function_map.end(); ptr++) {
            p_fun = ptr->second;
            temp.clear();
            for(size_t i = 0; i < p_fun->code.size(); i++) {
               if(p_fun->code[i]->op == "sub" && p_fun->code[i]->arg2 == "0") {
                  reduce = true;
                  continue;
               }

               if((i+1) < p_fun->code.size()) {
                  if(p_fun->code[i]->op == "push" 
                     && p_fun->code[i+1]->op == "pop"
                     && p_fun->code[i]->arg1 == p_fun->code[i+1]->arg1) {
                     i++;
                     reduce = true;
                     continue;
                  }
               }

               // MATH REDUCER
               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "imul") {
                        if(is_register(p_fun->code[i]->arg1)
                           && is_register(p_fun->code[i+1]->arg1)) {
                           if(is_digit(p_fun->code[i]->arg2[0])
                              && is_digit(p_fun->code[i+1]->arg2[0])) {
                              if(p_fun->code[i]->label == ""
                                 && p_fun->code[i+1]->label == "") {
                                 if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg1) {
                                    p_fun->code[i]->arg2 = 
                                       to_string(atoi(p_fun->code[i]->arg2.c_str())
                                       * atoi(p_fun->code[i+1]->arg2.c_str()));
                                    temp.push_back(p_fun->code[i]);
                                    i++;
                                    reduce = true;
                                    continue;
                                 }
                              }
                           }
                        }
                     }
                  }
               }

               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "add") {
                        if(is_register(p_fun->code[i]->arg1)
                           && is_register(p_fun->code[i+1]->arg2)
                           && is_register(p_fun->code[i+1]->arg1)) {
                           if(is_digit(p_fun->code[i]->arg2[0])) {
                              if(p_fun->code[i]->label == ""
                                 && p_fun->code[i+1]->label == "") {
                                 if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg2) {
                                    p_fun->code[i+1]->arg2 = p_fun->code[i]->arg2;
                                    temp.push_back(p_fun->code[i+1]);
                                    i++;
                                    reduce = true;
                                    continue;
                                 }
                              }
                           }
                        }
                     }
                  }
               }

               // END MATH REDUCER
               if(p_fun->code[i]->op == "push") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "pop" 
                        && is_register(p_fun->code[i+1]->arg1)) {
                        temp.push_back(new instruction(label, "mov", p_fun->code[i+1]->arg1, p_fun->code[i]->arg1));
                        i++;
                        reduce = true;
                        continue;
                     }
                  }
               }

               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if((i+2) < p_fun->code.size()) {
                           if(p_fun->code[i+2]->op == "mov") {
                              if(p_fun->code[i]->label == ""
                                 && p_fun->code[i+1]->label == ""
                                 && p_fun->code[i+2]->label == ""
                                 && is_register(p_fun->code[i]->arg1)
                                 && is_register(p_fun->code[i+1]->arg1)
                                 && is_register(p_fun->code[i+2]->arg2)) {
                                 if(p_fun->code[i]->arg1 == p_fun->code[i+2]->arg2) {
                                    if(("[" + p_fun->code[i+1]->arg1 + "]") == p_fun->code[i+2]->arg1) {
                                       if(is_register(p_fun->code[i]->arg1)) {
                                          if(!(p_fun->code[i]->arg2.find("[") != string::npos
                                             && p_fun->code[i+2]->arg1.find("[") != string::npos)) {
                                             p_fun->code[i+2]->arg2 = p_fun->code[i]->arg2;
                                             temp.push_back(p_fun->code[i+1]);
                                             temp.push_back(p_fun->code[i+2]);
                                             i += 2;
                                             reduce = true;
                                             continue;
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                        }
                     }
                  }
               }


               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if((i+2) < p_fun->code.size()) {
                           if(p_fun->code[i+2]->op == "cmp") {
                              if(p_fun->code[i]->arg1 == p_fun->code[i+2]->arg2) {
                                 if(is_register(p_fun->code[i]->arg1)) {
                                    p_fun->code[i+2]->arg2 = p_fun->code[i]->arg2;
                                    temp.push_back(p_fun->code[i+1]);
                                    temp.push_back(p_fun->code[i+2]);
                                    i += 2;
                                    reduce = true;
                                    continue;
                                 }
                              }
                           }
                        }
                     }
                  }
               }


               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg2
                           && p_fun->code[i]->arg2 == p_fun->code[i+1]->arg1) {
                           if(is_register(p_fun->code[i]->arg1) && is_register(p_fun->code[i+1]->arg2)) {
                              temp.push_back(new instruction(label, "mov", p_fun->code[i+1]->arg1, p_fun->code[i]->arg2));
                              i++;
                              reduce = true;
                              continue;
                           }
                        }
                     }
                  }
               }

               if(p_fun->code[i]->op == "mov" && is_register(p_fun->code[i]->arg1)) {
                  if((i+1) < p_fun->code.size()) {
                     if(is_digit(p_fun->code[i]->arg2[0])
                        || p_fun->code[i]->arg2.find("\'") != string::npos) {
                        if(p_fun->code[i+1]->op == "mov" 
                           && is_register(p_fun->code[i]->arg1)
                           && is_register(p_fun->code[i+1]->arg2)) {
                           if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg2) {
                              temp.push_back(new instruction(label, "mov", p_fun->code[i+1]->arg1, p_fun->code[i]->arg2));
                              i++;
                              reduce = true;
                              continue;
                           }
                        }
                     }
                  }
               }

               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg2
                           && is_register(p_fun->code[i]->arg2) 
                           && is_register(p_fun->code[i+1]->arg2)) {
                           temp.push_back(new instruction(label, "mov", p_fun->code[i+1]->arg1, p_fun->code[i]->arg2));
                           i++;
                           reduce = true;
                           continue;
                        }
                     }
                  }
               }

               if(p_fun->code[i]->op == "mov") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if(p_fun->code[i]->arg2 == p_fun->code[i+1]->arg1
                           && is_register(p_fun->code[i]->arg1)
                           && is_register(p_fun->code[i+1]->arg2)) {
                           temp.push_back(new instruction(label, "mov", p_fun->code[i]->arg1, p_fun->code[i]->arg2));
                           i++;
                           reduce = true;
                           continue;
                        }
                     }
                  }
               }
/**/
               if(p_fun->code[i]->op == "push") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "lea") {
                        if((i+2) < p_fun->code.size()) {
                           if(is_register(p_fun->code[i+2]->arg1)) {
                              if(p_fun->code[i+2]->op == "pop") {
                                 if(p_fun->code[i]->arg1 == p_fun->code[i+2]->arg1) {
                                    temp.push_back(p_fun->code[i+1]);
                                    temp.push_back(new instruction(label, "mov", 
                                    p_fun->code[i+2]->arg1, p_fun->code[i]->arg1));
                                    i += 2;
                                    reduce = true;
                                    continue;
                                 }
                              }
                           }
                        }
                     }
                  }
               }
/**/
               if(p_fun->code[i]->op == "push") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if((i+2) < p_fun->code.size()) {
                           if(p_fun->code[i+2]->op == "pop"
                              && p_fun->code[i]->arg1 == p_fun->code[i+2]->arg1) {
                              temp.push_back(p_fun->code[i+1]);
                              i += 2;
                              reduce = true;
                              continue;
                           }
                        }
                     }
                  }
               }

/**/
               if(p_fun->code[i]->op == "push") {
                  if((i+1) < p_fun->code.size()) {
                     if(p_fun->code[i+1]->op == "mov") {
                        if((i+2) < p_fun->code.size()) {
                           if(p_fun->code[i+2]->op == "pop") {
                              if(p_fun->code[i]->arg1 == p_fun->code[i+2]->arg1) {
                                 temp.push_back(p_fun->code[i+1]);
                                 temp.push_back(new instruction(label, "mov", 
                                       p_fun->code[i+2]->arg1, p_fun->code[i]->arg1));
                                 i += 2;
                                 reduce = true;
                                 continue;
                              }
                           }
                        }
                     }
                  }
               }
/**/

               if((i+6) < p_fun->code.size()) {
                  if(p_fun->code[i]->op == "push") {
                     if(p_fun->code[i+1]->op == "jmp"
                        || p_fun->code[i+1]->op == "je"
                        || p_fun->code[i+1]->op == "jne"
                        || p_fun->code[i+1]->op == "jl"
                        || p_fun->code[i+1]->op == "jg"
                        || p_fun->code[i+1]->op == "jle"
                        || p_fun->code[i+1]->op == "jge") {
                        if(p_fun->code[i+2]->label != "") {
                           if(p_fun->code[i+3]->op == "push") {
                              if(p_fun->code[i+4]->label != "") {
                                 if(p_fun->code[i+5]->op == "pop") {
                                    if(p_fun->code[i+6]->op == "cmp") {
                                       p_fun->code[i]->op = "mov";
                                       p_fun->code[i]->arg2 = p_fun->code[i]->arg1;
                                       p_fun->code[i]->arg1 = "ax";


                                       p_fun->code[i+3]->op = "mov";
                                       p_fun->code[i+3]->arg2 = p_fun->code[i+3]->arg1;
                                       p_fun->code[i+3]->arg1 = "ax";


                                       p_fun->code[i+5]->op = "mov";
                                       p_fun->code[i+5]->arg2 = p_fun->code[i+5]->arg1;
                                       p_fun->code[i+5]->arg1 = "ax";




                                       temp.push_back(p_fun->code[i]);
                                       temp.push_back(p_fun->code[i+1]);
                                       temp.push_back(p_fun->code[i+2]);
                                       temp.push_back(p_fun->code[i+3]);
                                       temp.push_back(p_fun->code[i+4]);
                                       temp.push_back(p_fun->code[i+5]);
                                       temp.push_back(p_fun->code[i+6]);
                              
                                       i += 5;
                                       reduce = true;
                                       continue;
                                    }
                                 }
                              }
                           }
                        }
                     }
                  }
               }


               if(p_fun->code[i]->op == "mov") {
                  if(p_fun->code[i]->arg1 == p_fun->code[i]->arg2) {
                     if(is_register(p_fun->code[i]->arg1) && is_register(p_fun->code[i]->arg2)) {
                        i++;
                        reduce = true;
                        continue;
                     }
                  }
               }


               if(p_fun->code[i]->op == "mov") {
                  if(p_fun->code[i+1]->op == "push") {
                     if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg1) {
                        if(is_register(p_fun->code[i]->arg1)
                           && p_fun->code[i]->arg2 != "[di]") {
                           if(p_fun->code[i+1]->arg1 == "al"
                              || p_fun->code[i+1]->arg1 == "ah") {
                              temp.push_back(new instruction(label, "push", 
                              "byte " + p_fun->code[i]->arg2, ""));
                           }
                           else {
                              temp.push_back(new instruction(label, "push", 
                              "word " + p_fun->code[i]->arg2, ""));
                           }
                           reduce = true;
                           i++;
                           continue;
                        }
                     }
                  }
               }


               if(p_fun->code[i]->op == "cpush") {
                  if((i+1) < p_fun->code.size())  {
                     if(p_fun->code[i+1]->op == "cpop") {
                        if(p_fun->code[i]->arg1 == p_fun->code[i+1]->arg1) {
                           i++;
                           reduce = true;
                           continue;
                        }
                     }
                  }
               }

               temp.push_back(p_fun->code[i]);
            }
            if(reduce == true) {
               break;
            }
         }
         p_fun->code = temp;
      }
   }
   int run() {
      int ret = 0;
      lex();
      parse();
      if(error_vec.size() == 0) {
         //optimize();
         emit();
         ret = 0;
      }
      else {
         for(size_t i = 0; i < error_vec.size(); i++) {
            cerr << error_vec[i] << endl;
         }
         ret = 1;
      }
      for(size_t i = 0; i < warning_vec.size(); i++) {
         cerr << warning_vec[i] << endl;
      }
      return ret;
   }
   bool is_operator(const char ch) {
      bool ret = false;
      if(ch == ';'
         || ch == ':'
         || ch == ','
         || ch == '.'
         || ch == '('
         || ch == ')'
         || ch == '['
         || ch == ']'
         || ch == '='
         || ch == '<'
         || ch == '>'
         || ch == '|'
         || ch == '&'
         || ch == '!'
         || ch == '^'
         || ch == '~'
         || ch == '-'
         || ch == '+'
         || ch == '*'
         || ch == '/'
         || ch == '%'
         || ch == '{'
         || ch == '}'
         || ch == '?') {
         ret = true;
      } 
      return ret;
   }
   bool is_digit(const char ch) {
      bool ret = false;
      if(ch >= '0' && ch <= '9') {
         ret = true;
      }
      return ret;
   }
   bool is_letter(const char ch) {
      bool ret = false;
      if((ch >= 'A' && ch <= 'Z')
         || (ch >= 'a' && ch <= 'z')) {
         ret = true;
      }
      return ret;
   }
   bool is_space(const char ch) {
      bool ret = false;
      if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
         ret = true;
      }
      return ret;
   }
   void lex() {
      char ch;
      string str,file = infile;
      int lineno = 1;
      ifstream fin(infile.c_str(), ios::in);
      if(fin) {
         ch = fin.get();
         while(fin) {
            if(is_digit(ch)) {
               str = "";
               while(is_digit(ch) || ch == '.') {
                  str += ch;
                  ch = fin.peek();
                  if(!is_digit(ch) && ch != '.') break;
                  ch = fin.get();
               }
               if(str.find(".") != string::npos) {
                  token_vec.push_back(new token(str, T_DOUBLE, lineno, file));
               }
               else {
                  token_vec.push_back(new token(str, T_INT, lineno, file));
               }
            }
            else if(is_letter(ch) || ch == '_') {
               str = "";
               while(is_letter(ch) || is_digit(ch) || ch == '_') {
                  str += ch;
                  ch = fin.peek();
                  if(!is_letter(ch) && !is_digit(ch) && ch != '_') break;
                  ch = fin.get();
               }
               if(is_keyword(str)) {
                  token_vec.push_back(new token(str, T_KEYWORD, lineno, file));
               }
               else {
                  str = "_" + str;
                  token_vec.push_back(new token(str, T_IDENTIFIER, lineno, file));
               }
            }
            else if(is_operator(ch)) {
               str = "";
               while(is_operator(ch)) {
                  str += ch;
                  ch = fin.peek();
                  if(ch == '('
                     || ch == ')'
                     || ch == '*'
                     || ch == ';'
                     || ch == ','
                     || ch == '{'
                     || ch == '}'
                     || ch == '['
                     || ch == ']'
                     || ch == '&'
                     || ch == '.') {
                     if(ch == '&' && str == "&") {
                        ch = fin.get();
                        str += ch;
                     }
                     break;
                  }
                  if(!is_operator(ch)) break;
                  ch = fin.get();
               }
               token_vec.push_back(new token(str, T_OPERATOR, lineno, file));
            }
            else if(ch == '\'') {
               str = "\'";
               ch = fin.get();
               do {
                  str += ch;
                  ch = fin.get();
               }
               while(ch != '\'');
               str += "\'";
               if(str == "\'\\\"\'") {
                  token_vec.push_back(new token("\'\"\'", T_CHAR, lineno, file));
               }
               else if(str == "\'\\t\'") {
                  token_vec.push_back(new token("\'\\t\'", T_CHAR, lineno, file));
               }
               else if(str == "\'\\r\'") {
                  token_vec.push_back(new token("13", T_CHAR, lineno, file));
               }
               else if(str == "\'\\n\'") {
                  token_vec.push_back(new token("10", T_CHAR, lineno, file));
               }
               else if(str == "\'\\b\'") {
                  token_vec.push_back(new token("8", T_CHAR, lineno, file));
               }
               else if(str == "\'\\0\'") {
                  token_vec.push_back(new token("0", T_CHAR, lineno, file));
               }
               else {
                  //stringstream s;
                  //s << (int)str[1];
                  //s >> str;
                  token_vec.push_back(new token(str, T_CHAR, lineno, file));
               }
            }
            else if(ch == '\"') {
               str = "\"";
               ch = fin.get();
               while(ch != '\"') {
                  if(ch == '\\') {
                    ch = fin.peek();
                    if(ch == '\"') {
                       ch = fin.get();
                    }
                    else {
                       str += "\\";
                       ch = fin.get();
                    }
                  }
                  str += ch;
                  ch = fin.peek();
                  if(ch == '\"') break;
                  ch = fin.get();
               }
               ch = fin.get();
               str += "\"";
               token_vec.push_back(new token(str, T_STRING, lineno, file));
            }
            else if(is_space(ch)) {
               if(ch == '\n') {
                  lineno++;
               }
            }
            else if(ch == '#') {
               string temp;
               while(ch != '\n' && fin) {
                  temp += ch;
                  ch = fin.get();
               }
               stringstream str;
               str << temp;
               string line;
               str >> temp >> line >> file;
               if(file.size() >= 2) {
                  file = file.substr(1, file.size()-2);
               }
               lineno = atoi(line.c_str());
            }
            else {
               throw lex_exception(lineno);
            }
            ch = fin.get();
         }
         fin.close();
      }
      else {
         throw io_exception("error: opening input file...");
      }
/*
      for(size_t i = 0; i < token_vec.size(); i++) {
         cout << "token_vec[" << i << "] == \"" << token_vec[i]->value << "\"" << endl << flush;
      }
*/
   }
   void parse() {
      size_t offset = 0;
      while(global_statement(offset)) {
         cout << "GLOBAL STATEMENT..." << endl;
         cout << "OFFSET: " << offset << endl;
         cout << "SIZE: " << token_vec.size() << endl;
      }
      cout << "done parse..." << endl;
   }
   void emit() {
      bool my_os = true;
      ofstream fout(outfile.c_str(), ios::ate | ios::trunc | ios::out);
      if(fout) {
         if(!my_os) {
            fout << "[BITS 16]" << endl;
            fout << "[section .text]" << endl << endl;
            fout << "org 100h" << endl << endl;
            fout << "start:" << endl;
            fout << "jmp _main" << endl << endl;
         }
         if(my_os) {
            fout << "[BITS 16]" << endl;
            fout << "[org 0]" << endl;
            fout << "[section .text]" << endl << endl;
            fout << "start:" << endl;
            fout << "\tmov ax,cs" << endl;
            fout << "\tmov ds,ax" << endl;
            fout << "\tmov es,ax" << endl << endl;

            fout << "\tmov ah,03" << endl;
            fout << "\tmov bh,0" << endl;
            fout << "\tint 10h" << endl << endl;
         }

         fout << "\tcall _main" << endl << endl;

         if(my_os) {
            fout << "\tjmp 0x1000:0" << endl << endl;
         }

         size_t i;
         for(i = 0; i < global_vec.size(); i++) {
            fout << "global " << global_vec[i] << endl;
         }
         bool found;
         for(i = 0; i < extern_vec.size(); i++) {
            found = false;
            for(size_t j = 0; j < global_vec.size(); j++) {
               if(extern_vec[i] == global_vec[j]) {
                  found = true;
                  break;
               }
            }
            if(!found) {
               fout << "global " << extern_vec[i] << endl;
            }
         }
         fout << endl;
         fout << "[segment .text]" << endl << endl;
         fout << "%include \"io.asm\"" << endl;
         if(!my_os) {
            fout << "%include \"libc.asm\"" << endl;
         }
         fout << endl;
         for(struc_map_type::iterator ptr = struc_map.begin(); ptr != struc_map.end(); ptr++) {
            if(ptr->second == 0) continue;
            fout << "struc " << ptr->second->name << endl;
            for(size_t i = 0; i < ptr->second->var_vec.size(); i++) {
               fout << "   ." << ptr->second->var_vec[i]->name;
               if(ptr->second->var_vec[i]->type.find("*") != string::npos
                  || ptr->second->var_vec[i]->type.find("short") != string::npos) {
                  fout << " resw 1" << endl;
               }
               else if(ptr->second->var_vec[i]->type.find("int") != string::npos
                       && ptr->second->var_vec[i]->type.find("float") != string::npos) {
                  fout << " resd 1" << endl;
               }
               else if(ptr->second->var_vec[i]->type.find("char") != string::npos) {
                  fout << " resb " << ptr->second->var_vec[i]->array_size() << endl;
               }
               else if(ptr->second->var_vec[i]->type.find("long") != string::npos
                       || ptr->second->var_vec[i]->type.find("double") != string::npos) {
                  fout << " resq 1" << endl;
               }
               else if(ptr->second->var_vec[i]->type.find("struct") != string::npos) {
                  struc * ps = struc_map[get_struct_name(ptr->second->var_vec[i]->type)];
                  if(ps) {
                     fout << " resb " << ps->size() << endl;
                  }
                  else {
                     fout << " resw 1" << endl;
                  }
               }
               else {
                  fout << " resw 1" << endl;
               }
            }
            fout << "endstruc" << endl << endl;
         }
         fout << endl;
         for(function_map_type::iterator ptr2 = function_map.begin(); ptr2 != function_map.end(); ptr2++) {
            if(ptr2->second->code.size() == 0) continue;
            int address = 0;
            var_map_type::iterator ptr;
            size_t index;
            for(index = 0; index < ptr2->second->var_vec.size(); index++) {
               address -= ptr2->second->var_vec[index]->size() * ptr2->second->var_vec[index]->array_size();
               fout << "%define " <<  ptr2->second->var_vec[index]->name << " " << address << endl;
            }
            address = 4;
            for(index = 0; index < ptr2->second->param_vec.size(); index++) {
               if(global_map.find(ptr2->second->param_vec[index]->name) == global_map.end()) {
                  fout << "%define " << ptr2->second->param_vec[index]->name << " " << address << endl;
                  address += ptr2->second->param_vec[index]->size();
               }
            }
            fout << endl;
            p_fun = ptr2->second;
            fout << p_fun->name << ":" << endl;
            fout << "\tpush bp" << endl;
            fout << "\tmov bp,sp" << endl;
            for(size_t i = 0; i < p_fun->code.size(); i++) {
               if(p_fun->code[i]->label != "") {
                  fout << p_fun->code[i]->label << ":";
               }
               if(p_fun->code[i]->arg1 == "" && p_fun->code[i]->arg2 == "") {
                  fout << "\t" << p_fun->code[i]->op << endl;
               }
               else if(p_fun->code[i]->arg1 != "" && p_fun->code[i]->arg2 == "") {
                  fout << "\t" << p_fun->code[i]->op << " " 
                       << p_fun->code[i]->arg1 << endl;
               }
               else if(p_fun->code[i]->arg1 != "" && p_fun->code[i]->arg2 != "") {
                  if(is_digit(p_fun->code[i]->arg2[0])) {
                     if(p_fun->code[i]->arg1 == "al"
                        || p_fun->code[i]->arg1 == "ah") {
                        fout << "\t" << p_fun->code[i]->op << " " 
                             << p_fun->code[i]->arg1 << ",byte " 
                             << p_fun->code[i]->arg2 << endl;
                     } 
                     else {
                        fout << "\t" << p_fun->code[i]->op << " " 
                             << p_fun->code[i]->arg1 << ",word " 
                             << p_fun->code[i]->arg2 << endl;
                     }
                  }
                  else {
                     fout << "\t" << p_fun->code[i]->op << " " 
                          << p_fun->code[i]->arg1 << "," 
                          << p_fun->code[i]->arg2 << endl;
                  }
               }
               else {
                  fout << "\t" << p_fun->code[i]->op << " " 
                       << p_fun->code[i]->arg1 << endl;
               }
            }
            bool flag = false;
            if(p_fun->code.size() >= 2) {
               if(p_fun->code[p_fun->code.size()-1]->op == "ret") {
                  if(p_fun->code[p_fun->code.size()-2]->op == "leave") {
                     flag = true;
                  }
               }
            }
            if(!flag) {
               fout << "\tleave" << endl;
               fout << "\tret" << endl << endl;
            }
            for(index = 0; index < ptr2->second->var_vec.size(); index++) {
               fout << "%undef " <<  ptr2->second->var_vec[index]->name << endl;
            }
            for(index = 0; index < ptr2->second->param_vec.size(); index++) {
               if(global_map.find(ptr2->second->param_vec[index]->name) == global_map.end()) {
                  fout << "%undef " << ptr2->second->param_vec[index]->name << endl;
               }
            }
            fout << endl;
         }
         fout << endl;

         fout << endl;
         fout << "[section .data]" << endl << endl;
         if(!my_os) {
            fout << "hex db \"0x0000\",10,13,0" << endl;
            fout << "hexc db \"0123456789ABCDEF\"" << endl;
            fout << "C100: db 'OPEN NEXT...',13,10,0" << endl;
            fout << "C101: db 'READ NEXT...',13,10,0" << endl;
            fout << "C102: db 'CLOSE NEXT...',13,10,0" << endl;
            fout << "filename: db 'hello16',0" << endl;
         }

         for(i = 0; i < const_data.size(); i++) {
            fout << const_data[i] << endl;
         }
         fout << endl;

         fout << "[section .bss]" << endl << endl;
         if(!my_os) {
            fout << "file: resw 1" << endl;
            fout << "buffer: resw 1" << endl;
            fout << "temp_word: resd 1" << endl;
         }
         if(!my_os) {
            fout << "the_ch: resw 1" << endl;
         }
         fout << "answer: resb 20" << endl;
         for(i = 0; i < global_var_vec.size(); i++) {
            if(global_var_vec[i]->type.find("*") != string::npos) {
               fout << global_var_vec[i]->name << ": resw 1" << endl;
            }
            else if(global_var_vec[i]->type == "short") {
               fout << global_var_vec[i]->name << ": resw 1" << endl;
            }
            else if(global_var_vec[i]->type == "char") {
               fout << global_var_vec[i]->name << ": resb 1" << endl;
            }
            else if(global_var_vec[i]->type == "int") {
               fout << global_var_vec[i]->name << ": resd 1" << endl;
            }
            else if(global_var_vec[i]->type == "float") {
               fout << global_var_vec[i]->name << ": resd 1" << endl;
            }
            else if(global_var_vec[i]->type == "double") {
               fout << global_var_vec[i]->name << ": resq 1" << endl;
            }
            else if(global_var_vec[i]->type == "long") {
               fout << global_var_vec[i]->name << ": resq 1" << endl;
            }
            else {
               struc * p_struct;
               if(struc_map.find(global_var_vec[i]->type) != struc_map.end()) {
                  p_struct = struc_map[global_var_vec[i]->type];
                  fout << global_var_vec[i]->name << ": resb " 
                       << global_var_vec[i]->size() << endl;
               }
            }
         }
         fout.close();
      }
      else {
         throw io_exception("error: unable to open output file...");
      }
   } 
   string to_string(const size_t arg) {
      stringstream str;
      str << arg;
      string ret;
      str >> ret;
      return ret;
   }
   bool is_type_keyword(const size_t offset) {
      if(offset >= token_vec.size()) 
         return false;
      string word = token_vec[offset]->value;
      bool ret = false;
      if(typedef_map.find(word) != typedef_map.end()) {
         ret = true;
      }
      if(word == "char"
         || word == "short"
         || word == "int"
         || word == "long"
         || word == "float"
         || word == "double"
         || word == "void"
         || word == "unsigned"
         || word == "register"
         || word == "signed"
         || word == "register"
         || word == "volatile"
         || word == "static"
         || word == "extern"
         || word == "struct"
         || word == "const") {
         ret = true;
      }
      return ret;
   }

   string get_type(size_t & offset) {
      string type;


      if(match("struct", offset)) {
         type = "struct ";
         offset++;
         if(match(T_IDENTIFIER, offset)) {
            type += token_vec[offset]->value;
            offset++; 
            while(match("*", offset)) {
               type += " *";
               offset++;
            }
            return type;
         }
      }
      while(is_type_keyword(offset)) {
         if(type.size())
           type += " ";
         type += token_vec[offset]->value;
         offset++;
      }
      while(match("[", offset)) {
         if(type.size())
           type += " ";
         type += "[";
         offset++;
         if(match(T_INT, offset)) {
            type += token_vec[offset]->value;
            offset++;
         }
         if(match("]", offset)) {
            if(type.size())
               type += " ";
            type += "]";
            offset++;
         }
         else {
            error(offset, "epecting: \"]\"");
         }
      }
      if(type.size()) {
         while(match("*", offset)) {
            if(type.size())
               type += " ";
            type += token_vec[offset]->value;
            offset++;
         }
      }
cout << "get_type: \"" << type << "\"" << endl;
      return type;
   }
   bool global_statement(size_t & offset) {
      bool ret = false;
      size_t old_offset = offset;
      if(offset >= token_vec.size()) {
         return false;
      }
      offset = old_offset;
if(offset < token_vec.size()) {
cout << "TOKEN: \"" << token_vec[offset]->value << "\"" << endl;
}
      if(struct_statement(offset)) {
cout << "STRUCT..." << endl;
         return true;
      }
      offset = old_offset;
      if(union_statement(offset)) {
cout << "UNION..." << endl;
         return true;
      }
      offset = old_offset;
      if(typedef_statement(offset)) {
cout << "TYPEDEF..." << endl;
         return true;
      }
      offset = old_offset;
      if(function_decl_statement(offset)) {
cout << "FUNCTION DECL..." << endl;
         return true;
      }
      offset = old_offset;
      if(function_def_statement(offset)) {
cout << "FUNCTION DEF..." << endl;
         return true;
      }
      offset = old_offset;
      if(global_variable_statement(offset)) {
cout << "GLOBAL VARIABLE STATEMENT..." << endl;
         return true;
      }
      offset = old_offset;
      return ret;
   }
   bool struct_variable_statement(size_t & offset) {
      bool ret = false;
      bool got_star = false;
      string type = get_type(offset);
      string ttype;
      if(type.size() == 0) return false;
      while(match(T_IDENTIFIER, offset)) {
         string id = token_vec[offset]->value;
         if(got_star) 
            ttype = type + " *";
         else
            ttype = type;
         got_star = false;
         var * v = new var(ttype, id);
         p_struct->var_vec.push_back(v);
         offset++;
         if(pf_map.find(ttype) != pf_map.end()) {
            pf_map[id] = true;
         }
         if(match("[", offset)) {
            while(match("[", offset)) {
               offset++;
               if(match(T_INT, offset)) {
                  v->size_vec.push_back(atoi(token_vec[offset]->value.c_str()));
                  offset++;
                  if(match("]", offset)) {
                     offset++;
                  }
               }
            }
         }
         else {
            v->size_vec.push_back(1);
         }
         if(match(";", offset)) {
            offset++;
            ret = true;
            break;
         }
         if(match(",", offset)) {
            offset++;
            if(match("*", offset)) {
               got_star = true;
               offset++;
            }
         }
         else {
            error(offset, "expected: \";\" in struct variable");
            break;
         }
      }
      return ret;
   }
   bool union_variable_statement(size_t & offset) {
      bool ret = false;
      string type = get_type(offset);
      if(type.size() == 0) return false;
      while(match(T_IDENTIFIER, offset)) {
         string id = token_vec[offset]->value;
         offset++;
         if(pf_map.find(type) != pf_map.end()) {
            pf_map[id] = true;
         }
         if(match(";", offset)) {
            offset++;
            ret = true;
            break;
         }
         if(match(",", offset)) {
            offset++;
         }
         else {
            break;
         }
      }
      return ret;
   }


   bool struct_statement(size_t & offset) {
      bool ret = false;
      if(match("struct", offset)) {
         offset++;
         if(match(T_IDENTIFIER, offset)) {
            string id = token_vec[offset]->value;
            offset++;
            if(match("{", offset)) {
               offset++;
               p_struct = new struc();
               p_struct->name = id;
               struc_map[id] = p_struct;


               while(struct_variable_statement(offset)) {


               }


               p_struct = 0;


               if(match("}", offset)) {
                  offset++;
                  if(match(";", offset)) {
                     offset++;
                     ret = true;
                  }
               }
            }
         }
      }
      return ret;
   }
   bool union_statement(size_t & offset) {
      bool ret = false;
      if(match("union", offset)) {
         offset++;
         if(match(T_IDENTIFIER, offset)) {
            string id = token_vec[offset]->value;
            offset++;
            if(match("{", offset)) {
               offset++;
               while(union_variable_statement(offset)) {


               }
               if(match("}", offset)) {
                  offset++;
                  if(match(";", offset)) {
                     offset++;
                     ret = true;
                  }
                  else error(offset, "expected: \";\"");
               }
               else error(offset, "expected: \"}\"");
            }
            else error(offset, "expected: \"{\"");
         }
         else error(offset, "expected: <identifier>");
      }
      return ret;
   }
   bool typedef_statement(size_t & offset) {
      bool ret = false;
      if(match("typedef", offset)) {
         offset++;
         string t = get_type(offset);
         if(match(T_IDENTIFIER, offset)) {
            string id = token_vec[offset]->value;
            offset++;
            if(match(";", offset)) {
               offset++;
               ret = true;
               typedef_map[id] = t;
            }
            else {
               error(offset, "expected: \";\" after typedef");
            }
         }
         else if(match("(", offset)) {
            offset++;
            if(match("*", offset)) {
               offset++;
               if(match(T_IDENTIFIER, offset)) {
                  string id = token_vec[offset]->value;
                  offset++;
                  if(match(")", offset)) {
                     offset++;
                     if(match("(", offset)) {
                        offset++;
                        if(match(")", offset)) {
                           offset++;
                           if(match(";", offset)) {
                              typedef_map[id] = t;
                              pf_map[id] = true;
                              offset++;
                              ret = true;
                           }
                           else error(offset, "typedef error");
                        }
                        else error(offset, "typedef error");
                     }
                     else error(offset, "typedef error");
                  }
                  else error(offset, "typedef error");
               }
               else error(offset, "typedef error");
            } 
            else error(offset, "typedef error");
         }
         else error(offset, "typedef error");
      }
      return ret;
   }
   bool function_decl_statement(size_t & offset) {
      bool ret = false;
      string type = get_type(offset);
      if(match(T_IDENTIFIER, offset)) {
         string fun_id = token_vec[offset]->value;
         offset++;
         if(match("(", offset)) {
            offset++;
            if(match(")", offset)) {
               offset++;
               if(match(";", offset)) {
                  offset++;
                  ret = true;
                  if(type.find("extern ") == 0) {
                     extern_vec.push_back(fun_id);
                  }
                  else {
                     global_vec.push_back(fun_id);
                  }
                  p_fun = new function();
                  p_fun->name = fun_id;
                  p_fun->return_type = type;
                  function_map[fun_id] = p_fun;
                  p_fun = 0;
               }
               else if(!match("{", offset)) {
                  error(offset, "expected: \"{\"");
               }
            }
         }
      }
      return ret;
   }
   bool function_def_statement(size_t & offset) {
      bool ret = false;
      string rt = get_type(offset);
      var_map_type temp = var_map;
      if(match(T_IDENTIFIER, offset)) {
         string function_id = token_vec[offset]->value;
         offset++;
         if(match("(", offset)) {
            offset++;
            while(match(T_IDENTIFIER, offset) || match("...", offset)) {
               offset++;
               if(match(",", offset)) {
                  offset++;
               }
               else {
                  break;
               }
            }
            if(match(")", offset)) {
               offset++;
               p_fun = new function();
               while(param_statement(offset)) {


               }
               p_fun->name = function_id;
               p_fun->var_map = var_map;
               p_fun->return_type = rt;
               function_map[function_id] = p_fun;
               global_vec.push_back(function_id);
               if(compound_statement(offset)) {
                  ret = true;
if(p_fun) {
cout << "FUNCTION: \"" << p_fun->name << "\"" << endl;
}
                  p_fun = 0;
               }
               else if(!match(";", offset)) {
                  error(offset, "expected: \"{\" or \";\"");
               }
               else {
                  offset++;
               }
            }
         }
      }
      var_map = temp;
      return ret;
   }
   bool global_variable_statement(size_t & offset) {
   /**/
      bool ret = false;
      string type = get_type(offset);
      if(type.size() == 0) return ret;
      string id;
      string ttype;
      int array_size = 0;
      bool is_star = false;
      if(match("*", offset-1)) {
         is_star = true;
         type = type.substr(0,type.size()-2);
      }
      while(match(T_IDENTIFIER, offset)) {
         id = token_vec[offset]->value;
         if(is_star) { 
            ttype = type + " *";
         }
         else {
            ttype = type;
         }
         var * p_var = new var();
         p_var->name = id;
         p_var->type = ttype;
         p_var->address = stk_size;
         offset++;
         global_map[id] = p_var;
         var_map[id] = p_var;
         global_var_vec.push_back(p_var);
         if(pf_map.find(type) != pf_map.end()) {
            pf_map[id] = true;
         }
         array_size = 1;
         while(match("[", offset)) {
            offset++;
            if(match(T_INT, offset)) {
               array_size = atoi(token_vec[offset]->value.c_str());
               //if(p_var->type == "char") {
               //   p_var->type += " *";
               //}
               //p_var->array_size = array_size;
               p_var->size_vec.push_back(array_size);
               offset++;
               if(match("]", offset)) {
                  offset++;
               }
            }
         }
/*

         if(ttype.find("*") != string::npos) {
            stk_size += p_var->array_size() * DATA_WORD_SIZE;
         }
         else if(ttype.find("short") != string::npos) {
            stk_size += p_var->array_size() * 2;
         }
         else if(ttype.find("char") != string::npos) {
            stk_size += p_var->array_size(); 
         }
         else if(ttype.find("int") != string::npos) {
            stk_size += 4 * p_var->array_size();
         }
         else if(ttype.find("float") != string::npos) {
            stk_size += 4 * p_var->array_size();
         }
         else if(ttype.find("long") != string::npos) {
            stk_size += 8 * p_var->array_size();
         }
         else if(ttype.find("double") != string::npos) {
            stk_size += 8 * p_var->array_size();
         }
         else if(ttype.find("struct") != string::npos) {
            stk_size += get_struct_size(type) * p_var->array_size();
         }
         else {
            stk_size += DATA_WORD_SIZE * p_var->array_size();
         }

*/
         //ret = true;


         if(match(",", offset)) {
            offset++;
            if(match("*", offset)) {
               is_star = true;
               offset++;
            }
            else {
               is_star = false;
            }
         }
         else {
            break;
         }
      }
      if(match(";", offset)) {
         offset++; 
         ret = true;
      }
      else {
         error(offset, "expecting: \";\"");
      }
      return ret;
/****
      bool ret = false;
      string type = get_type(offset);
      while(match(T_IDENTIFIER, offset)) {
         string id = token_vec[offset]->value;
         var * v = new var();
         
         v->name = id;
         
         v->type = type;
         global_map[id] = v;
         var_map[id] = v;
         if(pf_map.find(type) != pf_map.end()) {
            pf_map[id] = true;
         }
         offset++;
         if(match("[", offset)) {
            offset++;
            if(match(T_INT, offset)) {
               offset++;
               if(match("]", offset)) {
                  offset++;
               }
            }
         }
         if(match(",", offset)) {
            offset++;
         }
      }
      if(match(";", offset)) {
         offset++;
         ret = true;
      }
      return ret;
***/
   }
   bool statement(size_t & offset) {
cout << "STATEMENT..." << endl;
cout << "TOKEN: \"" << token_vec[offset]->value << "\"" << endl;


      size_t old_offset = offset;
      bool ret = false;
      if(return_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(if_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(while_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(for_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(do_while_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(switch_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(break_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(continue_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(goto_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(label_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(compound_statement(offset)) {
         return true;
      }
      offset = old_offset;
      if(expression_statement(offset)) {
         return true;
      }
      offset = old_offset;
      return ret;
   }
   bool variable_statement(size_t & offset) {
      bool ret = false;
      string type = get_type(offset);
      if(type.size() == 0) return ret;
      string id;
      string ttype;
      int array_size = 0;
      bool is_star = false;
      if(match("*", offset-1)) {
         is_star = true;
         type = type.substr(0,type.size()-2);
      }
      while(match(T_IDENTIFIER, offset)) {
         id = token_vec[offset]->value;
         if(is_star) { 
            ttype = type + " *";
         }
         else {
            ttype = type;
         }
         var * p_var = new var();
         p_var->name = id;
         p_var->type = ttype;
         p_var->address = stk_size;
         if(p_fun) {
            p_fun->var_map[id] = p_var;
            p_fun->var_vec.push_back(p_var);
         }
         offset++;
         var_map[id] = p_var;
         if(pf_map.find(type) != pf_map.end()) {
            pf_map[id] = true;
         }
         array_size = 1;
         while(match("[", offset)) {
            offset++;
            if(match(T_INT, offset)) {
               array_size = atoi(token_vec[offset]->value.c_str());
               //if(p_var->type == "char") {
               //   p_var->type += " *";
               //}
               //p_var->array_size = array_size;
               p_var->size_vec.push_back(array_size);
               offset++;
               if(match("]", offset)) {
                  offset++;
               }
            }
         }


         if(ttype.find("*") != string::npos) {
            stk_size += p_var->array_size() * DATA_WORD_SIZE;
         }
         else if(ttype.find("short") != string::npos) {
            stk_size += p_var->array_size() * 2;
         }
         else if(ttype.find("char") != string::npos) {
            stk_size += p_var->array_size(); 
         }
         else if(ttype.find("int") != string::npos) {
            stk_size += 4 * p_var->array_size();
         }
         else if(ttype.find("float") != string::npos) {
            stk_size += 4 * p_var->array_size();
         }
         else if(ttype.find("long") != string::npos) {
            stk_size += 8 * p_var->array_size();
         }
         else if(ttype.find("double") != string::npos) {
            stk_size += 8 * p_var->array_size();
         }
         else if(ttype.find("struct") != string::npos) {
            stk_size += get_struct_size(ttype) * p_var->array_size();
         }
         else {
            stk_size += DATA_WORD_SIZE * p_var->array_size();
         }
         ret = true;


         if(match(",", offset)) {
            offset++;
            if(match("*", offset)) {
               is_star = true;
               offset++;
            }
            else {
               is_star = false;
            }
         }
         else {
            break;
         }
      }
      if(match(";", offset)) {
         offset++; 
         ret = true;
      }
      else {
         error(offset, "expecting: \";\"");
      }
      return ret;
   }


   bool param_statement(size_t & offset) {
      bool ret = false;
      string type = get_type(offset);
      if(type.size() == 0) return ret;
      string id;
      int array_size = 1;
      while(match(T_IDENTIFIER, offset)) {
         id = token_vec[offset]->value;
         var * p_var = new var();
         p_var->name = id;
         p_var->type = type;
         p_var->address = stk_size;
         if(p_fun) {
            p_fun->param_map[id] = p_var;
            p_fun->var_map[id] = p_var;
            p_fun->param_vec.push_back(p_var);
         }
         offset++;
         var_map[id] = p_var;
         array_size = 1;
         if(match("[", offset)) {
            offset++;
            if(match(T_INT, offset)) {
               array_size = atoi(token_vec[offset]->value.c_str());
               offset++;
               if(match("]", offset)) {
                  offset++;
               }
            }
         }


         if(type.find("*") != string::npos) {
            stk_size += array_size * DATA_WORD_SIZE;
         }
         else if(type.find("short") != string::npos) {
            stk_size += array_size * 2;
         }
         else if(type.find("char") != string::npos) {
            stk_size += array_size;
         }
        else if(type.find("int") != string::npos) {
            stk_size += 4 * array_size;
         }
         else if(type.find("float") != string::npos) {
            stk_size += 4 * array_size;
         }
         else if(type.find("long") != string::npos) {
            stk_size += 8 * array_size;
         }
         else if(type.find("double") != string::npos) {
            stk_size += 8 * array_size;
         }
         else if(type.find("struct") != string::npos) {
            stk_size += get_struct_size(type) * array_size;
         }
         else {
            stk_size += DATA_WORD_SIZE * array_size;
         }
         ret = true;


         if(match(",", offset)) {
            offset++;
         }
         else {
            break;
         }
      }
      if(match(";", offset)) {
         offset++;
         ret = true;
      }
      else {
         error(offset, "expecting: \";\"");
      }
      return ret;
   }


///////
   bool expression_statement(size_t & offset) {
      bool ret = false;
      if(expression(offset)) {
         if(match(";", offset)) {
            offset++; 
            ret = true;
// DEBUG
            if(last_type != "void") {
               add_instruction("pop", "ax");
            }
         }
         else error(offset, "expected: \";\"");
      }
      else if(match(";", offset)) {
         ret = true;
         offset++;
         add_instruction("nop", "");
      }
      return ret;
   }
   bool break_statement(size_t & offset) {
      bool ret = false;
      if(match("break", offset)) {
         offset++;
         if(match(";", offset)) {
            offset++;
            ret = true;
            if(loop_end != "") {
               add_instruction("jmp", loop_end);
            }
         }
         else error(offset, "expected: \";\"");
      }
      return ret;
   }
   bool continue_statement(size_t & offset) {
      bool ret = false;
      if(match("continue", offset)) {
         offset++;
         if(match(";", offset)) {
            offset++;
            ret = true;
            if(loop_cond != "") {
               add_instruction("jmp", loop_cond);
            }
         }
         else {
            error(offset, "expected: \";\" after \"continue\"");
         }
      }
      return ret;
   }
   bool goto_statement(size_t & offset) {
      bool ret = false;
      if(match("goto", offset)) {
         offset++;
         if(match(T_IDENTIFIER, offset)) {
            offset++;
            if(match(";", offset)) {
               offset++;
               ret = true;
            }
            else error(offset, "expected: \";\"");
         }
         else error(offset, "expected: <identifier>");
      }
      return ret;
   }
   bool return_statement(size_t & offset) {
      bool ret = false;
      if(match("return", offset)) {
         offset++;
         if(match(";", offset)) {
            add_instruction("leave", "");
            add_instruction("ret", "");
            offset++;
            ret = true;
         }
         else if(expression(offset)) {
            add_instruction("pop", "ax");
            add_instruction("leave", "");
            add_instruction("ret", "");
            if(match(";", offset)) {
               offset++;
               ret = true;
            }
            else error(offset, "expected: \";\"");
         }
         else error(offset, "expected: <expression> or \";\"");
      }
      return ret;
   }
   bool label_statement(size_t & offset) {
      bool ret = false;
      if(match(T_IDENTIFIER, offset)) {
         string label = token_vec[offset]->value;
         offset++;
         if(match(":", offset)) {
            ret = true;
            offset++;
            add_instruction(label, "", "", "");
         }
      }
      return ret;
   }
   string get_next_temp(const size_t size = DATA_WORD_SIZE, const string & type = "short") {
      temp_count++;
      stringstream str;
      str << temp_count;
      string ret;
      str >> ret;
      ret = "temp" + ret;
      stk_size += size;
      var * v = new var();
      v->name = ret;
      v->type = type;
      var_map[v->name] = v;
      p_fun->var_map[v->name] = v;
      p_fun->var_vec.push_back(v);
      //int sz = atoi(p_fun->code[allocate_index]->op.c_str());
      //sz += size;
      // MY DEBUG sz
      p_fun->code[allocate_index]->arg2 = to_string(stk_size);
      return ret;
   }
   bool switch_statement(size_t & offset) {
      bool ret = false;
      if(match("switch", offset)) {
         string end = get_next_label();
         string prev = loop_end;
         loop_end = end;
         offset++;
         if(match("(", offset)) {
            offset++;
            if(expression(offset)) { 
               string temp = get_next_temp();
               add_instruction("pop", "word [bp+" + temp + "]");
               if(match(")", offset)) {
                  offset++;
                  if(match("{", offset)) {
                     offset++;
                     string next;
                     while(match("case", offset)) {
                        next = get_next_label();
                        offset++;
                        if(match(T_CHAR, offset)) {
                           add_instruction("mov", "ax", token_vec[offset]->value);
                           add_instruction("mov", "bx", "word [bp+" + temp + "]");
                           add_instruction("cmp", "ax", "bx");
                           add_instruction("jne", next);
                           offset++;
                        }
                        else if(match(T_INT, offset)) {
                           add_instruction("mov", "ax", token_vec[offset]->value);
                           add_instruction("mov", "bx", "word [bp+" + temp + "]");
                           add_instruction("cmp", "ax", "bx");
                           add_instruction("jne", next);
                           offset++;
                        }
                        if(match(":", offset)) {
                           offset++;
                        }
                        while(statement(offset)) {


                        }
                        add_instruction(next, "", "", "");
                     }
                     if(match("default", offset)) {
                        offset++;
                        if(match(":", offset)) {
                           offset++;
                           while(statement(offset)) {


                           }
                        }
                     }
                     if(match("}", offset)) {
                        offset++;
                        ret = true;
                     }
                  }
               }
            }
         }
         add_instruction(end, "", "", "");
         loop_end = prev;
      }
      return ret;
   }
   bool compound_statement(size_t & offset) {
      bool ret = false;
      if(match("{", offset)) {
         offset++;
         stk_size = 0;
         bool got = false;
         while(variable_statement(offset)) {
            got = true;
         }
cout << "stk_size == " << stk_size << endl;
//cin.get();cin.get();
         //if(stk_size != 0) {
            allocate_index = p_fun->code.size();
            add_instruction("sub", "sp", to_string(stk_size));
         //}
         while(statement(offset)) {
            got = true;
         }
for(size_t i = 0; i < 10 && (offset+i) < token_vec.size(); i++) {
cout << "COMPOUND: \"" << token_vec[offset+i]->value << "\"" << endl;
}
         if(!got) {
            add_instruction("nop", "", "");
         }
         if(match("}", offset)) {
            offset++;
            ret = true;
         }
      }
      return ret;
   }


   bool if_statement(size_t & offset) {
      bool ret = false;
      string end;
      string the_end;
      bool found = false;
      if(match("if", offset)) {
         the_end = get_next_label();
      }
      while(match("if", offset)) {
         found = true;
         offset++;
         if(match("(", offset)) {
            offset++;
size_t off = offset;
            if(!expression(offset)) {
               error(offset, 
                     "expected: <expression> after the \"if\" \"(\"");
            }


cout << "if_statement: \"" << last_type << "\"" << endl;
for(size_t i = off; i < token_vec.size() && i < off+5; i++) {
cout << "(" << token_vec[i]->value << ")" << endl;
}
//cin.get();cin.get();
            if(last_type == "char") {
               add_instruction("cpop", "al");
               add_instruction("cmp", "al", "0");
            }
            else {
               add_instruction("pop", "ax");
               add_instruction("cmp", "ax", "0");
            }
            end = get_next_label();
            add_instruction("je", end);
            if(match(")", offset)) {
               offset++;
               ret = statement(offset);
               if(!ret) {
                  error(offset, 
                        "expected: <statement> after if statement\"");
               }
               add_instruction("jmp", the_end);
               add_instruction(end, "", "", "");
            }
            else {
               error(offset, 
                     "expected: <expression> after the \"if\" \"(\" <expression>\"");
            }
         }
         else {
            error(offset, "expected: \"(\" after the \"if\"");
         }
         if(match("else", offset) && match("if", offset+1)) {
            offset++;
         }
      }
      if(match("else", offset)) {
         offset++;
         ret = statement(offset);
         if(!ret) {
            error(offset, "expected: <statement> after \"else\""); 
         }
      }
      if(found) {
         add_instruction(the_end, "", "", "");
      }
      return ret;
   }
   bool for_statement(size_t & offset) {
      bool ret = false;
      if(match("for", offset)) {
         offset++;
         string end,cond;
         end = get_next_label();
         cond = get_next_label();
         if(match("(", offset)) {
            offset++;
            if(expression(offset) || true) {
               
               if(match(";", offset)) {
                  offset++;
                  string temp = loop_cond;
                  loop_cond = cond;
                  add_instruction(cond, "", "", "");
                  size_t current = code.size();
                  if(expression(offset) || true) {
                     if(current == code.size()) {
                        add_instruction("pop", "1");
                     }
                     if(last_type == "char") {
                        add_instruction("cpop", "al");
                        add_instruction("cmp", "al", "0");
                     }
                     else {
                        add_instruction("pop", "ax");
                        add_instruction("cmp", "ax", "0");
                     }
                     add_instruction("je", end);
                     if(match(";", offset)) {
                        offset++;
                        current = code.size();
                        instruction_vector_type temp;
                        if(expression(offset) || true) {
                           for(size_t i = current; i < code.size(); i++) {
                              temp.push_back(code[i]);
                           }
                           temp.push_back(new instruction("pop", "ax", ""));

                           while(code.size() != current) {
                              code.pop_back();
                              if(p_fun) {
                                 p_fun->code.pop_back();
                              }
                           }
                           if(match(")", offset)) {
                              offset++;
                              if(statement(offset)) {
                                 ret = true;
                                 for(size_t i = 0; i < temp.size(); i++) {
                                    add_instruction(temp[i]);
                                 }
                                 add_instruction("jmp", cond);
                              }
                              else {
                                 error(offset, "expected: <statement>");
                              }
                           }
                           else {
                              error(offset, "expected: \")\"");
                           }
                        }
                     }
                     else {
                        error(offset, "expected: \";\"");
                     }
                  }
                  loop_cond = temp;
               }
               else {
                  error(offset, "expected: \";\"");
               }
            }
         }
         else {
            error(offset, "expected: \"(\"");
         }
         add_instruction(end, "", "", "");
      }
      return ret;
   }
   bool while_statement(size_t & offset) {
      string end,top;
      bool ret = false;
      if(match("while", offset)) {
         end = get_next_label();
         top = get_next_label();


         string temp = loop_cond;


         loop_cond = top;


         offset++;


         add_instruction(top, "", "", "");
         if(match("(", offset)) {
            offset++;
            if(expression(offset)) {
               if(last_type == "char") {
                  add_instruction("cpop", "al");
                  add_instruction("cmp", "al", "0");
               }
               else {
                  add_instruction("pop", "ax");
                  add_instruction("cmp", "ax", "0");
               }
               add_instruction("je", end);
               if(match(")", offset)) {
                  offset++;
                  if(statement(offset)) {
                     ret = true;
                  }
                  else {
                     error(offset, "expected: <statement>");
                  }
               }
               else {
                  error(offset, "expected: \")\"");
               }
            }
            else {
               error(offset, "expected: <expression>");
            }
         }
         else {
            error(offset, "expected: \"(\"");
         }
         
         add_instruction("jmp", top);
         add_instruction(end, "", "", "");


         loop_cond = temp;
      }
      return ret;
   }
   bool do_while_statement(size_t & offset) {
      bool ret = false;
      if(match("do", offset)) {
         offset++;
         string top = get_next_label();
         add_instruction(top, "", "", "");
         if(compound_statement(offset)) {
            if(match("while", offset)) {
               offset++;
               if(match("(", offset)) {
                  offset++;
                  string temp = loop_cond;
                  loop_cond = get_next_label();
                  add_instruction(loop_cond, "", "", "");
                  if(expression(offset)) {
                     if(match(")", offset)) {
                        offset++;
                        if(match(";", offset)) {
                           offset++;
                           ret = true;
                           if(last_type == "char") {
                              add_instruction("cpop", "al");
                              add_instruction("cmp", "al", "0");
                           }
                           else {
                              add_instruction("pop", "ax");
                              add_instruction("cmp", "ax", "0");
                           }
                           add_instruction("jne", top);
                        }
                        else error(offset, "loop error");
                     }
                     else error(offset, "loop error");
                  }
                  else error(offset, "loop error");
                  loop_cond = temp;
               }
               else error(offset, "loop error");
            }
            else error(offset, "loop error");
         }
         else error(offset, "loop error");
      }
      return ret;
   }
   bool expression(size_t & offset) {
      bool ret = false;
      if(boolean(offset)) {
         ret = true;
         if(!in_expression_list) {
            while(match(",", offset)) {
               offset++;
               add_instruction("pop", "ax", "");
               if(boolean(offset)) {

               }
               else {
                  error(offset, "expected: <boolean>");
               }
            }
         }
      }
      return ret;
   }
   bool boolean(size_t & offset) {
      bool ret = false;
      if(relation(offset)) {
         ret = true;
         if(match("&&", offset)) {
            offset++;
            if(boolean(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "ax");
               add_instruction("and", "ax", "bx");
               add_instruction("push", "ax");
            }
            else error(offset, "expected: <boolean>");
         }
         else if(match("||", offset)) {
            offset++;
            if(boolean(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "ax");
               add_instruction("or", "ax", "bx");
               add_instruction("push", "ax");
            }
            else error(offset, "expected: <boolean>");
         }
      }
      return ret;
   }
   string get_next_label() {
      stringstream str;
      str << ".L" << label_count;
      label_count++;
      string ret;
      str >> ret;
      return ret;
   }
   bool relation(size_t & offset) {
      bool ret = false;
      if(term(offset)) {
         ret = true;
         if(match("<", offset)) {
            offset++;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("cmp", "dx", "bx");
               add_instruction("jl", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", ""); 
               add_instruction("push", "1");
               add_instruction(end, "", "", ""); 
            }
            else error(offset, "expected: <relation>");
         }
         else if(match(">", offset)) {
            offset++;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("cmp", "dx", "bx");
               add_instruction("jg", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", "");
               add_instruction("push", "1");
               add_instruction(end, "", "", "");
            }
            else error(offset, "expected: <relation>");
         }
         else if(match("<=", offset)) {
            offset++;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("cmp", "dx", "bx");
               add_instruction("jle", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", "");
               add_instruction("push", "1");
               add_instruction(end, "", "", "");
            }
            else error(offset, "expected: <relation>");
         }
         else if(match(">=", offset)) {
            offset++;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("cmp", "dx", "bx");
               add_instruction("jge", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", "");
               add_instruction("push", "1");
               add_instruction(end, "", "", "");
            }
            else error(offset, "expected: <relation>");
         }
         else if(match("==", offset)) {
            offset++;
cout << "is equal to: \"" << last_type << "\"" << endl;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();
cout << "is equal to: \"" << last_type << "\"" << endl;
//cin.get();cin.get();
               //if(last_type == "char") {
                  //add_instruction("mov", "si", "sp");
                  //add_instruction("add", "si", "1");
                  //add_instruction("mov", "al", "[si]");
                  //add_instruction("add", "sp", "1");
                  //add_instruction("pop", "bp");

                  //add_instruction("cpop", "ah");
                  //add_instruction("cpop", "al");

                  //add_instruction("mov", "si", "sp");
                  //add_instruction("add", "si", "1");
                  //add_instruction("mov", "ah", "[si]");
                  //add_instruction("add", "sp", "1");
                  
                  //add_instruction("cmp", "al", "ah");
               //}
               //else {
                  add_instruction("pop", "bx");
                  add_instruction("pop", "dx");
                  add_instruction("cmp", "dx", "bx");
               //}
               add_instruction("je", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", "");
               add_instruction("push", "1");
               add_instruction(end, "", "", "");
               last_type = "short";
            }
            else error(offset, "expected: <relation>");
         }
         else if(match("!=", offset)) {
            offset++;
            if(relation(offset)) {
               string label = get_next_label();
               string end = get_next_label();

               //if(last_type == "char") {
                  //add_instruction("cpop", "ah");
                  //add_instruction("cpop", "al");
                  //add_instruction("cmp", "al", "ah");
               //}
               //else {
                  add_instruction("pop", "bx");
                  add_instruction("pop", "dx");
                  add_instruction("cmp", "dx", "bx");
               //}

               add_instruction("jne", label);
               add_instruction("push", "0");
               add_instruction("jmp", end);
               add_instruction(label, "", "", "");
               add_instruction("push", "1");
               add_instruction(end, "", "", "");
               last_type = "short";
            }
            else error(offset, "expected: <relation>");
         }
      }
      return ret;
   }
   bool term(size_t & offset) {
      bool ret = false;
      if(factor(offset)) {
         ret = true;
         if(match("+", offset)) {
            offset++;
            if(term(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("add", "dx", "bx");
               add_instruction("push", "dx");
            }
            else {
               error(offset, "expected: <term>");
            }
         }
         else if(match("-", offset)) {
            offset++;
            if(term(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("sub", "dx", "bx");
               add_instruction("push", "dx");
            }
            else {
               error(offset, "expected: <term>");
            }
         }
      } 
      return ret;
   }
   bool factor(size_t & offset) {
      bool ret = false;
      if(bitops(offset)) {
         ret = true;
         if(match("*", offset)) {
            offset++;
            if(factor(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("imul", "bx", "dx");
               add_instruction("push", "bx");
            }
            else error(offset, "expected: <factor>");
         }
         else if(match("/", offset)) {
            offset++;
            if(factor(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "ax");
               add_instruction("xor", "dx", "dx");
               add_instruction("idiv", "bx");
               add_instruction("push", "ax");
            }
            else error(offset, "expected: <factor>");
         }
         else if(match("%", offset)) {
            offset++;
            if(factor(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "ax");
               add_instruction("xor", "dx", "dx");
               add_instruction("idiv", "bx");
               add_instruction("push", "dx");
            }
            else error(offset, "expected: <factor>");
         }
      } 
      return ret;
   }
   bool bitops(size_t & offset) {
      bool ret = false;
      if(primary(offset)) {
         ret = true;
         if(match("<<", offset)) {
            offset++;
            if(bitops(offset)) {
               add_instruction("cpop", "cl");
               add_instruction("pop", "dx");
               add_instruction("shl", "dx", "cl");
               add_instruction("push", "dx");
            }
            else error(offset, "expected: <bitiops>");
         }
         else if(match(">>", offset)) {
            offset++;
            if(bitops(offset)) {
               add_instruction("cpop", "cl");
               add_instruction("pop", "dx");
               add_instruction("shr", "dx", "cl");
               add_instruction("push", "dx");
            }
            else error(offset, "expected: <bitiops>");
         }
         else if(match("|", offset)) {
            offset++;
            if(bitops(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("or", "dx", "bx");
               add_instruction("push", "dx");
            }
            else error(offset, "expected: <bitiops>");
         }
         else if(match("&", offset)) {
            offset++;
            if(bitops(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "ax");
               add_instruction("and", "ax", "bx");
               add_instruction("push", "ax");
            }
            else error(offset, "expected: <bitiops>");
         }
         else if(match("^", offset)) {
            offset++;
            if(bitops(offset)) {
               add_instruction("pop", "bx");
               add_instruction("pop", "dx");
               add_instruction("xor", "dx","bx");
               add_instruction("push", "dx");
            }
            else error(offset, "expected: <bitiops>");
         }
      } 
      return ret;
   }
   bool expression_list(size_t & offset, size_t & size, bool do_push = true) {
      bool ret = false;
      bool old = in_expression_list;
      //bool b = in_expression;
      //in_expression = true;
      in_expression_list = true;
      instruction_vector_type temp;
      instruction_vector_type temp2 = code;
      instruction_vector_type temp3;
      if(p_fun) {
         temp3 = p_fun->code;
      }
      vector< instruction_vector_type > ivec;
      while(expression(offset)) {
         for(size_t i = temp2.size(); i < code.size(); i++) {
            temp.push_back(code[i]);
         }
         ivec.push_back(temp);
         temp.clear();
         code = temp2;
         if(p_fun) {
            p_fun->code = temp3;
         }
         if(last_type.find("*") != string::npos) {
            size += DATA_WORD_SIZE;
         }
         else if(last_type == "char") {
            size += 2;
         }
         else if(last_type == "short") {
            size += 2;
         }
         else {
            size += DATA_WORD_SIZE;
         }
         ret = true;
         if(match(",", offset)) {
            offset++;
         }
         else {
            break;
         }
      }
      if(ivec.size()) {
         for(int i = ivec.size()-1; i >= 0; i--) {
            for(size_t j = 0; j < ivec[i].size(); j++) {
               code.push_back(ivec[i][j]);
               if(p_fun) {
                  p_fun->code.push_back(ivec[i][j]);
               }
            }
         }
      }
      in_expression_list = old;
      //in_expression = b;
      return ret;
   }
   string trim_star(const string & t_str) {
      string ret;
      if(ret.size() >= 2) {
         stringstream str;
         str << t_str;
         vector< string > vec;
         string temp;
         while(str >> temp) {
            vec.push_back(temp);
         }
         if(vec.size()) {
            for(size_t i = 0; i < vec.size(); i++) {
               if(i == vec.size()-1 && vec[i] == "*") {
                  break;
               }
               if(ret.size()) ret += " ";
               ret += vec[i];
            }
         }
      }
      else {
         ret = t_str;
      }
      return ret;
   }

   void insert_assign_code(const string & op)
   {
      if(op == "+=") {
         add_instruction("add", "bx", "dx");
      }
      else if(op == "-=") {
         add_instruction("sub", "bx", "dx");
      }
      else if(op == "*=") {
         add_instruction("imul", "bx", "dx");
      }
      else if(op == "/=") {
         add_instruction("mov", "ax", "bx");
         add_instruction("xor", "dx", "dx");
         add_instruction("idiv", "bx");
         add_instruction("mov", "bx", "ax");
      }
      else if(op == "%=") {
         add_instruction("mov", "ax", "bx");
         add_instruction("xor", "dx", "dx");
         add_instruction("idiv", "bx");
         add_instruction("mov", "bx", "dx");
      }
      else if(op == "|=") {
         add_instruction("or", "bx", "dx");
      }
      else if(op == "&=") {
         add_instruction("and", "bx", "dx");
      }
      else if(op == "<<=") {
         add_instruction("push", "bx");
         add_instruction("cpop", "cl");
         add_instruction("shl", "dx", "cl");
         add_instruction("mov", "bx", "dx");
      }
      else if(op == ">>=") {
         add_instruction("push", "bx");
         add_instruction("cpop", "cl");
         add_instruction("shr", "dx", "cl");
         add_instruction("mov", "bx", "dx");
      }
      else if(op == "^=") {
         add_instruction("xor", "bx", "dx");
      }
   }

   bool continue_primary(const string & id, size_t & offset) {
cout << "continue_primary(" << id << "," << offset << ")" << endl;
//cin.get();
      bool ret = false;
      string id2;
      string struct_name;
      bool is_global = false;
      if(global_map.find(id) != global_map.end()) {
         var * v = global_map[id];
         last_type = v->type;
         is_global = true;
      }
      if(var_map.find(id) != var_map.end()) {
cout << "found var: \"" << id << "\"" << endl;
         var * v = var_map[id];
         if(v) {
            if(match("[", offset)) {
               last_type = v->type;
            }
            else {
               last_type = v->type + " [" + to_string(v->array_size()) + "]";
            }
            struct_name = get_struct_name(v->type);
cout << "struct_name: \"" << struct_name << "\"" << endl;
         }
      }
      function * pf = 0;
      if(function_map.find(id) != function_map.end()) {
         pf = function_map[id];
         last_type = pf->return_type;
         if(pf) {
            if(!match("(", offset+1)) {
               add_instruction("mov", "dx", id);
               add_instruction("push", "dx");
               ret = true;
               offset++;
               return ret;
            }
         }
      }
      if(!match("->", offset)
         && !match(".", offset)
         && !match("[", offset)
         && !match("(", offset)
         && !is_assign_operator(offset)) {
         offset++;
      }
      bool got_array = false;
      string rel = "bp+";
      if(is_global) {
         rel = "";
      }
//
// ARRAY
//
      if(match("[", offset)) {
         size_t index = 0;
         var * v = var_map[id];
         add_instruction("push", "word 0");
         while(match("[", offset)) {
            offset++;
            //bool b = in_expression;
            //in_expression = true;
cout << "array expression next..." << endl;
//cin.get();cin.get();
            if(expression(offset)) {
cout << "got array expression..." << endl;
cout << "TOKEN=" << token_vec[offset]->value << endl;
//cin.get();cin.get();
               if(match("]", offset)) {
                  got_array = true;
                  offset++;
                  if(v->size_vec.size() == 0) {
                     add_instruction("pop", "bx");
                     add_instruction("pop", "dx");
                     add_instruction("add", "bx", "dx");
                     add_instruction("push", "bx");
                     index++;
                  }
                  else if(index == v->size_vec.size()-1) {
                     add_instruction("pop", "bx");
                     add_instruction("pop", "dx");
                     add_instruction("add", "bx", "dx");
                     add_instruction("push", "bx");
                     index++;
                  }
                  else {
                     add_instruction("pop", "bx");
                     add_instruction("pop", "dx");
                     add_instruction("imul", "bx", to_string(v->size_vec[index]));
                     add_instruction("add", "bx", "dx");
                     add_instruction("push", "bx");
                     index++;
                  }
               }
            }
            //in_expression = b;
         }
         if(got_array) {
            if(v->type == "char *") {
               add_instruction("mov", "bx", "[" + rel + id + "]");
               add_instruction("pop", "dx");
               add_instruction("push", "bx");
               add_instruction("add", "bx", "dx");
               add_instruction("push", "bx");
               last_type = "char";
            }
            else {
               add_instruction("lea", "bx", "[" + rel + id + "]");
               add_instruction("pop", "dx");
               add_instruction("imul", "dx", to_string(v->size()));
               add_instruction("add", "bx", "dx");
               add_instruction("push", "bx");
               last_type = v->type;
            }
         }
      }
      if(match(".", offset)) {
         offset++;
         string strcut_name = get_struct_name(last_type);
         struc * p_struct = struc_map[struct_name];
         string temp;
         string type;
         while(match(T_IDENTIFIER, offset)) {
            temp = token_vec[offset]->value;
            id2 += temp;
            type = p_struct->get_type(temp);
            type = get_struct_name(type);
            if(struc_map.find(type) != struc_map.end()) {
               id2 += "+" + type;
            }
            offset++;
            if(match(".", offset)) {
               offset++;
               id2 += ".";
            }
         }
         if(got_array) {
            add_instruction("pop", "bx");
            add_instruction("add", "bx", 
            get_struct_name(last_type) + "." + id2);
            add_instruction("push", "bx");
         }
      }
      if(match("->", offset)) {
         offset++;
         if(match(T_IDENTIFIER, offset)) {
            id2 = token_vec[offset]->value;
            offset++;

            if(got_array) {
               add_instruction("pop", "bx");
               add_instruction("add", "bx", 
               get_struct_name(last_type) + "." + id2);
               add_instruction("push", "bx");
            }
         }
      }
      struct_name = get_struct_name(struct_name);
      if(match("++", offset)) {
         offset++;
         if(id2.size()) {
            if(p_fun->param_map.find(id) == p_fun->param_map.end()) {
               add_instruction("inc", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
               add_instruction("push", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
            }
            else {
               add_instruction("inc", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
               add_instruction("push", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
            }
         }
         else {
            add_instruction("inc", "word [" + rel + id + "]");
            add_instruction("push", "word [" + rel + id + "]");
         }
         ret = true;
      }
      if(match("--", offset)) {
         offset++;
         if(id2.size()) {
            if(p_fun->param_map.find(id) == p_fun->param_map.end()) {
               add_instruction("dec", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
               add_instruction("push", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
            }
            else {
               add_instruction("dec", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
               add_instruction("push", "word [" + rel + id + "+" + struct_name + "." + id2 + "]");
            }
         }
         else { 
            add_instruction("dec", "word [" + rel + id + "]");
            add_instruction("push", "word [" + rel + id + "]");
         }
         ret = true;
      }
      if(match("(", offset)) {
         offset++;
         size_t size = 0;
         ///bool b = in_expression;
         //in_expression = true;
         if(match(")", offset)) {
            if(pf_map.find(id) != pf_map.end()) 
               add_instruction("call", "[" + rel + id + "]");
            else 
               add_instruction("call", id);
            if(size != 0) {
               add_instruction("add", "sp", to_string(size));
            }
            //if(in_expression) {
               if(pf) {
                  if(pf->return_type != "void") {
                     add_instruction("push", "ax");
                     last_type = pf->return_type;
                  }
                  else {
                     //add_instruction("push", "word 0");
                     last_type = "void";
                  }
               }
               else {
                  //add_instruction("push", "word 0");
                  last_type = "void";
               }
            //}
            offset++;
            ret = true;
         }
         else  if(expression_list(offset, size)) {
            if(match(")", offset)) {
               if(pf_map.find(id) != pf_map.end())
                  add_instruction("call", "[" + rel + id + "]");
               else
                  add_instruction("call", id);
               if(size != 0) {
                  add_instruction("add", "sp", to_string(size));
               }
               //if(in_expression) {
                  if(pf) {
                     if(pf->return_type != "void") {
                        add_instruction("push", "ax");
                        last_type = pf->return_type;
                     }
                     else {
                        //add_instruction("push", "word 0");
                        last_type = "void";
                     }
                  }
                  else {
                     //add_instruction("push", "word 0");
                     last_type = "void";
                  }
               //}
               offset++;
               ret = true;
            }
         }
         //in_expression = b;
      }


      if(got_array && !is_assign_operator(offset)) {
         add_instruction("pop", "bx");
         if(last_type == "char") {
	    add_instruction("push", "bp");
            add_instruction("mov", "bp", "bx");
            add_instruction("mov", "al", "[bp]");
            add_instruction("pop", "bp");
            add_instruction("cpush", "al");
         }
         else {
	    add_instruction("push", "bp");
            add_instruction("mov", "bp", "bx");
            add_instruction("mov", "dx", "[bp]");
            add_instruction("push", "dx");
         }
         ret = true;
      }


      if(is_assign_operator(offset)) {
         while(is_assign_operator(offset)) {
            string op = token_vec[offset]->value;
            offset++;
            bool old2 = on_right;
            on_right = true;
            if(expression(offset)) {
               if(op != "=") {
                  if(id2.size()) {
                     if(p_fun->param_map.find(id) == p_fun->param_map.end()) 
                        add_instruction("mov", "bx", "[" + rel +  id + "+" + struct_name + "." + id2 + "]");
                     else
                        add_instruction("mov", "bx", "[" + rel +  id + "+" + struct_name + "." + id2 + "]");
                     add_instruction("pop", "dx");
                     insert_assign_code(op);
                     add_instruction("push", "bx");
                  }
                  else {
                     add_instruction("mov", "bx", "[" + rel +  id + "]");
                     add_instruction("pop", "dx");
                     insert_assign_code(op);
                     add_instruction("push", "bx");
                  }
               }
               var * v = var_map[id];
               if(v == 0) {
                  error(offset, "unknown variable...");
               }
               if(v->type == "char" && !got_array) {
                  add_instruction("mov", "si", "sp");
                  add_instruction("add", "si", "1");
                  add_instruction("mov", "al", "[sp+si]");
                  add_instruction("add", "sp", "1");
               }
               if(!got_array) {
                  if(last_type == "char") {
                     add_instruction("cpop", "al");
                  }
                  else {
                     add_instruction("pop", "ax");
                  }
cout << "last_type: \"" << last_type << "\"" << endl;
cout << "id: \"" << id << "\"" << endl;
//cin.get();cin.get();
               }
               if(got_array) {
                  if(last_type == "char" || v->type == "char") {
                     add_instruction("cpop", "al");
                     add_instruction("pop", "cx");
                     add_instruction("push", "bp");
                     add_instruction("mov", "bp", "cx");
                     add_instruction("mov", "[bp]", "al");
                     add_instruction("pop", "bp");
                     add_instruction("cpush", "al");
                     ret = true;
                  }
                  else {
                     add_instruction("pop", "dx");
                     add_instruction("pop", "cx");
                     add_instruction("push", "bp");
                     add_instruction("mov", "bp", "cx");
                     add_instruction("mov", "[bp]", "dx");
                     add_instruction("pop", "bp");
                     add_instruction("push", "dx");
                     ret = true;
                  }
               }
               else if(get_value && v->type == "char") {
                  if(id2.size()) {
                     if(p_fun->param_map.find(id) == p_fun->param_map.end())
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                     else
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                  }
                  else {
                     add_instruction("mov", "di", id);
                  }
                  
                  add_instruction("mov", "[sp+di]", "al");
                  add_instruction("cpush", "al");
               }
               else if(get_value && v->type.find("*") != string::npos && last_type == "char" && l_val) {
                  if(id2.size()) {
                     if(p_fun->param_map.find(id) == p_fun->param_map.end())
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                     else
                        add_instruction("mov", "di", rel + id + "+" + struct_name + "." + id2);
                  }
                  else {
                     add_instruction("mov", "di", id);
                  }
                  add_instruction("mov", "[" + rel + "di]", "al");
                  add_instruction("cpush", "al");
               }
               else if(get_value && v->type.find("*") != string::npos && l_val) {
                  if(id2.size()) {
                     if(p_fun->param_map.find(id) == p_fun->param_map.end())
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                     else
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                  }
                  else {
                     add_instruction("mov", "di", id);
                  }
                  add_instruction("mov", "cx", "[" + rel + "di]");
                  add_instruction("push", "bp");
                  add_instruction("mov", "bp", "cx");
                  add_instruction("mov", "[bp]", "ax");
                  add_instruction("pop", "bp");
                  add_instruction("push", "ax");
               }
               else if(get_value) {
                  if(id2.size()) {
                     if(p_fun->param_map.find(id) == p_fun->param_map.end())
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                     else
                        add_instruction("mov", "di", id + "+" + struct_name + "." + id2);
                  }
                  else {
                     add_instruction("mov", "si", id);
                  }
                  add_instruction("mov", "[" + rel + "si]", "ax");
                  add_instruction("push", "ax");
               }
               else if(id2.size()) {
                  if(p_fun->param_map.find(id) == p_fun->param_map.end()) {
                     if(var_map.find(id) != var_map.end()) {
                        if(var_map[id]->type.find("*") != string::npos) {
                           //add_instruction("mov", string("[") + rel + id + "+" + struct_name + "." + id2 + string("]"), "ax");
                           add_instruction("push", "bp", "");
                           add_instruction("mov", "bp", string("[") + rel + id + "]");
                           add_instruction("add", "bp", struct_name + "." + id2);
                           add_instruction("mov", "[bp]", "ax");
                           add_instruction("pop", "bp");
                           add_instruction("push", "ax", "");
                        }
                        else {
                           add_instruction("mov", string("[") + rel + id + "+" + struct_name + "." + id2 + string("]"), "ax");
                           add_instruction("push", "ax", "");
                        }
                     }
                     else {
                        add_instruction("mov", string("[") + rel + id + "+" + struct_name + "." + id2 + string("]"), "ax");
                        add_instruction("push", "ax", "");
                     }                  
                  }
                  else {
                     add_instruction("mov", string("[") + rel + id + "+" + struct_name + "." + id2 + string("]"), "ax");
                     add_instruction("push", "ax", "");
                  }
               }
               else { 
                  add_instruction("mov", string("[") + rel + id + string("]"), "ax");
                  add_instruction("push", "ax", "");
               }
               ret = true;
            }
            else {
cout << "MOV..." << endl << flush;
               error(offset, "expecting: <expression>");
            }
            on_right = old2;
         }
      }
      if(!ret) {
         var * v = var_map[id];
         if(v == 0) 
            error(offset, "unknown variable...");
         if(get_addr) {
            if(id2.size()) {
               if(p_fun->param_map.find(id) == p_fun->param_map.end())
                  add_instruction("lea", "ax", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
               else 
                  add_instruction("lea", "ax", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
            }
            else {
               add_instruction("lea", "ax", string("[") + rel + id + string("]"));
            }
            add_instruction("push", string("ax"));
         }
         else if(get_value && v->type == "char *") {
            add_instruction("push", "bp");
            if(id2.size()) {
               if(p_fun->param_map.find(id) == p_fun->param_map.end())
                  add_instruction("mov", "bp", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
               else
                  add_instruction("mov", "bp", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
            }
            else {
               add_instruction("mov", "bp", string("[bp+") + id + string("]"));
            }
            add_instruction("mov", "al", "[bp]");
            add_instruction("pop", "bp");
            add_instruction("cpush", "al");
            last_type = "char";
         }

         else if(get_value && v->size_vec.size()) {
            if(id2.size()) {
               if(p_fun->param_map.find(id) == p_fun->param_map.end())
                  add_instruction("lea", "ax", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
               else
                  add_instruction("lea", "ax", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
            }
            else {
               add_instruction("lea", "ax", string("[") + rel + id + string("]"));
            }
            add_instruction("push", "ax");
         }

         else if(get_value) {
            bool f = false;
            if(id2.size()) {
               if(p_fun->param_map.find(id) == p_fun->param_map.end())
                  add_instruction("mov", "si", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
               else
                  add_instruction("mov", "si", string("[") + rel + id + "+" + struct_name + "." + id2+ string("]"));
            }
            else {
               add_instruction("push", "bp");
               add_instruction("mov", "bp", "[" + rel + id + "]");
               f = true;
            }
            if(f) {
                add_instruction("mov", "dx", "[bp]");
                add_instruction("pop", "bp");
            }
            else {
                add_instruction("mov", "dx", "[" + rel + "si]");
            }
            add_instruction("push", "dx", "");
         }
         else if(id2.size()) {
            if(p_fun->param_map.find(id) == p_fun->param_map.end()) {
               if(var_map[id]->type.find("*") != string::npos) {
                  //add_instruction("push", string("word [") + rel + id + "+" + struct_name + "." + id2+ string("]"));
                  add_instruction("mov", "bp", string("word [") + rel + id +  string("]"));
                  add_instruction("add", "bp", struct_name + "." + id2);
                  add_instruction("mov", "cx", "[bp]");
                  add_instruction("pop", "bp");
                  add_instruction("push", "cx");
               }
               else {
                  v = var_map[id];
cout << "id -> " << id << endl;
cout << "id2 -> " << id2 << endl;
cout << "type -> " << v->type << endl;
cout << "array_size -> " << v->array_size() << endl;
                  struc * p_struct = struc_map[get_struct_name(v->type)];
                  if(p_struct) {
                     var * v = p_struct->get_var(id2);
                     if(v) {
                        if(v->array_size() == 1) {
                           add_instruction("push", string("word [") + rel + id + "+" + struct_name + "." + id2 + string("]"));
                        }
                        else {
                           add_instruction("lea", "ax", string("[") + rel + id + "+" + struct_name + "." + id2 + string("]"));
                           add_instruction("push", "ax");
                        }
                     }
                  }
//cin.get();cin.get();
               }
            }
            else
               add_instruction("push", string("word [") + rel + id + "+" + struct_name + "." + id2 + string("]"));
         }
         else {
            var * v = var_map[id];
            if(v) {
               if(v->size_vec.size()) {
                  if(v->size_vec[0] > 1) {
                     add_instruction("lea", "ax", string("[") + rel + id + string("]"));
                     add_instruction("push", "ax", "");
                  }
                  else {
                     add_instruction("push", string("word [") + rel + id + string("]"));
                  }
               }
               else {
                  add_instruction("push", string("word [") + rel + id + string("]"));
               }
            }
            else {
               add_instruction("push", string("word [") + rel + id + string("]"));
            }
         }
         ret = true;
      }

      if(is_assign_operator(offset)
         || match(".", offset)
         || match("->", offset)
         || match("(", offset)
         || match("[", offset)) {
         var * v = var_map[id];
         string type = v->type;
         type = get_struct_name(type);
         struc * p_struc = struc_map[type];
         if(p_struc) {
            type = p_struc->get_type(id2);
            string temp = get_next_temp(2, type);
            add_instruction("pop", "word [bp+" + temp + "]");
            ret = continue_primary(temp, offset);
         }
         else {
            type = v->type;
            string temp = get_next_temp(2, type);
            add_instruction("pop", "word [bp+" + temp + "]");
            ret = continue_primary(temp, offset);
         }
      }


      return ret;
   }


   bool is_assign_operator(const size_t & offset) {
      bool ret = false;
      if(match("=", offset)
         || match("+=", offset)
         || match("-=", offset)
         || match("*=", offset)
         || match("%=", offset)
         || match("/=", offset)
         || match(">>=", offset)
         || match("<<=", offset)
         || match("&=", offset)
         || match("|=", offset)
         || match("^=", offset)) {
         ret = true;
      }
      return ret;
   }

   string get_size(string t) {
      string size;
      if(t == "char") {
         size = "1";
      }
      else if(t == "short") {
         size = "2";
      }
      else if(t == "int") {
         size = "4";
      }
      else if(t == "float") {
         size = "4";
      }
      else if(t == "long") {
         size = "8";
      }
      else if(t == "double") {
         size = "8";
      }
      else if(t.find("*") != string::npos) {
         size = to_string(DATA_WORD_SIZE);
      }
      else {
         if(t.find("[") != string::npos) {
            char * buffer = new char [ t.size() + 1 ];
            strcpy(buffer, t.c_str());
            char * ptr = strtok(buffer, " []");
            if(ptr) {
               string type = ptr;
               ptr = strtok(NULL, " []");
               while(ptr != NULL) {
                  if(is_digit(ptr[0])) {
                     size = ptr;
                  }
                  ptr = strtok(NULL, " []");
               }
               size = to_string(atoi(size.c_str()) 
                     * atoi(get_size(type).c_str()));
            }
            delete [] buffer;
         }
         if(var_map.find(t) != var_map.end()) {
            var * v = var_map[t];
            size = to_string(v->size() * v->array_size());
         }
         if(t.substr(0, 6) == "struct") {
            t = t.substr(7);
            if(struc_map.find(t) != struc_map.end()) {
               struc * p_st = struc_map[t];
               size = to_string(p_st->size());
            }
         }
         else {
            if(typedef_map.find(t) != typedef_map.end()) {
               t = typedef_map[t];
               size = get_size(t);
            }
         }
      }
      return size;
   }


   bool primary(size_t & offset) { 
      bool ret = false;
      if(match("(", offset)) {
         offset++;
         size_t temp = offset;
         string t = get_type(offset);
         if(t.size()) {
            if(match(")", offset)) {
               offset++;
               //bool b = in_expression;
               //in_expression = true;
               if(primary(offset)) {
                  if(match("(", offset)
                     || match("->", offset)
                     || match(".", offset)
                     || match("[", offset)
                     || is_assign_operator(offset)) {
                     string temp = get_next_temp();
                     add_instruction("pop", "word [bp+" + temp + "]");
                     continue_primary(temp, offset);
                  }
                  ret = true;
                  last_type = t;
               }
               //in_expression = b;
            }
         }
         if(t.size() == 0) {
            offset = temp;
            //bool b = in_expression;
            if(expression(offset)) {
               if(match(")", offset)) {
                  offset++;
                  if(match("(", offset)
                     || match("->", offset)
                     || match(".", offset)
                     || match("[", offset)
                     || is_assign_operator(offset)) {
                     string temp = get_next_temp();
                     add_instruction("pop", "word [bp+" + temp + "]");
                     continue_primary(temp, offset);
                  }
                  ret =  true;
               }
               else {
                  error(offset, "expecting: \")\"");
               }
            }
            else {
cout << "LEA..." << endl << flush;
               error(offset, "expecting: <expression>");
            }
            //in_expression = b;
         }
      }

      else if(match("sizeof", offset)) {
         offset++;
         if(match("(", offset)) { 
            offset++;
            string size;
            string t = get_type(offset);
            if(t.size() == 0) {
               if(expression(offset)) {
                  if(match(")", offset)) {
                     offset++;
                     size = get_size(last_type);
                     add_instruction("push", "word " + size);
                     ret = true;
                  }
               }
            }
            else if(match(")", offset)) {
               size = get_size(t);
               add_instruction("push", "word " + size);
               offset++;
               ret = true;
               last_type = "short";
            }
         }
      }

      else if(match(T_CHAR, offset)) {
         add_instruction("push", "word " + token_vec[offset]->value);
         offset++;
         ret = true;
         last_type = "short";
      }
      else if(match(T_STRING, offset)) {
         string label = get_string_const(token_vec[offset]->value);
         add_instruction("push", label);
         offset++;
         ret = true;
         last_type = "char *";
      }
      else if(match(T_INT, offset)) {
         add_instruction("push", token_vec[offset]->value);
         offset++;
         ret = true;
         last_type = "short";
      }
      else if(match("-", offset)) {
         offset++;
         primary(offset);
         add_instruction("pop", "dx");
         add_instruction("neg", "dx");
         add_instruction("push", "dx");
         ret = true;
      }
      else if(match("*", offset)) {
         offset++;
         
         bool old;
         
         old = get_value;
         get_value = true;

         bool ol = l_val;
        
         if(!on_right)
            l_val = true;
         else
            l_val = false;

         if(primary(offset)) {
            l_val = ol;

            last_type = trim_star(last_type);
            
            get_value = old;
            
            ret = true;
         }
      }
      else if(match("&", offset)) {
cout << "ADDRESS OF..." << endl << flush;
         offset++;
         bool old = get_addr;
         get_addr = true;
         if(primary(offset)) {
cout << "GOT PRIMARY..." << endl << flush;
            get_addr = old;
            ret = true;
         }
cout << "LEA: " << ret << endl << flush;
         last_type = last_type + " *";
      }
      else if(match(T_IDENTIFIER, offset)) {
         string id = token_vec[offset]->value;
         ret = continue_primary(id, offset);
      }
      return ret;
   }
};

}


using namespace cc16;

int
main(int argc, char ** argv)
{
   int rc = 0;
   try {
      if(argc < 3) {
         cerr << "usage: " << argv[0] << " <input>.c <output>.asm" << endl;
         exit(1);
      }

      c_compiler compiler(argv[1], argv[2]);


      rc = compiler.run();
   }
   catch(io_exception ioe) {
      cerr << "i/o exception..." << endl;
      cerr << ioe.message << endl;
      exit(1);
   }
   catch(lex_exception xe) {
      cerr << "lexical error: " << xe.line_number << endl;
      exit(1);
   }
   catch(syntax_exception syn) {
      cerr << "error:" << syn.line_number << ": " << syn.message << endl;
      exit(1);
   }
   catch(...) {
      cerr << "unknown exception..." << endl;
      exit(1);
   }
   return rc;
}
