#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <cstdlib>
#include "csv.h"

namespace gen_asm {

using namespace std;
using namespace csv_reader;

class Node {
public:
   string token,machine_code;
   map< string, Node* > node_map;

   Node(const string & tok) {
      token = tok;
   }
   Node() {
   }
   ~Node() {
   }
};

class ASM_generator {
   Node tree;

public:
   void process(const string & str, const string & code) {
      char * buffer = new char [ str.size() + 1 ];
      strcpy(buffer, str.c_str());
      char * ptr = strtok(buffer, ", ");
      vector< string > temp;
      while(ptr != NULL) {
         temp.push_back(ptr);
         ptr = strtok(NULL, ", ");
      }
      delete [] buffer;
      Node * p_node = &tree;
      string opcode,arg1,arg2;
      if(temp.size() == 3) {
         opcode = temp[0];
         arg1 = temp[1];
         arg2 = temp[2];
         p_node->node_map[opcode] = new Node(opcode);
         p_node->node_map[opcode]->node_map[arg1] = new Node(arg1);
         p_node->node_map[opcode]->node_map[arg1]->node_map[arg2] = new Node(arg2);
         p_node->node_map[opcode]->node_map[arg1]->node_map[arg2]->machine_code = code;
      } 
      else if(temp.size() == 2) {
         opcode = temp[0];
         arg1 = temp[1];
         p_node->node_map[opcode] = new Node(opcode);
         p_node->node_map[opcode]->node_map[arg1] = new Node(arg1);
         p_node->node_map[opcode]->node_map[arg1]->machine_code = code;
      }
      else if(temp.size() == 1) {
         opcode = temp[0];
         p_node->node_map[opcode] = new Node(opcode);
         p_node->node_map[opcode]->machine_code = code;
      }
   }

   string indent(size_t i) {
      string str;
      while(i) {
         str += "   ";
         i--;
      }
      return str;
   }

   void print_if(ostream & out, Node * p_node, int i, vector< string > & temp) {
      if(p_node && i < (int)temp.size()) {
         out << indent(i+1) << "if(str[" << i << "] == \"" << temp[i] << "\") {" << endl;
         for(map< string, Node* >::iterator ptr = p_node->node_map.begin();  
             ptr != p_node->node_map.end(); 
             ptr++) {
            if(ptr->second->machine_code.size()) {
               out << indent(i+2) << "return \"" << ptr->second->machine_code << "\";" << endl;
            }
            print_if(out, ptr->second, i+1, temp);
         }
         out << indent(i+1) << "}" << endl; 
      }
   }

   void print_if(ostream & out, vector< string > & temp) {
      print_if(out, &tree, 0, temp);
   }

   void run() {
      ifstream fin("code.csv", ios::in);
      ofstream fout("asmif.h", ios::ate | ios::trunc | ios::out);
      if(fin && fout) {
         csv_row_type row;
         char * buffer, * ptr;
         while(fin >> row) {
            vector< string > temp;
            buffer = new char [ row[0].size() + 1 ];
            strcpy(buffer, row[0].c_str());
            ptr = strtok(buffer, ", ");
            while(ptr != NULL) {
               temp.push_back(ptr);
               ptr = strtok(NULL, ", ");
            }
            delete [] buffer;
            process(row[0], row[1]);
            print_if(fout, temp);
         }
         fout.close();
         fin.close();
      }
   }
};

}

using namespace gen_asm;
using namespace std;

int
main(int argc, char ** argv)
{
   try {
      ASM_generator gen;
      gen.run();
   }
   catch(...) {
      cerr << "unknown exception..." << endl;
      exit(0);
   }
   return 0;
}
