DEADSOFTWARE

JVM: Реализован доступ к полям записей и NEW для записей(без инициализации полей)
[dsw-obn.git] / src / backends / jvm / generator-jvm.c
index c217ccb3d6f37ebb809bf076dcd35e62636d3c5e..215f6d757b1d92fd1b1b2c67ed088333959e927d 100644 (file)
@@ -96,6 +96,9 @@ get_descriptor(oberon_context_t * ctx, oberon_type_t * type)
                case OBERON_TYPE_BOOLEAN:
                        return new_string("Z");
                        break;
+               case OBERON_TYPE_POINTER:
+                       return get_descriptor(ctx, type -> base);
+                       break;
                case OBERON_TYPE_PROCEDURE:
                case OBERON_TYPE_RECORD:
                        desc = get_class_full_name(ctx, type);
@@ -141,7 +144,21 @@ get_prefix(oberon_context_t * ctx, oberon_type_t * type)
 static char *
 get_field_full_name(oberon_context_t * ctx, oberon_object_t * x)
 {
-       return new_string("%s/%s", x -> module -> name, x -> name);
+       switch(x -> class)
+       {
+               case OBERON_CLASS_VAR:
+                       return new_string("%s/%s", x -> module -> name, x -> name);
+               case OBERON_CLASS_FIELD:;
+                       char * rec_name = get_class_full_name(ctx, x -> parent_type);
+                       return new_string("%s/%s", rec_name, x -> name);
+               case OBERON_CLASS_MODULE:
+                       return new_string(x -> module -> name);
+               default:
+                       oberon_error(ctx, "get_field_full_name: wat");
+                       break;
+       }
+
+       return NULL;
 }
 
 static char *
@@ -170,8 +187,6 @@ get_class_full_name(oberon_context_t * ctx, oberon_type_t * type)
 
                        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;
@@ -282,7 +297,6 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type)
                        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);
@@ -301,7 +315,10 @@ oberon_generate_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x)
        switch(x -> class)
        {
                case OBERON_CLASS_VAR:
-                       fprintf(fp, ".field public static %s %s\n\n", name, desc);
+                       if(x -> local == 0)
+                       {
+                               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);
@@ -491,7 +508,7 @@ jvm_alloc_register(struct gen_register_file * rf, oberon_type_t * type)
        else
        {
                assert(i <= MAX_REGISTERS);
-               rf -> num_used += 2;
+               rf -> num_used += 1;
                rf -> reg[i].used = true;
                rf -> reg[i].wide = false;
        }
@@ -713,6 +730,44 @@ push_var(oberon_context_t * ctx, FILE * fp, oberon_object_t * var)
        }
 }
 
+static void
+jvm_generate_new_static(oberon_context_t * ctx, FILE * fp, oberon_type_t * type, int num, oberon_expr_t * arg)
+{
+       //char * desc;
+       char * cname;
+       //desc = get_descriptor(ctx, type);
+       cname = get_class_full_name(ctx, type);
+
+       switch(type -> class)
+       {
+               case OBERON_TYPE_INTEGER:
+               case OBERON_TYPE_BOOLEAN:
+               case OBERON_TYPE_PROCEDURE:
+               case OBERON_TYPE_REAL:
+               case OBERON_TYPE_POINTER:
+                       /* ничего не генерируем */
+                       break;
+               case OBERON_TYPE_RECORD:
+                       fprintf(fp, "new %s\n", cname);
+                       fprintf(fp, "dup\n");
+                       fprintf(fp, "invokespecial %s/<init>()V\n", cname); 
+                       break;
+               case OBERON_TYPE_ARRAY:
+                       oberon_error(ctx, "jvm_generate_new_static: TODO array");
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_generate_new_static: unk type class %i", type -> class);
+                       break;
+       }
+}
+
+static void
+jvm_generate_new_pointer(oberon_context_t * ctx, FILE * fp, oberon_type_t * type, int num, oberon_expr_t * arg)
+{
+       assert(type -> class == OBERON_TYPE_POINTER);
+       jvm_generate_new_static(ctx, fp, type -> base, num, arg);
+}
+
 static void
 push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
 {
@@ -734,16 +789,20 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
                        oberon_error(ctx, "push_item: TODO index");
                        break;
                case MODE_FIELD:
-                       oberon_error(ctx, "push_item: TODO field");
+                       push_item(ctx, fp, item -> parent);
+                       char * field = get_field_full_name(ctx, item -> var);
+                       char * desc = get_descriptor(ctx, item -> var -> type);
+                       fprintf(fp, "getfield %s %s\n", field, desc);
                        break;
                case MODE_DEREF:
-                       oberon_error(ctx, "push_item: TODO deref");
+                       /* Все объекты представляются как увказатели */
+                       push_item(ctx, fp, item -> parent);
                        break;
                case MODE_NIL:
                        fprintf(fp, "aconst_null\n");
                        break;
                case MODE_NEW:
-                       oberon_error(ctx, "push_item: TODO new");
+                       jvm_generate_new_pointer(ctx, fp, item -> result, item -> num_args, item -> args);
                        break;
                case MODE_REAL:
                        push_float(fp, item -> real, item -> result -> size);
@@ -754,60 +813,155 @@ push_item(oberon_context_t * ctx, FILE * fp, oberon_item_t * item)
        }
 }
 
