/*



SIMPLE x86 16 BIT C COMPILER...



Author: Matthew W. Coan

Date: Tue Oct  1 20:49:22 EDT 2013



*/



#include <fstream>

#include <iostream>

#include <cstdlib>

#include <string>

#include <vector>

#include <list>

#include <map>

#include <sstream>



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 };



struct syntax_exception { 

   int line_number;

   const char * message;

   syntax_exception(int ln, const char * msg) { 

      line_number = ln; 

      message = msg;

   }

};



struct io_exception { 

   const char * message;

   io_exception(const char * msg) {

      message = msg;

   }

};



struct lex_exception { 

   int line_number;

   lex_exception(int ln) {

      line_number = ln;

   }

};



class token {

public:

   string value;

   token_type type;

   int lineno;

 

   token() { type = T_UNKNOWN; }

   token(const token & tok) { value = tok.value; type = tok.type; lineno = tok.lineno; }

   token(const string & v, token_type t, int lno) { value = v; type = t; lineno = lno; }

   ~token() { }



   token & operator=(const token & right) {

      value = right.value;

      type = right.type;

      lineno = right.lineno;

      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);



class var {

public:

   string type;

   string name;

   string value;

   size_t address;

   size_t array_size;

   var() { address = 0; array_size = 1; }

   var(const string & type,

       const string & name) {

      address = 0;

      this->type = type;

      this->name = name;

      array_size = 1;

   }

   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;



class function {

public:

   string name;

   string return_type;

   var_map_type var_map;

   var_map_type param_map;

   instruction_vector_type code;

};



typedef vector< var* > var_vector_type;



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();

      }

      return ret;

   }

};



int get_struct_size(const string & name) 

{

   int index = name.find(" ");

   index++;

   string nam = name.substr(index);

   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;

}



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;



class c_compiler {

   string infile;

   string outfile;

   const_map_type const_map;

   var_map_type var_map;

   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 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") {

         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 == "register"

         || 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 += "\',13,\'";

