index 2a2abcdcd3632f1b73a22aecc2135138f8e94523..215f6d757b1d92fd1b1b2c67ed088333959e927d 100644 (file)
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);
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 *
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;
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, ".end method\n\n");
fprintf(fp, ".method public abstract invoke%s\n", signature);
fprintf(fp, ".end method\n\n");
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);
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);
switch(var -> class)
{
+ case OBERON_CLASS_VAR_PARAM:
+ oberon_error(ctx, "generator: VAR-parameters not implemented");
+ break;
case OBERON_CLASS_PARAM:
case OBERON_CLASS_FIELD:
break;
memset(p, 0, sizeof *p);
proc -> gen_proc = p;
+ struct gen_register_file * rf = GC_MALLOC(sizeof *rf);
+ memset(rf, 0, sizeof *rf);
+ p -> rf = rf;
+
if(proc -> local)
{
oberon_error(ctx, "generator: local procedures not implemented");
// GENERATOR
// =======================================================================
+static void
+push_expr(oberon_context_t * ctx, FILE * fp, oberon_expr_t * expr);
+
void
oberon_generate_begin_module(oberon_context_t * ctx)
{
fprintf(m -> fp, ".end method\n");
}
+static int
+jvm_cell_size_for_type(oberon_type_t * type)
+{
+ if(type -> class == OBERON_TYPE_INTEGER
+ || type -> class == OBERON_TYPE_REAL)
+ {
+ if(type -> size > 4)
+ {
+ return 2;
+ }
+ }
+
+ return 1;
+}
+
+static bool
+jvm_is_wide_type(oberon_type_t * type)
+{
+ int cell;
+ cell = jvm_cell_size_for_type(type);
+ assert(cell <= 2);
+ return (cell == 2);
+}
+
+static bool
+jvm_is_free_register(struct gen_register_file * rf, int i, bool wide)
+{
+ if(wide)
+ {
+ assert(i + 1 < MAX_REGISTERS);
+ return !(rf -> reg[i].used || rf -> reg[i + 1].used);
+ }
+ else
+ {
+ assert(i < MAX_REGISTERS);
+ return !(rf -> reg[i].used);
+ }
+}
+
+static int
+jvm_alloc_register(struct gen_register_file * rf, oberon_type_t * type)
+{
+ bool wide;
+ wide = jvm_is_wide_type(type);
+
+ int i = 0;
+ while(i < MAX_REGISTERS && !jvm_is_free_register(rf, i, wide))
+ {
+ i += 1;
+ }
+
+ if(wide)
+ {
+ assert(i + 1 <= MAX_REGISTERS);
+ rf -> num_used += 2;
+ rf -> reg[i].used = true;
+ rf -> reg[i + 1].used = true;
+ rf -> reg[i].used = true;
+ rf -> reg[i + 1].wide = false;
+ }
+ else
+ {
+ assert(i <= MAX_REGISTERS);
+ rf -> num_used += 1;
+ rf -> reg[i].used = true;
+ rf -> reg[i].wide = false;
+ }
+
+ if(rf -> num_used > rf -> max_used)
+ {
+ rf -> max_used = rf -> num_used;
+ }
+
+ return i;
+}
+
+static void
+jvm_init_local_object(oberon_context_t * ctx, FILE * fp, oberon_object_t * x)
+{
+ int reg;
+ gen_context_t * c;
+ gen_var_t * v;
+ char * desc;
+
+ c = ctx -> gen_context;
+ v = x -> gen_var;
+ desc = get_descriptor(ctx, x -> type);
+
+ reg = -1;
+ switch(x -> class)
+ {
+ case OBERON_CLASS_VAR:
+ case OBERON_CLASS_PARAM:
+ if(x -> local)
+ {
+ reg = jvm_alloc_register(c -> rf, x -> type);
+ }
+ v -> reg = reg;
+ fprintf(fp, ".var %i is %s %s from start to end\n", reg, x -> name, desc);
+ break;
+ default:
+ oberon_error(ctx, "jvm_init_local_object: wat");
+ break;
+ }
+}
+
void
oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc)
{
+ gen_context_t * c;
gen_module_t * m;
+ gen_proc_t * p;
char * signature;
+ c = ctx -> gen_context;
m = ctx -> mod -> gen_mod;
- signature = get_procedure_signature(ctx, proc -> type);
+ p = proc -> gen_proc;
+ 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");
+ /* Сохраняем регистровый файл в стеке */
+ p -> rf -> up = c -> rf;
+ c -> rf = p -> rf;
+
+ oberon_object_t * var = proc -> type -> decl;
+ while(var)
+ {
+ jvm_init_local_object(ctx, m -> fp, var);
+ var = var -> next;
+ }
+
+ fprintf(m -> fp, "start:\n");
}
void
oberon_generate_end_proc(oberon_context_t * ctx)
{
+ gen_context_t * c;
gen_module_t * m;
+
+ c = ctx -> gen_context;
m = ctx -> mod -> gen_mod;
+ fprintf(m -> fp, "end:\n");
fprintf(m -> fp, " .limit stack 32\n");
- fprintf(m -> fp, " .limit locals 32\n");
+ fprintf(m -> fp, " .limit locals %i\n", c -> rf -> max_used);
fprintf(m -> fp, ".end method\n\n");
+
+ /* Возвращаем исходный регистровый файл */
+ c -> rf = c -> rf -> up;
+}
+
+void
+oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig)
+{
+ oberon_object_t * proc;
+ gen_module_t * m;
+ char * fullname;
+ char * signature;
+
+ assert(desig -> is_item);
+ assert(desig -> item.mode == MODE_CALL);
+
+ m = ctx -> mod -> gen_mod;
+ proc = desig -> item.var;
+ fullname = get_field_full_name(ctx, proc);
+ signature = get_procedure_signature(ctx, proc -> type);
+
+ int num = desig -> item.num_args;
+ oberon_expr_t * arg = desig -> item.args;
+ for(int i = 0; i < num; i++)
+ {
+ push_expr(ctx, m -> fp, arg);
+ arg = arg -> next;
+ }
+
+ fprintf(m -> fp, "invokestatic %s%s\n", fullname, signature);
}
void
oberon_generate_return(oberon_context_t * ctx, oberon_expr_t * expr)
{
gen_module_t * m;
+ char prefix;
m = ctx -> mod -> gen_mod;
if(expr)
{
- oberon_error(ctx, "oberon_generate_return: TODO return expr");
+ push_expr(ctx, m -> fp, expr);
+ prefix = get_prefix(ctx, expr -> result);
+ fprintf(m -> fp, " %creturn\n", prefix);
}
else
{
}
}
-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)
{
}
}
+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)
{
push_int(fp, item -> boolean);
break;
case MODE_CALL:
- oberon_error(ctx, "push_item: TODO call");
+ oberon_generate_call_proc(ctx, (oberon_expr_t *) item);
break;
case MODE_INDEX:
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);
}
}
+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
-push_operator(oberon_context_t * ctx, FILE * fp, oberon_oper_t * oper)
+jvm_generate_label(FILE * fp, int label_id)
{
- char prefix = get_prefix(ctx, oper -> result);
- switch(oper -> op)
+ 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
+jvm_generate_abs(FILE * fp, char prefix)
+{
+ 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;
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;
}
}
}
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;
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;
@@ -713,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