--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+
+#include <gc.h>
+
+#include "../../../include/oberon.h"
+#include "../../oberon-internals.h"
+#include "generator-jvm.h"
+
+char *
+new_string(const char * format, ...)
+{
+ va_list ptr;
+ va_start(ptr, format);
+
+ char buf[1024];
+ vsnprintf(buf, 1024, format, ptr);
+
+ va_end(ptr);
+
+ char * result;
+ int size;
+
+ size = strlen(buf);
+ result = GC_MALLOC(size + 1);
+ memset(result, 0, size);
+ strncpy(result, buf, size);
+
+ return result;
+}
+
+void
+oberon_generator_init_context(oberon_context_t * ctx)
+{
+ gen_context_t * gen_context = GC_MALLOC(sizeof *gen_context);
+ memset(gen_context, 0, sizeof *gen_context);
+
+ ctx -> gen_context = gen_context;
+}
+
+void
+oberon_generator_destroy_context(oberon_context_t * ctx)
+{
+ ctx -> gen_context = NULL;
+}
+
+static char * get_class_full_name(oberon_context_t * ctx, oberon_type_t * type);
+
+static char *
+get_descriptor(oberon_context_t * ctx, oberon_type_t * type)
+{
+ char * desc;
+
+ switch(type -> class)
+ {
+ case OBERON_TYPE_VOID:
+ return new_string("V");
+ break;
+ case OBERON_TYPE_INTEGER:
+ switch(type -> size)
+ {
+ case 1:
+ return new_string("B");
+ break;
+ case 2:
+ return new_string("S");
+ break;
+ case 4:
+ return new_string("I");
+ break;
+ case 8:
+ return new_string("J");
+ break;
+ default:
+ oberon_error(ctx, "get_descriptor: unsupported int size %i", type -> size);
+ break;
+ }
+ break;
+ case OBERON_TYPE_REAL:
+ switch(type -> size)
+ {
+ case 4:
+ return new_string("F");
+ break;
+ case 8:
+ return new_string("D");
+ break;
+ default:
+ oberon_error(ctx, "get_descriptor: unsupported float size %i", type -> size);
+ break;
+ }
+ break;
+ case OBERON_TYPE_BOOLEAN:
+ return new_string("Z");
+ break;
+ case OBERON_TYPE_PROCEDURE:
+ case OBERON_TYPE_RECORD:
+ desc = get_class_full_name(ctx, type);
+ return new_string("L%s;", desc);
+ break;
+ case OBERON_TYPE_ARRAY:
+ desc = get_descriptor(ctx, type -> base);
+ return new_string("[%s", desc);
+ break;
+ default:
+ oberon_error(ctx, "print_descriptor: unsupported type class %i", type -> class);
+ break;
+ }
+
+ return NULL;
+}
+
+static char
+get_prefix(oberon_context_t * ctx, oberon_type_t * type)
+{
+ int size = type -> size;
+ switch(type -> class)
+ {
+ case OBERON_TYPE_BOOLEAN:
+ case OBERON_TYPE_INTEGER:
+ return (size <= 4) ? ('i') : ('l');
+ break;
+ case OBERON_TYPE_PROCEDURE:
+ case OBERON_TYPE_ARRAY:
+ case OBERON_TYPE_RECORD:
+ case OBERON_TYPE_POINTER:
+ return 'a';
+ break;
+ case OBERON_TYPE_REAL:
+ return (size <= 4) ? ('f') : ('d');
+ break;
+ }
+
+ oberon_error(ctx, "get_prefix: wat");
+ return '!';
+}
+
+static char *
+get_field_full_name(oberon_context_t * ctx, oberon_object_t * x)
+{
+ return new_string("%s/%s", x -> module -> name, x -> name);
+}
+
+static char *
+get_class_full_name(oberon_context_t * ctx, oberon_type_t * type)
+{
+ int rec_id;
+ char * name = NULL;
+
+ switch(type -> class)
+ {
+ case OBERON_TYPE_PROCEDURE:
+ name = new_string("SYSTEM$PROCEDURE");
+
+ char * desc;
+ desc = get_descriptor(ctx, type -> base);
+ name = new_string("%s$%s", name, desc);
+
+ int num = type -> num_decl;
+ oberon_object_t * arg = type -> decl;
+ for(int i = 0; i < num; i++)
+ {
+ desc = get_descriptor(ctx, arg -> type);
+ name = new_string("%s%s", name, desc);
+ arg = arg -> next;
+ }
+
+ break;
+ case OBERON_TYPE_RECORD:
+ assert(type -> module);
+ assert(type -> module -> gen_mod);
+ rec_id = type -> gen_type -> rec_id;
+ name = new_string("%s$RECORD%i", type -> module -> name, rec_id);
+ break;
+ default:
+ oberon_error(ctx, "get_record_full_name: unk type class %i", type -> class);
+ break;
+ }
+
+ return name;
+}
+
+static char *
+get_procedure_signature(oberon_context_t * ctx, oberon_type_t * proc)
+{
+ char * signature;
+ char * desc;
+
+ signature = new_string("(");
+
+ int num = proc -> num_decl;
+ oberon_object_t * arg = proc -> decl;
+ for(int i = 0; i < num; i++)
+ {
+ desc = get_descriptor(ctx, arg -> type);
+ signature = new_string("%s%s", signature, desc);
+ arg = arg -> next;
+ }
+
+ desc = get_descriptor(ctx, proc -> base);
+ signature = new_string("%s)%s", signature, desc);
+
+ return signature;
+}
+
+static void
+oberon_generate_procedure_class(oberon_context_t * ctx, oberon_type_t * proc)
+{
+ FILE * fp;
+ char * cname;
+ char * fname;
+ char * signature;
+
+ cname = get_class_full_name(ctx, proc);
+ fname = new_string("%s.j", cname);
+
+ fp = fopen(fname, "w");
+
+ fprintf(fp, ".source SYSTEM\n");
+ fprintf(fp, ".class public abstract %s\n", cname);
+ fprintf(fp, ".super java/lang/Object\n\n");
+
+ signature = get_procedure_signature(ctx, proc);
+
+ fprintf(fp, ".method public <init>()V\n");
+ fprintf(fp, " aload_0\n");
+ fprintf(fp, " invokespecial java/lang/Object/<init>()V\n");
+ fprintf(fp, " return\n");
+ fprintf(fp, ".end method\n");
+
+ fprintf(fp, ".method public abstract invoke%s\n", signature);
+ fprintf(fp, ".end method\n\n");
+
+ fclose(fp);
+}
+
+static void
+oberon_generate_record_class(oberon_context_t * ctx, oberon_type_t * rec)
+{
+ FILE * fp;
+ char * cname;
+ char * fname;
+
+ /* Устанавливаем новоый id */
+ rec -> gen_type -> rec_id = rec -> module -> gen_mod -> rec_id;
+ rec -> module -> gen_mod -> rec_id += 1;
+
+ cname = get_class_full_name(ctx, rec);
+ fname = new_string("%s.j", cname);
+
+ fp = fopen(fname, "w");
+
+ fprintf(fp, ".source %s\n", rec -> module -> name);
+ fprintf(fp, ".class public %s\n", cname);
+ fprintf(fp, ".super java/lang/Object\n\n");
+
+ rec -> gen_type -> fp = fp;
+}
+
+void
+oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type)
+{
+ gen_type_t * t = GC_MALLOC(sizeof *t);
+ memset(t, 0, sizeof *t);
+ type -> gen_type = t;
+
+ switch(type -> class)
+ {
+ case OBERON_TYPE_VOID:
+ case OBERON_TYPE_INTEGER:
+ case OBERON_TYPE_BOOLEAN:
+ case OBERON_TYPE_ARRAY:
+ case OBERON_TYPE_REAL:
+ break;
+ case OBERON_TYPE_RECORD:
+ oberon_generate_record_class(ctx, type);
+ break;
+ case OBERON_TYPE_PROCEDURE:
+ oberon_generate_procedure_class(ctx, type);
+ break;
+ case OBERON_TYPE_POINTER:
+ assert(type -> base -> class == OBERON_TYPE_VOID);
+ break;
+ default:
+ oberon_error(ctx, "oberon_generator_init_type: unk calss %i", type -> class);
+ break;
+ }
+}
+
+static void
+oberon_generate_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x)
+{
+ char * name;
+ char * desc;
+
+ name = x -> name;
+ desc = get_descriptor(ctx, x -> type);
+ switch(x -> class)
+ {
+ case OBERON_CLASS_VAR:
+ fprintf(fp, ".field public static %s %s\n\n", name, desc);
+ break;
+ case OBERON_CLASS_FIELD:
+ fprintf(fp, ".field public %s %s\n\n", name, desc);
+ break;
+ default:
+ oberon_error(ctx, "oberon_generate_object: unk class %i", x -> class);
+ break;
+ }
+}
+
+void
+oberon_generator_init_record(oberon_context_t * ctx, oberon_type_t * rec)
+{
+ FILE * fp;
+
+ fp = rec -> gen_type -> fp;
+
+ int num = rec -> num_decl;
+ oberon_object_t * field = rec -> decl;
+ for(int i = 0; i < num; i++)
+ {
+ oberon_generate_object(ctx, fp, field);
+ field = field -> next;
+ }
+
+ fprintf(fp, ".method public <init>()V\n");
+ fprintf(fp, " aload_0\n");
+ fprintf(fp, " invokespecial java/lang/Object/<init>()V\n");
+ fprintf(fp, " return\n");
+ fprintf(fp, ".end method\n");
+
+ fclose(fp);
+}
+
+void
+oberon_generator_init_var(oberon_context_t * ctx, oberon_object_t * var)
+{
+ gen_var_t * v = GC_MALLOC(sizeof *v);
+ memset(v, 0, sizeof *v);
+ var -> gen_var = v;
+
+ gen_module_t * m = ctx -> mod -> gen_mod;
+
+ switch(var -> class)
+ {
+ case OBERON_CLASS_PARAM:
+ case OBERON_CLASS_FIELD:
+ break;
+ case OBERON_CLASS_VAR:
+ oberon_generate_object(ctx, m -> fp, var);
+ break;
+ default:
+ oberon_error(ctx, "oberon_generator_init_var: unk var class %i", var -> class);
+ break;
+ }
+}
+
+void
+oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc)
+{
+ gen_proc_t * p = GC_MALLOC(sizeof *p);
+ memset(p, 0, sizeof *p);
+ proc -> gen_proc = p;
+
+ if(proc -> local)
+ {
+ oberon_error(ctx, "generator: local procedures not implemented");
+ }
+}
+
+void
+oberon_generator_init_module(oberon_context_t * ctx, oberon_module_t * mod)
+{
+ gen_module_t * m = GC_MALLOC(sizeof *m);
+ memset(m, 0, sizeof *m);
+ mod -> gen_mod = m;
+
+ int fnamesz = strlen(mod -> name) + 3;
+ char fname[fnamesz + 1];
+ snprintf(fname, fnamesz, "%s.j", mod -> name);
+
+ FILE * fp;
+ fp = fopen(fname, "w");
+ assert(fp != NULL);
+
+ fprintf(fp, ".source %s\n", mod -> name);
+ fprintf(fp, ".class %s\n", mod -> name);
+ fprintf(fp, ".super java/lang/Object\n\n");
+
+ m -> fp = fp;
+}
+
+// =======================================================================
+// GENERATOR
+// =======================================================================
+
+void
+oberon_generate_begin_module(oberon_context_t * ctx)
+{
+ gen_module_t * m = ctx -> mod -> gen_mod;
+ fprintf(m -> fp, ".method public <init>()V\n");
+ fprintf(m -> fp, " aload_0\n");
+ fprintf(m -> fp, " invokespecial java/lang/Object/<init>()V\n");
+}
+
+void
+oberon_generate_end_module(oberon_context_t * ctx)
+{
+ gen_module_t * m = ctx -> mod -> gen_mod;
+
+ fprintf(m -> fp, " .limit stack 32\n");
+ fprintf(m -> fp, " .limit locals 32\n");
+ fprintf(m -> fp, " return\n");
+ fprintf(m -> fp, ".end method\n");
+}
+
+void
+oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc)
+{
+ gen_module_t * m;
+ char * signature;
+
+ m = ctx -> mod -> gen_mod;
+ signature = get_procedure_signature(ctx, proc -> type);
+
+ fprintf(m -> fp, ".method public static %s%s\n", proc -> name, signature);
+}
+
+void
+oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig)
+{
+ printf("call proc\n");
+}
+
+void
+oberon_generate_end_proc(oberon_context_t * ctx)
+{
+ gen_module_t * m;
+ m = ctx -> mod -> gen_mod;
+
+ fprintf(m -> fp, " .limit stack 32\n");
+ fprintf(m -> fp, " .limit locals 32\n");
+ fprintf(m -> fp, ".end method\n\n");
+}
+
+void
+oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr)
+{
+ gen_module_t * m;
+
+ m = ctx -> mod -> gen_mod;
+
+ if(expr)
+ {
+ oberon_error(ctx, "oberon_generate_return: TODO return expr");
+ }
+ else
+ {
+ fprintf(m -> fp, " return\n");
+ }
+}
+
+static void
+push_int(FILE * fp, long i)
+{
+ if(i == -1)
+ {
+ fprintf(fp, "iconst_m1\n");
+ }
+ else if(i >= 0 && i <= 5)
+ {
+ fprintf(fp, "iconst_%li\n", i);
+ }
+ else if(i >= -128 && i <= 127)
+ {
+ fprintf(fp, "bipush %li\n", i);
+ }
+ else if(i >= -32768 && i <= 32767)
+ {
+ fprintf(fp, "sipush %li\n", i);
+ }
+ else if(i >= -2147483648 && i <= 2147483647)
+ {
+ fprintf(fp, "ldc %li\n", i);
+ }
+ else
+ {
+ fprintf(fp, "ldc2 %li\n", i);
+ }
+}
+
+static void
+push_float(FILE * fp, double f, int size)
+{
+ if(size <= 4)
+ {
+ if(f == 0.0)
+ {
+ fprintf(fp, "fconst_0\n");
+ }
+ if(f == 1.0)
+ {
+ fprintf(fp, "fconst_1\n");
+ }
+ if(f == 2.0)
+ {
+ fprintf(fp, "fconst_2\n");
+ }
+ else
+ {
+ fprintf(fp, "ldc %lf\n", f);
+ }
+ }
+ else
+ {
+ if(f == 0.0)
+ {
+ fprintf(fp, "dconst_0\n");
+ }
+ if(f == 1.0)
+ {
+ fprintf(fp, "dconst_1\n");
+ }
+ else
+ {
+ fprintf(fp, "ldc2 %lf\n", f);
+ }
+ }
+}
+
+static void push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr);
+
+static void
+push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var)
+{
+ if(var -> local)
+ {
+ int reg = var -> gen_var -> reg;
+ char prefix = get_prefix(ctx, var -> type);
+ fprintf(fp, "%cload %i\n", prefix, reg);
+ }
+ else
+ {
+ char * fullname = get_field_full_name(ctx, var);
+ char * desc = get_descriptor(ctx, var -> type);
+ fprintf(fp, "getstatic %s %s\n", fullname, desc);
+ }
+}
+
+static void
+push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
+{
+ switch(item -> mode)
+ {
+ case MODE_VAR:
+ push_var(ctx, fp, item -> var);
+ break;
+ case MODE_INTEGER:
+ push_int(fp, item -> integer);
+ break;
+ case MODE_BOOLEAN:
+ push_int(fp, item -> boolean);
+ break;
+ case MODE_CALL:
+ oberon_error(ctx, "push_item: TODO call");
+ break;
+ case MODE_INDEX:
+ oberon_error(ctx, "push_item: TODO index");
+ break;
+ case MODE_FIELD:
+ oberon_error(ctx, "push_item: TODO field");
+ break;
+ case MODE_DEREF:
+ oberon_error(ctx, "push_item: TODO deref");
+ break;
+ case MODE_NIL:
+ fprintf(fp, "aconst_null\n");
+ break;
+ case MODE_NEW:
+ oberon_error(ctx, "push_item: TODO new");
+ break;
+ case MODE_REAL:
+ push_float(fp, item -> real, item -> result -> size);
+ break;
+ default:
+ oberon_error(ctx, "push_item: unk mode %i", item -> mode);
+ break;
+ }
+}
+
+static void
+push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+{
+ char prefix = get_prefix(ctx, oper -> result);
+ switch(oper -> op)
+ {
+ case OP_UNARY_MINUS:
+ push_expr(ctx, fp, oper -> left);
+ fprintf(fp, "%cneg\n", prefix);
+ break;
+ case OP_BITWISE_NOT:
+ push_expr(ctx, fp, oper -> left);
+ push_int(fp, -1);
+ fprintf(fp, "%cxor\n", prefix);
+ break;
+
+ case OP_ADD:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cadd\n", prefix);
+ break;
+ case OP_SUB:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%csub\n", prefix);
+ break;
+ case OP_MUL:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cmul\n", prefix);
+ break;
+ case OP_DIV:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cdiv\n", prefix);
+ break;
+ case OP_MOD:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%crem\n", prefix);
+ break;
+ case OP_BITWISE_AND:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cand\n", prefix);
+ break;
+ case OP_BITWISE_XOR:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cxor\n", prefix);
+ break;
+ case OP_BITWISE_OR:
+ push_expr(ctx, fp, oper -> left);
+ push_expr(ctx, fp, oper -> right);
+ fprintf(fp, "%cor\n", prefix);
+ break;
+
+ case OP_EQ:
+ case OP_NEQ:
+ case OP_LSS:
+ case OP_LEQ:
+ case OP_GRT:
+ case OP_GEQ:
+ case OP_LOGIC_NOT:
+ case OP_ABS:
+ oberon_error(ctx, "push_oper: TODO op %i", oper -> op);
+ break;
+ default:
+ oberon_error(ctx, "push_oper: unk op %i", oper -> op);
+ break;
+ }
+}
+
+static void
+push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
+{
+ if(expr -> is_item)
+ {
+ push_item(ctx, fp, (oberon_item_t *) expr);
+ }
+ else
+ {
+ push_operator(ctx, fp, (oberon_oper_t *) expr);
+ }
+}
+
+static void
+store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
+{
+ assert(expr -> is_item);
+ oberon_item_t * item = (oberon_item_t *) expr;
+
+ char prefix;
+ switch(item -> mode)
+ {
+ case MODE_VAR:
+ if(item -> var -> local)
+ {
+ int reg = item -> var -> gen_var -> reg;
+ prefix = get_prefix(ctx, item -> result);
+ fprintf(fp, "%cstore %i\n", prefix, reg);
+ }
+ else
+ {
+ char * fullname = get_field_full_name(ctx, item -> var);
+ char * desc = get_descriptor(ctx, item -> result);
+ fprintf(fp, "putstatic %s %s\n", fullname, desc);
+ }
+ break;
+ default:
+ oberon_error(ctx, "store_expr: unk mode %i", item -> mode);
+ break;
+ }
+}
+
+void
+oberon_generate_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
+{
+ gen_module_t * m;
+ m = ctx -> mod -> gen_mod;
+
+ push_expr(ctx, m -> fp, src);
+ store_expr(ctx, m -> fp, dst);
+}
+
+void
+oberon_generate_code(oberon_context_t * ctx)
+{
+ printf("generate code\n");
+}
+
+void
+oberon_generator_dump(oberon_context_t * ctx, char * path)
+{
+ printf("jit: dump code\n");
+}
+
+void *
+oberon_generator_get_procedure(oberon_context_t * ctx, const char * name)
+{
+ printf("jit: get pointer to procedure %s\n", name);
+ return NULL;
+}
+
+void *
+oberon_generator_get_var(oberon_context_t * ctx, const char * name)
+{
+ printf("jit: get pointer to var %s\n", name);
+ return NULL;
+}