            i++;

         }

         else if(str[i] == '\\' && str[i+1] == 'r') {

            ret += "\',10,\'";

            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;

   }

   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 == "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;

                  }

               }

               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 == "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])) {

                        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") {

                                 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") {

                              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;

      }

   }

   void run() {

      lex();

      parse();

      optimize();

      emit();

   }

   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;

      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));

               }

               else {

                  token_vec.push_back(new token(str, T_INT, lineno));

               }

            }

            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));

               }

               else {

                  str = "_" + str;

                  token_vec.push_back(new token(str, T_IDENTIFIER, lineno));

               }

            }

            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 == '&') {

                     break;

                  }

                  if(!is_operator(ch)) break;

                  ch = fin.get();

               }

               token_vec.push_back(new token(str, T_OPERATOR, lineno));

            }

            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));

               }

               else if(str == "\'\\r\'") {

                  token_vec.push_back(new token("13", T_CHAR, lineno));

               }

               else if(str == "\'\\n\'") {

                  token_vec.push_back(new token("10", T_CHAR, lineno));

               }

               else if(str == "\'\\b\'") {

                  token_vec.push_back(new token("8", T_CHAR, lineno));

               }

               else if(str == "\'\\0\'") {

                  token_vec.push_back(new token("0", T_CHAR, lineno));

               }

               else {

                  //stringstream s;

                  //s << (int)str[1];

                  //s >> str;

                  token_vec.push_back(new token(str, T_CHAR, lineno));

               }

            }

            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));

            }

            else if(is_space(ch)) {

               if(ch == '\n') {

                  lineno++;

               }

            }

            else if(ch == '#') {

               while(ch != '\n' && fin) {

                  ch = fin.get();

               }

            }

            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() {

      ofstream fout(outfile.c_str(), ios::ate | ios::trunc | ios::out);

      if(fout) {

         fout << "[BITS 16]" << endl;

         fout << "[section text]" << endl << endl;

         fout << "org 100h" << endl << endl;

         fout << "jmp _main" << 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 << "%include \"io.asm\"" << endl;

         //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 1" << 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[ptr->first];

                  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;

            for(ptr = ptr2->second->var_map.begin(); 

                ptr != ptr2->second->var_map.end(); ptr++) {

               if(ptr2->second->param_map.find(ptr->first) == ptr2->second->param_map.end()) {

                  if(global_map.find(ptr2->first) != global_map.end()) {
                     address -= ptr->second->size() * ptr->second->array_size;

                     fout << "%define " << ptr->second->name << " " << address << endl;
                  }

               }

            }

            address = 4;

            for(ptr = ptr2->second->param_map.begin(); 

                ptr != ptr2->second->param_map.end(); ptr++) {

               if(global_map.find(ptr->first) != global_map.end()) {
                  fout << "%define " << ptr->second->name << " " << address << endl;

                  address += ptr->second->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;

               }

            }

            fout << "\tleave" << endl;

            fout << "\tret" << endl << endl;

            for(ptr = ptr2->second->var_map.begin(); 

                ptr != ptr2->second->var_map.end(); ptr++) {

               if(ptr2->second->param_map.find(ptr->first) == ptr2->second->param_map.end()) {

                   fout << "%undef " << ptr->second->name << endl;

               }

            }

            for(ptr = ptr2->second->param_map.begin(); 

                ptr != ptr2->second->param_map.end(); ptr++) {

               fout << "%undef " << ptr->second->name << endl;

            }

            fout << endl;

         }

         fout << endl;



         fout << "[section data]" << endl;

         for(i = 0; i < const_data.size(); i++) {

            fout << const_data[i] << 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++; 

            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 {

            throw syntax_exception(token_vec[offset]->lineno, "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;

      string type = get_type(offset);

      if(type.size() == 0) return false;

      while(match(T_IDENTIFIER, offset)) {

         string id = token_vec[offset]->value;

         p_struct->var_vec.push_back(new var(type, id));

         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 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;

                  }

               }

            }

         }

      }

      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 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;

                           }

                        }

                     }

                  }

               }

            } 

         }

      }

      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)) {

                  throw syntax_exception(token_vec[offset]->lineno, "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)) {

                  throw syntax_exception(token_vec[offset]->lineno, "expected: \"{\" or \";\"");

               }

               else {

                  offset++;

               }

            }

         }

      }

      var_map = temp;

      return ret;

   }

   bool global_variable_statement(size_t & offset) {

      bool ret = false;

      string type = get_type(offset);

      while(match(T_IDENTIFIER, offset)) {

         string id = token_vec[offset]->value;

         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;

         }

         offset++;

         var_map[id] = p_var;

         if(pf_map.find(type) != pf_map.end()) {

            pf_map[id] = true;

         }

         array_size = 1;

         if(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;

               offset++;

               if(match("]", offset)) {

                  offset++;

               }

            }

         }



         if(ttype.find("*") != string::npos) {

            stk_size += array_size * DATA_WORD_SIZE;

         }

         else if(ttype.find("short") != string::npos) {

            stk_size += array_size * 2;

         }

         else if(ttype.find("char") != string::npos) {

            stk_size += array_size; 

         }

         else if(ttype.find("int") != string::npos) {

            stk_size += 4 * array_size;

         }

         else if(ttype.find("float") != string::npos) {

            stk_size += 4 * array_size;

         }

         else if(ttype.find("long") != string::npos) {

            stk_size += 8 * array_size;

         }

         else if(ttype.find("double") != string::npos) {

            stk_size += 8 * array_size;

         }

         else if(ttype.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++;

            if(match("*", offset)) {

               is_star = true;

               offset++;

            }

            else {

               is_star = false;

            }

         }

         else {

            break;

         }

      }

      if(match(";", offset)) {

         offset++; 

         ret = true;

      }

      else {

         throw syntax_exception(token_vec[offset]->lineno, "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;

         }

         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 {

         throw syntax_exception(token_vec[offset]->lineno, "expecting: \";\"");

      }

      return ret;

   }



