#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;

string read_line(istream & in) 
{
   string ret;
   char ch;
   ch = in.get();
   while(in) {
      if(ch == '\n')
         break;
      ret += ch;
      ch = in.get();
   }
   return ret;
}

string filter(const string & arg)
{
   string ret;
   for(size_t i = 0; i < arg.size(); i++) {
      if(arg[i] == '.')
         ret += "L";
      else
         ret += arg[i];
   }
   return ret;
}

string filter2(const string & arg)
{
   string ret;
   char * buffer;
   
   buffer = new char [arg.size()+1];
   memset(buffer, 0, arg.size()+1);
   
   strcpy(buffer, arg.c_str());

   for(size_t i = 0; i < arg.size(); i++) {
      if(buffer[i] == '.') {
         buffer[i] = 'L';
      }
   }

   char * ptr = strtok(buffer, " \t");
   while(ptr != NULL) {
      if(ret.size())
         ret += "\t";
      if(strcmp(ptr, "br") == 0)
         ret += "jmp";
      else if(strcmp(ptr, "beq") == 0)
         ret += "je";
      else if(strcmp(ptr, "bne") == 0)
         ret += "jne";
      else if(strcmp(ptr, "bge") == 0)
         ret += "jge";
      else if(strcmp(ptr, "ble") == 0)
         ret += "jle";
      else if(strcmp(ptr, "blt") == 0)
         ret += "jl";
      else 
         ret += string(ptr);
      ptr = strtok(NULL, " \t");
   }

   delete [] buffer;

   return ret;
}

string clean(const string & line)
{
   string ret;
   for(size_t i = 0; i < line.size(); i++) {
      if(line[i] == '*')
         ;
      else if(line[i] == '#')
         ;
      else if(line[i] == '$')
         ret += "0x";
      else 
         ret += line[i];
   }
   return ret;
}

bool
is_register(const char * reg)
{
   bool ret = false;
   if(strcmp(reg, "ax") == 0
      || strcmp(reg, "al") == 0
      || strcmp(reg, "bx") == 0
      || strcmp(reg, "dx") == 0
      || strcmp(reg, "si") == 0
      || strcmp(reg, "sp") == 0
      || strcmp(reg, "bp") == 0) {
      ret = true;
   }
   return ret;
}