+static int
+jvm_new_label_id(oberon_context_t * ctx)
+{
+       gen_context_t * c = ctx -> gen_context;
+       int label_id = c -> label_id;
+       c -> label_id += 1;
+       return label_id;
+}
+
+static char *
+jvm_get_label_name(int label_id)
+{
+       return new_string("L%i", label_id);
+}
+
+static void
+jvm_generate_label(FILE * fp, int label_id)
+{
+       fprintf(fp, "L%i:\n", label_id);
+}
+
+static void
+jvm_generate_logical_not(oberon_context_t * ctx, FILE * fp)
+{
+       int label_true = jvm_new_label_id(ctx);
+       int label_false = jvm_new_label_id(ctx);
+       char * label_name_true = jvm_get_label_name(label_true);
+       char * label_name_false = jvm_get_label_name(label_false);
+
+       fprintf(fp, "ifne %s\n", label_name_false);
+       fprintf(fp, "iconst_1\n");
+       fprintf(fp, "goto %s\n", label_name_true);
+       jvm_generate_label(fp, label_false);
+       fprintf(fp, "iconst_0\n");
+       jvm_generate_label(fp, label_true);
+}
+
+static char
+jvm_get_type_of_prefix(char prefix)
+{
+       switch(prefix)
+       {
+               case 'b':
+                       return 'B';
+               case 'c':
+                       return 'C';
+               case 'd':
+                       return 'D';
+               case 'f':
+                       return 'F';
+               case 'i':
+                       return 'I';
+               case 'l':
+                       return 'J';
+       }
+
+       assert(0);
+}
+
 static void