///////

   bool expression_statement(size_t & offset) {

      bool ret = false;

      if(expression(offset)) {

         if(match(";", offset)) {

            offset++; 

            ret = true;

         }

      }

      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);

            }

         }

      }

      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);

            }

         }

      }

      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;

            }

         }

      }

      return ret;

   }

   bool return_statement(size_t & offset) {

      bool ret = false;

      if(match("return", offset)) {

         offset++;

         if(match(";", offset)) {

            offset++;

            ret = true;

         }

         else if(expression(offset)) {

            add_instruction("pop", "ax");

            if(match(";", offset)) {

               offset++;

               ret = true;

            }

         }

      }

      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() {

      temp_count++;

      stringstream str;

      str << temp_count;

      string ret;

      str >> ret;

      ret = "temp" + ret;

      stk_size += DATA_WORD_SIZE;

      var * v = new var();

      v->name = ret;

      v->type = "short";

      var_map[v->name] = v;

      p_fun->var_map[v->name] = v;

      int sz = atoi(p_fun->code[allocate_index]->op.c_str());

      sz += DATA_WORD_SIZE;

      p_fun->code[allocate_index]->arg2 = to_string(sz);

      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;

         while(variable_statement(offset)) {

            ;

         }

         //if(stk_size != 0) {

            allocate_index = p_fun->code.size();

            add_instruction("sub", "sp", to_string(stk_size));

         //}

         while(statement(offset)) {

            ;

         }

for(size_t i = 0; i < 10 && (offset+i) < token_vec.size(); i++) {

cout << "COMPOUND: \"" << token_vec[offset+i]->value << "\"" << endl;

}

         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)) {

               throw syntax_exception(token_vec[offset]->lineno, 

                                      "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("pop", "al");

               /*

               add_instruction("mov", "si", "sp");

               add_instruction("add", "si", "1");

               add_instruction("mov", "al", "[si]");

               add_instruction("add", "sp", "1");

               */



               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) {

                  throw syntax_exception(token_vec[offset]->lineno, 

                                         "expected: <statement> after if statement\"");

               }

               add_instruction("jmp", the_end);

               add_instruction(end, "", "", "");

            }

            else {

               throw syntax_exception(token_vec[offset]->lineno, 

                                      "expected: <expression> after the \"if\" \"(\" <expression>\"");

            }

         }

         else {

            throw syntax_exception(token_vec[offset]->lineno, "expected: \"(\" after the \"if\"");

         }

         if(match("else", offset) && match("if", offset+1)) {

            offset++;

         }

      }

      if(match("else", offset)) {

         offset++;

         ret = statement(offset);

         if(!ret) {

            throw syntax_exception(token_vec[offset]->lineno, "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("pop", "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]);

                           }

                           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 {

                                 throw syntax_exception(token_vec[offset]->lineno, "expected: <statement>");

                              }

                           }

                           else {

                              throw syntax_exception(token_vec[offset]->lineno, "expected: \")\"");

                           }

                        }

                     }

                     else {

                        throw syntax_exception(token_vec[offset]->lineno, "expected: \";\"");

                     }

                  }

                  loop_cond = temp;

               }

               else {

                  throw syntax_exception(token_vec[offset]->lineno, "expected: \";\"");

               }

            }

         }

         else {

            throw syntax_exception(token_vec[offset]->lineno, "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("pop", "al");

                  

                  //add_instruction("mov", "si", "sp");

                  //add_instruction("add", "si", "1");

                  //add_instruction("mov", "al", "[si]");

                  //add_instruction("add", "sp", "1");



                  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 {

                     throw syntax_exception(token_vec[offset]->lineno, "expected: <statement>");

                  }

               }

               else {

                  throw syntax_exception(token_vec[offset]->lineno, "expected: \")\"");

               }

            }

            else {

               throw syntax_exception(token_vec[offset]->lineno, "expected: <expression>");

            }

         }

         else {

            throw syntax_exception(token_vec[offset]->lineno, "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);

                        }

                     }

                  }

                  loop_cond = temp;

               }

            } 

         }

      }

      return ret;

   }

   bool expression(size_t & offset) {

      return boolean(offset);

   }

   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", "dx");

               add_instruction("and", "dx", "bx");

               add_instruction("push", "dx");

            }

            else throw syntax_exception(token_vec[offset]->lineno, "expected: <boolean>");

         }

         else if(match("||", offset)) {

            offset++;

            if(boolean(offset)) {

               add_instruction("pop", "bx");

               add_instruction("pop", "dx");

               add_instruction("or", "dx", "bx");

               add_instruction("push", "dx");

            }

            else throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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("mov", "si", "sp");

                  //add_instruction("add", "si", "1");

                  //add_instruction("mov", "al", "[si]");

                  //add_instruction("add", "sp", "1");



                  add_instruction("cpop", "ah");

                  add_instruction("cpop", "al");



                  //add_instruction("pop", "al");

                  //add_instruction("pop", "ah");

                  

                  //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("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 throw syntax_exception(token_vec[offset]->lineno, "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 {

               throw syntax_exception(token_vec[offset]->lineno, "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 {

               throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "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("pop", "bx");

               add_instruction("pop", "dx");

               add_instruction("shl", "dx", "bx");

               add_instruction("push", "dx");

            }

            else throw syntax_exception(token_vec[offset]->lineno, "expected: <bitiops>");

         }

         else if(match(">>", offset)) {

            offset++;

            if(bitops(offset)) {

               add_instruction("pop", "bx");

               add_instruction("pop", "dx");

               add_instruction("shr", "dx", "bx");

               add_instruction("push", "dx");

            }

            else throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "expected: <bitiops>");

         }

         else if(match("&", offset)) {

            offset++;

            if(bitops(offset)) {

               add_instruction("pop", "bx");

               add_instruction("pop", "dx");

               add_instruction("and", "dx", "bx");

               add_instruction("push", "dx");

            }

            else throw syntax_exception(token_vec[offset]->lineno, "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 throw syntax_exception(token_vec[offset]->lineno, "expected: <bitiops>");

         }

      } 

      return ret;

   }

   bool expression_list(size_t & offset, size_t & size) {

      bool ret = false;

      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;

         }

         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]);

               }

            }

         }

      }

      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;

   }



   bool continue_primary(const string & id, size_t & offset) {

      bool ret = false;

      string id2;

      string struct_name;

      if(var_map.find(id) != var_map.end()) {

         var * v = var_map[id];

         last_type = v->value;

         if(v) {

            struct_name = v->type;

            if(struct_name.size() > 7) {

               struct_name = struct_name.substr(7);

            }

         }

      }

      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;

            }

         }

      }

      offset++;

      bool got_array = false;

      if(match("[", offset)) {

         offset++;

         if(expression(offset)) {

            if(match("]", offset)) {

               got_array = true;

               var * v = var_map[id];

               add_instruction("lea", "bx", "[bp+" + id + "]");

               add_instruction("pop", "dx");

               add_instruction("imul", "dx", to_string(v->size()));

               add_instruction("add", "bx", "dx");

               add_instruction("push", "bx");

               offset++;

               last_type = v->type;

            }

         }

      }

      if(match(".", offset)) {

         offset++;

         if(match(T_IDENTIFIER, offset)) {

            id2 = token_vec[offset]->value;

            offset++;

         }

      }

      if(match("->", offset)) {

         offset++;

         if(match(T_IDENTIFIER, offset)) {

            id2 = token_vec[offset]->value;

            offset++;

         }

      }

      if(match("++", offset)) {

         offset++;

         if(id2.size()) {

            if(p_fun->param_map.find(id) == p_fun->param_map.end()) 

               add_instruction("inc", "word [bp+" + id + "-" + struct_name + "." + id2 + "]");

            else 

               add_instruction("inc", "word [bp+" + id + "+" + struct_name + "." + id2 + "]");

         }

         else

            add_instruction("inc", "word [bp+" + 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 [bp+" + id + "-" + struct_name + "." + id2 + "]");

            else 

               add_instruction("dec", "word [bp+" + id + "+" + struct_name + "." + id2 + "]");

         }

         else 

            add_instruction("dec", "word [bp+" + id + "]");

         ret = true;

      }

      if(match("(", offset)) {

         offset++;

         size_t size = 0;

         if(match(")", offset)) {

            if(pf_map.find(id) != pf_map.end()) 

               add_instruction("call", "[bp+" + id + "]");

            else 

               add_instruction("call", id);

            if(size != 0) {

               add_instruction("add", "sp", to_string(size));

            }

            //if(pf) {

            //   if(pf->return_type != "void") {

            //      add_instruction("push", "ax");

            //   }

            //}

            offset++;

            ret = true;

         }

         else  if(expression_list(offset, size)) {

            if(match(")", offset)) {

               if(pf_map.find(id) != pf_map.end())

                  add_instruction("call", "[bp+" + id + "]");

               else

                  add_instruction("call", id);

               if(size != 0) {

                  add_instruction("add", "sp", to_string(size));

               }

               //if(pf) {

               //   if(pf->return_type != "void") {

               //      add_instruction("push", "ax");

               //   }

               //}

               offset++;

               ret = true;

            }

         }

      }



      if(got_array && !match("=", offset) && !match("+=", offset)) {

         add_instruction("pop", "bx");

         if(last_type == "char") {

            add_instruction("mov", "al", "[bx]");

            add_instruction("cpush", "al");

         }

         else {

            add_instruction("mov", "dx", "[bx]");

            add_instruction("push", "dx");

         }

         ret = true;

      }



      if(match("=", offset) || match("+=", offset)) {

         while(match("=", offset) || match("+=", 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", "[bp+" +  id + "-" + struct_name + "." + id2 + "]");

                     else

                        add_instruction("mov", "bx", "[bp+" +  id + "+" + struct_name + "." + id2 + "]");

                     add_instruction("pop", "dx");

                     add_instruction("add", "bx", "dx");

                     add_instruction("push", "bx");

                  }

                  else {

                     add_instruction("mov", "bx", "[bp+" +  id + "]");

                     add_instruction("pop", "dx");

                     add_instruction("add", "bx", "dx");

                     add_instruction("push", "bx");

                  }

               }

               var * v = var_map[id];

               if(v == 0) 

                  throw syntax_exception(token_vec[offset]->lineno, "unknown variable...");

               if(v->type == "char" && !got_array) {

                  add_instruction("mov", "si", "sp");

                  add_instruction("add", "si", "1");

                  add_instruction("mov", "al", "[si]");

                  add_instruction("add", "sp", "1");

               }

               if(!got_array)

                  add_instruction("pop", "ax");

               if(got_array) {

                  if(last_type == "char") {

                     add_instruction("pop", "bx");

                     add_instruction("cpop", "al");

                     add_instruction("mov", "[bx]", "al");

                     ret = true;

                  }

                  else {

                     add_instruction("pop", "dx");

                     add_instruction("pop", "bx");

                     add_instruction("mov", "[bx]", "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("lea", "bx", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"));

                     else

                        add_instruction("lea", "bx", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"));

                  }

                  else {

                     add_instruction("lea", "bx", string("[bp+") + id + string("]"));

                  }

                  

                  add_instruction("mov", "[bx]", "al");

               }

               else if(get_value) {

                  if(id2.size()) {

                     if(p_fun->param_map.find(id) == p_fun->param_map.end())

                        add_instruction("lea", "bx", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"));

                     else

                        add_instruction("lea", "bx", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"));

                  }

                  else {

                     add_instruction("lea", "bx", string("[bp+") + id + string("]"));

                  }

                  add_instruction("mov", "[bx]", "ax");

               }

               else if(id2.size()) {

                  if(p_fun->param_map.find(id) == p_fun->param_map.end()) 

                     add_instruction("mov", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"), "ax");

                  else

                     add_instruction("mov", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"), "ax");

               }

               else { 

                  add_instruction("mov", string("[bp+") + id + string("]"), "ax");

               }

               ret = true;

            }

            else {

cout << "MOV..." << endl << flush;

               throw syntax_exception(token_vec[offset]->lineno, "expecting: <expression>");

            }

            on_right = old2;

         }

      }

      if(!ret) {

         var * v = var_map[id];

         if(v == 0) 

            throw syntax_exception(token_vec[offset]->lineno, "unknown variable...");

         if(get_addr) {

            if(id2.size()) {

               if(p_fun->param_map.find(id) == p_fun->param_map.end())

                  add_instruction("lea", "dx", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

               else 

                  add_instruction("lea", "dx", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

            }

            else {

               add_instruction("lea", "dx", string("[bp+") + id + string("]"));

            }

            add_instruction("push", string("dx"));

         }

         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", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

               else

                  add_instruction("mov", "di", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

            }

            else {

               add_instruction("mov", "di", string("[bp+") + id + string("]"));

            }

            add_instruction("mov", "al", "[di]");

            add_instruction("cpush", "al");

            //add_instruction("mov", "si", "sp");

            //add_instruction("sub", "sp", "1");

            //add_instruction("mov", "[si]", "al");



            //add_instruction("push", "al");

            last_type = "char";

         }

         else if(get_value) {

            if(id2.size()) {

               if(p_fun->param_map.find(id) == p_fun->param_map.end())

                  add_instruction("mov", "di", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

               else

                  add_instruction("mov", "di", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

            }

            else {

               add_instruction("mov", "di", string("[bp+") + id + string("]"));

            }

            add_instruction("mov", "dx", "[di]");

            add_instruction("push", "dx");

            //add_instruction("mov", "si", "sp");

            //add_instruction("sub", "sp", "1");

            //add_instruction("mov", "[si]", "al");

         }

         else if(id2.size()) {

            if(p_fun->param_map.find(id) == p_fun->param_map.end())

               add_instruction("push", string("word [bp+") + id + "-" + struct_name + "." + id2+ string("]"));

            else

               add_instruction("push", string("word [bp+") + id + "+" + struct_name + "." + id2+ string("]"));

         }

         else 

            add_instruction("push", string("word [bp+") + id + string("]"));

         ret = true;

      }



      return ret;

   }



   bool is_assign_operator(const size_t & offset) {

      bool ret = false;

      if(match("=", offset)

         || match("+=", offset)) {

         ret = true;

      }

      return ret;

   }



   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++;

               if(primary(offset)) {

                  if(match("(", offset)

                     || match("->", offset)

                     || match(".", offset)

                     || match("[", offset)

                     || is_assign_operator(offset)) {

                     string temp = get_next_temp();

                     add_instruction("pop", temp);

                     continue_primary(temp, offset);

                  }

                  ret = true;

               }

            }

         }

         if(t.size() == 0) {

            offset = temp;

            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", temp);

                     continue_primary(temp, offset);

                  }

                  ret =  true;

               }

               else {

                  throw syntax_exception(token_vec[offset]->lineno, "expecting: \")\"");

               }

            }

            else {

cout << "LEA..." << endl << flush;

               throw syntax_exception(token_vec[offset]->lineno, "expecting: <expression>");

            }

         }

         

         if(ret) {

            if(match("=", offset)) {

               offset++;

               if(expression(offset)) {

                  ; 

               }

            }

         }

      }

      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 = get_value;

         get_value = true;

         if(primary(offset)) {

cout << "STAR: \"" << last_type << "\"" << endl;

            last_type = trim_star(last_type);

cout << "STAR: \"" << last_type << "\"" << endl;

//cin.get();cin.get();

            get_value = old;

            if(on_right) {

               if(last_type == "short") {

                  add_instruction("pop", "si");

                  add_instruction("mov", "bx", "[si]");

                  add_instruction("push", "bx");

               }

               else if(last_type == "char") {

                  add_instruction("pop", "si");

                  add_instruction("mov", "al", "[si]");

                  add_instruction("cpush", "al");

               }

               else {

                  add_instruction("pop", "si");

                  add_instruction("mov", "bx", "[si]");

                  add_instruction("push", "bx");

               }

            }

            ret = true;

            //string temp = get_next_temp();

            //continue_primary(temp, offset);

            if(match("(", offset)

               || match("->", offset)

               || match(".", offset)

               || match("[", offset)

               || is_assign_operator(offset)) {

               string temp = get_next_temp();

               add_instruction("pop", temp);

               continue_primary(temp, offset);

            }



/*

            if(match("=", offset)) {

               offset++;

               if(expression(offset)) {

                  ; 

               }

            }

*/



         }

      }

      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);

