#ifndef _BYTE_CODE_H
#define _BYTE_CODE_H

/*

Java C++ Macros For running Java Byte Code in a native way.

Author: Matthew W. Coan
Date: Thu Nov 29 18:23:08 EST 2012

*/

#include <stack>
#include <vector>
#include <string>
#include <iostream>
#include "jstack.h"

using namespace std;

typedef stack< void* > stack_type;
//typedef Stack stack_type;
typedef vector< string > string_vector_type;

namespace java {
namespace lang {
class Object {
public:
   void _init_() { }
};
}
}

stack_type * the_stack;

#define PUTSTATIC(c,f,t) \
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   c::f = arg1;

#define GETSTATIC(c,f,t) the_stack->push((int)(&c::f));

#define PUTFIELD(c,f,t) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   ((c*)arg1)->f = arg2;

#define GETFIELD(c,f,t) \
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(((c*)arg1)->f));

#define ASTORE(a) var[a] = the_stack->top(); the_stack->pop();

#define DUP() ptr1 = the_stack->top(); the_stack->push(ptr1);

#define NEW(C) the_stack->push(new C());

#define ALOAD(a) the_stack->push(var[a]);

#define GOTO(L) goto L;

#define IPUSH(a) the_stack->push((void*)a);

#define BIPUSH(a) the_stack->push((void*)a);

#define ISTORE(a) var[a] = the_stack->top(); the_stack->pop();
#define ISTORE_1() var[0] = the_stack->top(); the_stack->pop();
#define ISTORE_2() var[1] = the_stack->top(); the_stack->pop();
#define ISTORE_3() var[2] = the_stack->top(); the_stack->pop();

#define ILOAD(a) the_stack->push((void*)var[a]);
#define ILOAD_1() the_stack->push((void*)var[0]);
#define ILOAD_2() the_stack->push((void*)var[1]);
#define ILOAD_3() the_stack->push((void*)var[2]);

#define IINC(a,b) *((int*)&(var[a])) += b;

#define IADD() \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(arg1 + arg2));

#define ISUB() \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(arg1 - arg2));

#define IMUL() \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(arg1 * arg2));

#define IDIV() \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(arg1 / arg2));

#define IREM() \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   the_stack->push((void*)(arg1 % arg2));

#define IF_ICMPNE(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 != arg2) goto L;

#define IF_ICMPEQ(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 == arg2) goto L;

#define IF_ICMPLT(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 < arg2) goto L;

#define IF_ICMPGT(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 > arg2) goto L;

#define IF_ICMPLE(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 <= arg2) goto L;

#define IF_ICMPGE(L) \
   arg2 = (int)the_stack->top();\
   the_stack->pop();\
   arg1 = (int)the_stack->top();\
   the_stack->pop();\
   if(arg1 >= arg2) goto L;


#define RETURN2(code) return code;

#define RETURN() return;

#define PRINT(v) cout << "VALUE = " << v << endl;

#define LDC(m) ptr = m; the_stack->push((void*)ptr);

#define INVOKESTATIC(function,type_string) function();

#define INVOKEVIRTUAL(type,function,type_string) {\
type* object = (type*)the_stack->top();\
the_stack->pop();\
object->function();\
}

#define INVOKESPECIAL(type,function,type_string) {\
type* object = (type*)the_stack->top();\
the_stack->pop();\
object->function();\
}

typedef string String;


class IO {
public:
   static void print() {
      char * str = (char*)the_stack->top();
      the_stack->pop();
      cout << str << flush;
   }

   static void println() {
      char * str = (char*)the_stack->top();
      the_stack->pop();
      cout << str << endl;
   }

   static void printInt() {
      int i = (int)the_stack->top();
      the_stack->pop();
      cout << i << endl;
   }
};

#endif