-push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+jvm_generate_abs(FILE * fp, char prefix)
 {
-       char prefix = get_prefix(ctx, oper -> result);
-       switch(oper -> op)
+       char t = jvm_get_type_of_prefix(prefix);
+       fprintf(fp, "invokestatic java/lang/Math/abs(%c)%c\n", t, t);
+}
+
+static void
+jvm_generate_compare_op(oberon_context_t * ctx, FILE *fp, char prefix, int op)
+{
+       int label_true = jvm_new_label_id(ctx);
+       int label_false = jvm_new_label_id(ctx);
+       char * label_name_true = jvm_get_label_name(label_true);
+       char * label_name_false = jvm_get_label_name(label_false);
+
+       assert(prefix == 'i' || prefix == 'a');
+
+       switch(op)
+       {
+               case OP_EQ:
+                       fprintf(fp, "if_%ccmpeq %s\n", prefix, label_name_true);
+                       break;
+               case OP_NEQ:
+                       fprintf(fp, "if_%ccmpne %s\n", prefix, label_name_true);
+                       break;
+               case OP_LSS:
+                       fprintf(fp, "if_icmplt %s\n", label_name_true);
+                       break;
+               case OP_LEQ:
+                       fprintf(fp, "if_icmple %s\n", label_name_true);
+                       break;
+               case OP_GRT:
+                       fprintf(fp, "if_icmpgt %s\n", label_name_true);
+                       break;
+               case OP_GEQ:
+                       fprintf(fp, "if_icmpge %s\n", label_name_true);
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_generate_compare_op: wat");
+                       break;
+       }
+
+       fprintf(fp, "iconst_0\n");
+       fprintf(fp, "goto %s\n", label_name_false);
+       jvm_generate_label(fp, label_true);
+       fprintf(fp, "iconst_1\n");
+       jvm_generate_label(fp, label_false);
+}
+
+static void
+jvm_generate_operator(oberon_context_t * ctx, FILE *fp, char prefix, int op)
+{
+       switch(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_LOGIC_NOT:
+                       jvm_generate_logical_not(ctx, fp);
+                       break;
+               case OP_ABS:
+                       jvm_generate_abs(fp, 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;
 
@@ -817,12 +971,95 @@ push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
                case OP_LEQ:
                case OP_GRT:
                case OP_GEQ:
+                       jvm_generate_compare_op(ctx, fp, prefix, op);
+                       break;
+               default:
+                       oberon_error(ctx, "jvm_generate_operator: unk op %i", op);
+                       break;
+       }       
+}
+
+static void
+jvm_generate_logical_or(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q)
+{
+       int label_calc_q = jvm_new_label_id(ctx);
+       int label_done = jvm_new_label_id(ctx);
+       char * label_name_calc_q = jvm_get_label_name(label_calc_q);
+       char * label_name_done = jvm_get_label_name(label_done);
+
+       /* p OR q -- если p, то TRUE, иначе q */
+
+       push_expr(ctx, fp, p);
+       fprintf(fp, "ifne %s\n", label_name_calc_q);
+       fprintf(fp, "iconst_1\n");
+       fprintf(fp, "goto %s\n", label_name_done);
+       jvm_generate_label(fp, label_calc_q);
+       push_expr(ctx, fp, q);
+       jvm_generate_label(fp, label_done);
+}
+
+static void
+jvm_generate_logical_and(oberon_context_t * ctx, FILE * fp, oberon_expr_t * p, oberon_expr_t * q)
+{
+       int label_false = jvm_new_label_id(ctx);
+       int label_done = jvm_new_label_id(ctx);
+       char * label_name_false = jvm_get_label_name(label_false);
+       char * label_name_done = jvm_get_label_name(label_done);
+
+       /* p AND q -- если p, то q, иначе FALSE */
+
+       push_expr(ctx, fp, p);
+       fprintf(fp, "ifne %s\n", label_name_false);
+       push_expr(ctx, fp, q);
+       fprintf(fp, "goto %s\n", label_name_done);
+       jvm_generate_label(fp, label_false);
+       fprintf(fp, "iconst_0\n");
+       jvm_generate_label(fp, label_done);
+}
+
+static void
+push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+{
+       char prefix = get_prefix(ctx, oper -> result);
+       int op = oper -> op;
+       switch(op)
+       {
+               case OP_UNARY_MINUS:
+               case OP_BITWISE_NOT:
                case OP_LOGIC_NOT:
                case OP_ABS:
-                       oberon_error(ctx, "push_oper: TODO op %i", oper -> op);
+                       push_expr(ctx, fp, oper -> left);
+                       jvm_generate_operator(ctx, fp, prefix, op);
+                       break;
+
+               case OP_ADD:
+               case OP_SUB:
+               case OP_MUL:
+               case OP_DIV:
+               case OP_MOD:
+               case OP_BITWISE_AND:
+               case OP_BITWISE_XOR:
+               case OP_BITWISE_OR:
+
+               case OP_EQ:
+               case OP_NEQ:
+               case OP_LSS:
+               case OP_LEQ:
+               case OP_GRT:
+               case OP_GEQ:
+                       push_expr(ctx, fp, oper -> left);
+                       push_expr(ctx, fp, oper -> right);
+                       jvm_generate_operator(ctx, fp, prefix, op);
+                       break;
+
+               case OP_LOGIC_OR:
+                       jvm_generate_logical_or(ctx, fp, oper -> left, oper -> right);
+                       break;
+               case OP_LOGIC_AND:
+                       jvm_generate_logical_and(ctx, fp, oper -> left, oper -> right);
                        break;
                default:
-                       oberon_error(ctx, "push_oper: unk op %i", oper -> op);
+                       oberon_error(ctx, "push_oper: unk op %i", op);
                        break;
        }
 }
@@ -841,15 +1078,16 @@ push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
 }
 
 static void
-store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
+store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * dst, oberon_expr_t * src)
 {
-       assert(expr -> is_item);
-       oberon_item_t * item = (oberon_item_t *) expr;
+       assert(dst -> is_item);
+       oberon_item_t * item = (oberon_item_t *) dst;
 
        char prefix;
        switch(item -> mode)
        {
                case MODE_VAR:
+                       push_expr(ctx, fp, src);
                        if(item -> var -> local)
                        {
                                int reg = item -> var -> gen_var -> reg;
@@ -863,6 +1101,21 @@ store_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr)
                                fprintf(fp, "putstatic %s %s\n", fullname, desc);
                        }
                        break;
+               case MODE_INDEX:
+                       oberon_error(ctx, "store_expr: TODO index");
+                       break;
+               case MODE_FIELD:
+                       {
+                               char * fullname = get_field_full_name(ctx, item -> var);
+                               char * desc = get_descriptor(ctx, item -> result);
+                               printf("push parent\n");
+                               push_item(ctx, fp, item -> parent);
+                               printf("push expr\n");
+                               push_expr(ctx, fp, src);
+                               printf("store to field %s:%s\n", fullname, desc);
+                               fprintf(fp, "putfield %s %s ; store field\n", fullname, desc);
+                       }
+                       break;
                default:
                        oberon_error(ctx, "store_expr: unk mode %i", item -> mode);
                        break;
@@ -875,8 +1128,7 @@ oberon_generate_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_
        gen_module_t * m;
        m = ctx -> mod -> gen_mod;
 
-       push_expr(ctx, m -> fp, src);
-       store_expr(ctx, m -> fp, dst);
+       store_expr(ctx, m -> fp, dst, src);
 }
 
 void