/*

         string id2;

         string struct_name;

         if(var_map.find(id) != var_map.end()) {

            var * v = var_map[id];

            last_type = v->value;

            if(v) {

               struct_name = v->type;

               if(struct_name.size() > 7) {

                  struct_name = struct_name.substr(7);

               }

            }

         }

         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;

               }

            }

         }

         offset++;

         bool got_array = false;

         if(match("[", offset)) {

            offset++;

            if(expression(offset)) {

               if(match("]", offset)) {

                  got_array = true;

                  var * v = var_map[id];

                  add_instruction("lea", "bx", "[bp+" + id + "]");

                  add_instruction("pop", "dx");

                  add_instruction("imul", "dx", to_string(v->size()));

                  add_instruction("add", "bx", "dx");

                  add_instruction("push", "bx");

                  offset++;

                  last_type = v->type;

               }

            }

         }

         if(match(".", offset)) {

            offset++;

            if(match(T_IDENTIFIER, offset)) {

               id2 = token_vec[offset]->value;

               offset++;

            }

         }

         if(match("->", offset)) {

            offset++;

            if(match(T_IDENTIFIER, offset)) {

               id2 = token_vec[offset]->value;

               offset++;

            }

         }

         if(match("++", offset)) {

            offset++;

            if(id2.size()) {

               if(p_fun->param_map.find(id) == p_fun->param_map.end()) 

                  add_instruction("inc", "word [bp+" + id + "-" + struct_name + "." + id2 + "]");

               else 

                  add_instruction("inc", "word [bp+" + id + "+" + struct_name + "." + id2 + "]");

            }

            else

               add_instruction("inc", "word [bp+" + 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 [bp+" + id + "-" + struct_name + "." + id2 + "]");

               else 

                  add_instruction("dec", "word [bp+" + id + "+" + struct_name + "." + id2 + "]");

            }

            else 

               add_instruction("dec", "word [bp+" + id + "]");

            ret = true;

         }

         if(match("(", offset)) {

            offset++;

            size_t size = 0;

            if(match(")", offset)) {

               if(pf_map.find(id) != pf_map.end()) 

                  add_instruction("call", "[bp+" + id + "]");

               else 

                  add_instruction("call", id);

               if(size != 0) {

                  add_instruction("add", "sp", to_string(size));

               }

               //if(pf) {

               //   if(pf->return_type != "void") {

               //      add_instruction("push", "ax");

               //   }

               //}

               offset++;

               ret = true;

            }

            else  if(expression_list(offset, size)) {

               if(match(")", offset)) {

                  if(pf_map.find(id) != pf_map.end())

                     add_instruction("call", "[bp+" + id + "]");

                  else

                     add_instruction("call", id);

                  if(size != 0) {

                     add_instruction("add", "sp", to_string(size));

                  }

                  //if(pf) {

                  //   if(pf->return_type != "void") {

                  //      add_instruction("push", "ax");

                  //   }

                  //}

                  offset++;

                  ret = true;

               }

            }

         }



         if(got_array && !match("=", offset) && !match("+=", offset)) {

            add_instruction("pop", "bx");

            if(last_type == "char") {

               add_instruction("mov", "al", "[bx]");

               add_instruction("cpush", "al");

            }

            else {

               add_instruction("mov", "dx", "[bx]");

               add_instruction("push", "dx");

            }

            ret = true;

         }



         if(match("=", offset) || match("+=", offset)) {

            while(match("=", offset) || match("+=", 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", "[bp+" +  id + "-" + struct_name + "." + id2 + "]");

                        else

                           add_instruction("mov", "bx", "[bp+" +  id + "+" + struct_name + "." + id2 + "]");

                        add_instruction("pop", "dx");

                        add_instruction("add", "bx", "dx");

                        add_instruction("push", "bx");

                     }

                     else {

                        add_instruction("mov", "bx", "[bp+" +  id + "]");

                        add_instruction("pop", "dx");

                        add_instruction("add", "bx", "dx");

                        add_instruction("push", "bx");

                     }

                  }

                  var * v = var_map[id];

                  if(v == 0) 

                     throw syntax_exception(token_vec[offset]->lineno, "unknown variable...");

                  if(v->type == "char" && !got_array) {

                     add_instruction("mov", "si", "sp");

                     add_instruction("add", "si", "1");

                     add_instruction("mov", "al", "[si]");

                     add_instruction("add", "sp", "1");

                  }

                  if(!got_array)

                     add_instruction("pop", "ax");

                  if(got_array) {

                     if(last_type == "char") {

                        add_instruction("pop", "bx");

                        add_instruction("cpop", "al");

                        add_instruction("mov", "[bx]", "al");

                        ret = true;

                     }

                     else {

                        add_instruction("pop", "dx");

                        add_instruction("pop", "bx");

                        add_instruction("mov", "[bx]", "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("lea", "bx", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"));

                        else

                           add_instruction("lea", "bx", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"));

                     }

                     else {

                        add_instruction("lea", "bx", string("[bp+") + id + string("]"));

                     }

                     

                     add_instruction("mov", "[bx]", "al");

                  }

                  else if(get_value) {

                     if(id2.size()) {

                        if(p_fun->param_map.find(id) == p_fun->param_map.end())

                           add_instruction("lea", "bx", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"));

                        else

                           add_instruction("lea", "bx", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"));

                     }

                     else {

                        add_instruction("lea", "bx", string("[bp+") + id + string("]"));

                     }

                     add_instruction("mov", "[bx]", "ax");

                  }

                  else if(id2.size()) {

                     if(p_fun->param_map.find(id) == p_fun->param_map.end()) 

                        add_instruction("mov", string("[bp+") + id + "-" + struct_name + "." + id2 + string("]"), "ax");

                     else

                        add_instruction("mov", string("[bp+") + id + "+" + struct_name + "." + id2 + string("]"), "ax");

                  }

                  else { 

                     add_instruction("mov", string("[bp+") + id + string("]"), "ax");

                  }

                  ret = true;

               }

               else {

cout << "MOV..." << endl << flush;

                  throw syntax_exception(token_vec[offset]->lineno, "expecting: <expression>");

               }

               on_right = old2;

            }

         }

         if(!ret) {

            var * v = var_map[id];

            if(v == 0) 

               throw syntax_exception(token_vec[offset]->lineno, "unknown variable...");

            if(get_addr) {

               if(id2.size()) {

                  if(p_fun->param_map.find(id) == p_fun->param_map.end())

                     add_instruction("lea", "dx", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

                  else 

                     add_instruction("lea", "dx", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

               }

               else {

                  add_instruction("lea", "dx", string("[bp+") + id + string("]"));

               }

               add_instruction("push", string("dx"));

            }

            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", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

                  else

                     add_instruction("mov", "di", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

               }

               else {

                  add_instruction("mov", "di", string("[bp+") + id + string("]"));

               }

               add_instruction("mov", "al", "[di]");

               add_instruction("cpush", "al");

               //add_instruction("mov", "si", "sp");

               //add_instruction("sub", "sp", "1");

               //add_instruction("mov", "[si]", "al");



               //add_instruction("push", "al");

               last_type = "char";

            }

            else if(get_value) {

               if(id2.size()) {

                  if(p_fun->param_map.find(id) == p_fun->param_map.end())

                     add_instruction("mov", "di", string("[bp+") + id + "-" + struct_name + "." + id2+ string("]"));

                  else

                     add_instruction("mov", "di", string("[bp+") + id + "+" + struct_name + "." + id2+ string("]"));

               }

               else {

                  add_instruction("mov", "di", string("[bp+") + id + string("]"));

               }

               add_instruction("mov", "dx", "[di]");

               add_instruction("cpush", "dx");

               //add_instruction("mov", "si", "sp");

               //add_instruction("sub", "sp", "1");

               //add_instruction("mov", "[si]", "al");

            }

            else if(id2.size()) {

               if(p_fun->param_map.find(id) == p_fun->param_map.end())

                  add_instruction("push", string("word [bp+") + id + "-" + struct_name + "." + id2+ string("]"));

               else

                  add_instruction("push", string("word [bp+") + id + "+" + struct_name + "." + id2+ string("]"));

            }

            else 

               add_instruction("push", string("word [bp+") + id + string("]"));

            ret = true;

         }

         */

      }

      return ret;

   }

};



int

main(int argc, char ** argv)

{

   try {

      if(argc != 3) {

         cerr << "usage: " << argv[0] << " <input>.c <output>.asm" << endl;

         exit(1);

      }



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



      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 0;

}