int
clean_bcc(const char * ifile, 
          const char * ofile)
{
   string line;
   const size_t MAX = 1024;
   char buffer[MAX];
   string temp;
   string temp2;
   size_t count = 0;
   char * ptr;
   size_t i;
 
   ifstream in(ifile, ios::in);
   ofstream out(ofile, ios::out | ios::app);

   if(!in || !out) {
      cerr << "file input output error..." << endl;
      return 1;
   }

   while(in) {
      line = clean(read_line(in));
      if(line.size() == 0)
         ;
      else if(line.find("export") != string::npos)
         ;
      else if(line.find(".globl") != string::npos)
         ;
      else if(line.find(".bss") != string::npos)
         ;
      else if(line.find(".data") != string::npos)
         ;
      else if(line.find(".text") != string::npos)
         ;
      else if(line.find("fail!") != string::npos)
         ;
      else if(line.find("..FF") != string::npos)
         ;
      else if(line.find(".comm") != string::npos) {
         line = line.substr(5);
         temp = "";

         for(i = 0; i < line.size(); i++) {
            if(line[i] == ',') {
               break;
            }
            temp += line[i];
         }

         i++;
    
         temp2 = "";

         while(i < line.size()) {
            temp2 += line[i];
            i++;
         }

         //out << temp << ":\tresb " << hex << temp2 << dec << endl << flush;
         out << temp << ":\ttimes " << temp2.c_str() << dec << " db 0" << endl << flush;
         //cin.get();cin.get();
         //cout << temp << ":\tdb " << temp2 << endl << flush;
      }
      else if(line.find("cs") != string::npos && line.find("seg") != string::npos) {
         out << "\tmov\tal,[cs:bx]" << endl;
         out << "\tmov\t[temp],al" << endl;
         out << "\tmov\tbyte [temp+1],0" << endl;
         out << "\tmov\tax,[temp]" << endl << flush;
      }

      else if(line.find("[bx]") != string::npos && line.find("mov") != string::npos) {
         size_t i;
         string temp;
         for(i = 0; i < line.size(); i++) {
            if(line[i] == ',') {
               break;
            }
            else {
               temp += line[i];
            }
         }
         temp += ",";
         i++;
         string temp2;
         while(i < line.size()) {
            if(line[i] == '[')
               break;
            temp2 += line[i];
            i++;
         }
         if(temp2 == "al") {
            string op = "mov";
            string num;
            for(i = 4; line[i] != '['; i++) {
               num += line[i];
            }
            if(num == "") {
               out << "\t" << op << "\t[bx],al" << endl << flush;
            }
            else if(num[0] == '-') {
               out << "\t" << op << "\t[bx" << num << "],al" << endl << flush;
            }
            else {
               out << "\t" << op << "\t[bx+" << num << "],al" << endl << flush;
            }
            //out << line << endl << flush;
         }
         else if(temp2 == "ax") {
            string op = "mov";
            out << "\t" << op << "\t[bx],ax" << endl << flush;
         }
         else if(temp2 == "si") {
            string op = "mov";
            out << "\t" << op << "\t[bx],si" << endl << flush;
         }
         else {
            if(temp2 == "")
               out << "\t" << temp << "[bx]" << endl << flush;
            else if(temp2[0] == '-')
               out << "\t" << temp << "[bx" << temp2 << "]" << endl << flush;
            else
               out << "\t" << temp << "[bx+" << temp2 << "]" << endl << flush;
         }
      }

      else if(line.find("[bx]") != string::npos && line.find("br") != string::npos) {
         if(line.size() < MAX) {
            strcpy(buffer, line.c_str());
            char * p = strstr(buffer, "[");
            char * p0 = p;
            p0--;
            string temp;
            while(*p0 != ' ' && *p0 != '\t') {
               p0--;
            }
            p0++;
            while(*p0 != '[') {
               temp += *p0;
               p0++;
            }
            out << "\tjmp\tword [bx+" << filter(temp) << "]" << endl << flush;
         }
      }
      else if(line.find("[bx]") != string::npos) {
         size_t i;
         string temp;
         for(i = 0; i < line.size(); i++) {
            if(line[i] == ',') {
               break;
            }
            else {
               temp += line[i];
            }
         }
         temp += ",";
         i++;
         string temp2;
         while(i < line.size()) {
            if(line[i] == '[')
               break;
            temp2 += line[i];
            i++;
         }
         if(line.find("push") != string::npos) {
            if(temp2 == "") {
               out << "\tpush\tword [bx]" << endl << flush;
            }
            else if(temp2[0] == '-') {
               out << "\tpush\tword [bx" << temp2 << "]" << endl << flush;
            }
            else {
               out << "\tpush\tword [bx+" << temp2 << "]" << endl << flush;
            }
         }
         else if(temp2 == "al") {
            out << line << endl << flush;
         }
         else {
            if(temp2 == "") 
               out << "\t" << temp << "[bx]" << endl << flush;
            else if(temp2[0] == '-')
               out << "\t" << temp << "[bx" << temp2 << "]" << endl << flush;
            else
               out << "\t" << temp << "[bx+" << temp2 << "]" << endl << flush;
         }
      }
      else if(line.find("[si]") != string::npos && line.find("mov") != string::npos) {
         size_t i;
         string temp;
         for(i = 0; i < line.size(); i++) {
            if(line[i] == ',') {
               break;
            }
            else {
               temp += line[i];
            }
         }
         temp += ",";
         i++;
         string temp2;
         while(i < line.size()) {
            if(line[i] == '[')
               break;
            temp2 += line[i];
            i++;
         }
         if(temp2 == "al") {
            string op = "mov";
            string num;
            for(int i = 4; i < line.size() && line[i] != '['; i++) {
               num += line[i];
            }
            if(num[0] == '-') {
               out << "\t" << op << "\t[si" << num << "],al" << endl << flush;
            }
            else {
               out << "\t" << op << "\t[si+" << num << "],al" << endl << flush;
            }
            //out << line << endl << flush;
         }
         else if(temp2 == "bx") {
            string op = "mov";
            string num;
            for(int i = 4; i < line.size() && line[i] != '['; i++) {
               num += line[i];
            }
            if(num.size() == 0) {
               out << "\t" << op << "\t[si],bx" << endl << flush;
            }
            else if(num[0] == '-') {
               out << "\t" << op << "\t[si" << num << "],bx" << endl << flush;
            }
            else {
               out << "\t" << op << "\t[si+" << num << "],bx" << endl << flush;
            }
            //out << line << endl << flush;
         }
         else {
            if(temp2 == "")
               out << "\t" << temp << "[si]" << endl << flush;
            else if(temp2[0] == '-')
               out << "\t" << temp << "[si" << temp2 << "]" << endl << flush;
            else
               out << "\t" << temp << "[si+" << temp2 << "]" << endl << flush;
         }
      }
      else if(line.find("[bp]") != string::npos) {
         string reg;
         if(line.size() < MAX) {
            strcpy(buffer, line.c_str());
            ptr = strtok(buffer, " ,\r\n\t");
            count = 0;
            bool is_al = false;
            string word;
            bool lea;
            lea = false;
            string op = ptr;
            while(ptr != NULL) {
               if(strcmp(ptr, "al") == 0)
                  word = "byte";
               else if(word.size() == 0) 
                  word = "word";
               if(strcmp(ptr, "lea") == 0)
                  lea = true;
               temp2 = string(ptr);
               if(op != "push") {
                  word = "";
               }
               if(count == 2) {
                  temp += ",";
                  temp2 = "";
                  for(i = 0; i < strlen(ptr); i++) {
                     if(ptr[i] == '[') break;
                     temp2 += ptr[i];
                  }
                  if(temp2 != "" && !is_register(temp2.c_str()) && atoi(temp2.c_str()) < 0) {
                      if(lea)
                         word = "";
                      temp2 = word + string(" [bp") + temp2 + string("]");
                  }
                  else if(temp2 != "" && !is_register(temp2.c_str()) && atoi(temp2.c_str()) >= 0) {
                      if(lea)
                         word = "";
                      if(temp2[0] == '-')
                         temp2 = word + string(" [bp") + temp2 + string("]");
                      else
                         temp2 = word + string(" [bp+") + temp2 + string("]");
                  }
                  else if(temp2 != "" && !is_register(temp2.c_str())) {
                      if(lea)
                         word = "";
                      if(temp2[0] == '-')
                         temp2 = word + string(" [bp") + temp2 + string("]");
                      else
                         temp2 = word + string(" [bp+") + temp2 + string("]");
                  }
               }
               else if(count == 1) {
                  temp += "\t";
                  temp2 = "";
                  for(i = 0; i < strlen(ptr); i++) {
                     if(ptr[i] == '[') break;
                     temp2 += ptr[i];
                  }
                  if(temp2 != "" && !is_register(temp2.c_str()) && atoi(temp2.c_str()) < 0) {
                     if(lea)
                        word = "";
                     temp2 = word + string(" [bp") + temp2 + string("]");
                  }
                  else if(temp2 != "" && !is_register(temp2.c_str()) && atoi(temp2.c_str()) >= 0) {
                     if(lea)
                        word = "";
                     if(temp2[0] == '-')
                        temp2 = word + string(" [bp") + temp2 + string("]");
                     else
                        temp2 = word + string(" [bp+") + temp2 + string("]");
                  }
                  else if(temp2 != "" && is_register(temp2.c_str()) && atoi(temp2.c_str()) >= 0) {
                     temp2 = word + string(" ") + temp2;
                  }
                  else if(!is_register(temp2.c_str())) {
                     if(temp2[0] == '-')
                        temp2 = word + string(" [bp") + temp2 + string("]");
                     else
                        temp2 = word + string(" [bp+") + temp2 + string("]");
                  }
                  else {
                     temp2 = word + string(" ") + temp2;
                  }
               }
               else if(temp.size())
                  temp += "\t";
               temp += filter(temp2);
               temp2 = "";
               ptr = strtok(NULL, ", \r\n\t");
               count++;
            }
            line = temp;
         }
         temp2 = temp = "";
         out << '\t' << line << endl << flush;
      }
      else if(line.find(".ascii") != string::npos) {
         line = line.substr(6);
         out << "db " << line << endl << flush;
      }
      else if(line.find(".byte") != string::npos) {
         line = line.substr(5);
         out << "db " << clean(line) << endl << flush;
      }
      else if(line.find(".word") != string::npos) {
         line = line.substr(5);
         out << "dw " << filter(line) << endl << flush;
      }
      else if(line[0] == '!')
         ;
      else if(line[0] == '.') {
         line[0] = 'L';
         out << line << endl << flush;
      }
      else if(line.find(":") != string::npos) {
         out << filter2(line) << endl << flush;
      }
      else {
         out << '\t' << filter2(line) << endl << flush;
      }
   }

   return 0;
}
