From c4d4a265b71124ad0e8588601cfc1d66aca84b96 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Mon, 24 Jul 2017 23:01:34 +0300 Subject: [PATCH] =?utf8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?utf8?q?=D0=B0=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D0=B4=D1=83=D1=80=D0=B0?= =?utf8?q?=20NEW=20=D0=B4=D0=BB=D1=8F=20=D0=B0=D0=BB=D0=BB=D0=BE=D0=BA?= =?utf8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BE=D0=B1=D1=8B=D1=87=D0=BD=D1=8B?= =?utf8?q?=D1=85=20=D0=BC=D0=B0=D1=81=D1=81=D0=B8=D0=B2=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- generator.c | 60 +++++++++++++++++++++++++++++- make.sh | 2 +- notes | 7 +++- oberon.c | 103 +++++++++++++++++++++++++++++++++++++++++++++------- oberon.h | 5 ++- test.c | 28 ++++++++++++-- 6 files changed, 183 insertions(+), 22 deletions(-) diff --git a/generator.c b/generator.c index bad063d..94bc169 100644 --- a/generator.c +++ b/generator.c @@ -5,9 +5,23 @@ #include #include +#include + #include "oberon.h" #include "generator.h" +// ======================================================================= +// INTERNAL FUNCTIONS +// ======================================================================= + +static void * +__OBERON_ALLOC__ (size_t bytes) +{ + void * p = GC_MALLOC(bytes); + memset(p, 0, bytes); + return p; +} + // ======================================================================= // ALLOC // ======================================================================= @@ -41,6 +55,15 @@ oberon_generator_init_context(oberon_context_t * ctx) ctx -> gen_context = gen_context; gen_context -> gcc_context = gcc_context; + + gcc_jit_type * void_ptr_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_VOID_PTR); + gcc_jit_type * size_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_SIZE_T); + gcc_jit_type * alloc_ptr_type = gcc_jit_context_new_function_ptr_type( + gcc_context, NULL, void_ptr_type, 1, &size_type, 0 + ); + gen_context -> gcc_alloc = gcc_jit_context_new_global( + gcc_context, NULL, GCC_JIT_GLOBAL_EXPORTED, alloc_ptr_type, "__OBERON_ALLOC__" + ); } void @@ -299,6 +322,13 @@ oberon_generator_init_proc(oberon_context_t * ctx, oberon_object_t * proc) static gcc_jit_rvalue * rvalue_from_item(oberon_context_t * ctx, oberon_item_t * item); static gcc_jit_rvalue * rvalue_from_expr(oberon_context_t * ctx, oberon_expr_t * expr); +static int +oberon_generator_get_type_size(oberon_type_t * type) +{ + printf("TODO: oberon_generator_get_type_size\n"); + return 128; +} + void oberon_generate_begin_module(oberon_context_t * ctx) { @@ -423,7 +453,7 @@ lvalue_from_item(oberon_context_t * ctx, oberon_item_t * item) } else { - oberon_error(ctx, "invalid lvalue expression"); + oberon_error(ctx, "lvalue_from_item: invalid mode %i", item -> mode); } return left; @@ -548,6 +578,30 @@ rvalue_from_item(oberon_context_t * ctx, oberon_item_t * item) gcc_jit_type * type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_VOID_PTR); right = gcc_jit_context_null(gcc_context, type); } + else if(item -> mode == MODE_NEWARR) + { + int type_size = oberon_generator_get_type_size(item -> type); + int array_size = type_size; + + int num = item -> num_args; + oberon_expr_t * arg = item -> args; + for(int i = 0; i < num; i++) + { + array_size *= arg -> item.integer; + arg = arg -> next; + } + + gcc_jit_type * size_type; + size_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_SIZE_T); + + gcc_jit_rvalue * fnarg; + fnarg = gcc_jit_context_new_rvalue_from_int(gcc_context, size_type, array_size); + + gcc_jit_type * result_type = item -> result -> gen_type -> gcc_type; + gcc_jit_rvalue * gcc_alloc = gcc_jit_lvalue_as_rvalue(gen_context -> gcc_alloc); + right = gcc_jit_context_new_call_through_ptr(gcc_context, NULL, gcc_alloc, 1, &fnarg); + right = gcc_jit_context_new_cast(gcc_context, NULL, right, result_type); + } else { oberon_error(ctx, "rvalue_from_item: invalid mode %i", item -> mode); @@ -686,6 +740,10 @@ oberon_generate_code(oberon_context_t * ctx) gen_context -> gcc_result = gcc_result; + typedef void * (*TOberonAlloc)(size_t); + TOberonAlloc * fn_alloc_ptr = gcc_jit_result_get_global(gcc_result, "__OBERON_ALLOC__"); + *fn_alloc_ptr = __OBERON_ALLOC__; + // ctx -> mod -> begin = gcc_jit_result_get_code(gcc_result, "BEGIN"); } diff --git a/make.sh b/make.sh index 286e5ff..1f95bcf 100755 --- a/make.sh +++ b/make.sh @@ -2,4 +2,4 @@ set -e -cc -g -Wall -Werror -std=c11 -lgccjit *.c +cc -g -Wall -Werror -std=c11 -lgccjit -lgc *.c diff --git a/notes b/notes index fbb1be9..977d7cd 100644 --- a/notes +++ b/notes @@ -1,4 +1,7 @@ -- нету процедуры NEW +- размеры типов не вычисляются (oberon_generator_get_type_size) + в libgccjit нет средств получения размера типов, в т.ч. структур + Придётся гадать. +- процедура NEW создаёт массивы только статической размерности (и не создаёт структуры). - нету открытых массивов - нету операторов if, while и т.д. @@ -10,7 +13,7 @@ - не реализована свёртка констант - не протестированы типы разнных размеров -- не реализовано присваивание к переменным-процедурам: +- не реализовано присваивание процедур к переменным-процедурам: в libgccjit нет средств получения указателя на функцию. Как решение-костыль - получение указателя в основной программе и сохранение в переменной. - не реализовано расширение типа record: diff --git a/oberon.c b/oberon.c index e857b1d..931d948 100644 --- a/oberon.c +++ b/oberon.c @@ -665,7 +665,13 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * { if(pref -> class != expr -> result -> class) { - oberon_error(ctx, "incompatible types"); + if(pref -> class != OBERON_TYPE_PROCEDURE) + { + if(expr -> result -> class != OBERON_TYPE_POINTER) + { + oberon_error(ctx, "incompatible types"); + } + } } if(pref -> class == OBERON_TYPE_INTEGER) @@ -736,21 +742,26 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig) { if(param -> class == OBERON_CLASS_VAR_PARAM) { - if(arg -> is_item) + if(arg -> read_only) { - switch(arg -> item.mode) - { - case MODE_VAR: - case MODE_INDEX: - case MODE_FIELD: - // Допустимо разыменование? - //case MODE_DEREF: - break; - default: - oberon_error(ctx, "var-parameter accept only variables"); - break; - } + oberon_error(ctx, "assign to read-only var"); } + + //if(arg -> is_item) + //{ + // switch(arg -> item.mode) + // { + // case MODE_VAR: + // case MODE_INDEX: + // case MODE_FIELD: + // // Допустимо разыменование? + // //case MODE_DEREF: + // break; + // default: + // oberon_error(ctx, "var-parameter accept only variables"); + // break; + // } + //} } oberon_autocast_to(ctx, arg, param -> type); arg = arg -> next; @@ -2564,6 +2575,69 @@ oberon_make_abs_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ return expr; } +static void +oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args) +{ + if(num_args < 1) + { + oberon_error(ctx, "too few arguments"); + } + + if(num_args > 1) + { + oberon_error(ctx, "too mach arguments"); + } + + oberon_expr_t * dst; + dst = list_args; + + oberon_type_t * type; + type = dst -> result; + + if(type -> class != OBERON_TYPE_POINTER) + { + oberon_error(ctx, "not a pointer"); + } + + type = type -> base; + + oberon_expr_t * src; + if(type -> class == OBERON_TYPE_ARRAY) + { + int dim = 1; + + oberon_expr_t * sizes = NULL; + oberon_expr_t * last_size = NULL; + + sizes = last_size = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1); + sizes -> item.integer = type -> size; + + oberon_type_t * base = type -> base; + while(base -> class == OBERON_TYPE_ARRAY) + { + oberon_expr_t * size; + size = last_size = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1); + size -> item.integer = base -> size; + + last_size -> next = size; + last_size = size; + base = base -> base; + dim += 1; + } + + src = oberon_new_item(MODE_NEWARR, dst -> result, 0); + src -> item.num_args = dim; + src -> item.args = sizes; + src -> item.type = base; + } + else + { + oberon_error(ctx, "oberon_make_new_call: wat"); + } + + oberon_assign(ctx, src, dst); +} + oberon_context_t * oberon_create_context(ModuleImportCallback import_module) { @@ -2579,6 +2653,7 @@ oberon_create_context(ModuleImportCallback import_module) register_default_types(ctx); oberon_new_intrinsic(ctx, "ABS", oberon_make_abs_call, NULL); + oberon_new_intrinsic(ctx, "NEW", NULL, oberon_make_new_call); return ctx; } diff --git a/oberon.h b/oberon.h index ef9ad7f..4b78545 100644 --- a/oberon.h +++ b/oberon.h @@ -39,6 +39,7 @@ struct gen_context_s gcc_jit_result * gcc_result; gen_block_t * block; unsigned record_count; + gcc_jit_lvalue * gcc_alloc; }; typedef struct oberon_type_s oberon_type_t; @@ -257,7 +258,8 @@ enum MODE_INDEX, MODE_FIELD, MODE_DEREF, - MODE_NIL + MODE_NIL, + MODE_NEWARR }; enum @@ -302,6 +304,7 @@ struct oberon_item_s int num_args; oberon_expr_t * args; + oberon_type_t * type; }; struct oberon_oper_s diff --git a/test.c b/test.c index c3a4b14..fc00333 100644 --- a/test.c +++ b/test.c @@ -8,15 +8,30 @@ static char source_test[] = "(* Main module *)" "MODULE Test;" "IMPORT Out;" + "" + "VAR" + " nx- : INTEGER;" + " p : POINTER TO ARRAY 3 OF INTEGER;" + "" + "PROCEDURE ChParam(VAR i : INTEGER);" + "BEGIN" + " i := 1234;" + "END ChParam;" + "" "BEGIN;" + " NEW(p);" + " p[0] := 1;" + " " " Out.Open;" - " Out.Int(666, 0);" + " ChParam(nx);" + " Out.Int(nx, 0);" " Out.Ln;" "END Test." ; static char source_out[] = "MODULE Out;" + "(* Interface to outer program ;) *)" "VAR" " Open- : PROCEDURE;" // " Char- : PROCEDURE(ch : CHAR);" @@ -59,14 +74,21 @@ typedef void (*TOutInt)(int, int); static TOutInt * OutIntPtr; void ImplOutInt(int i, int n) { - printf("%i", i); + char number[22]; + snprintf(number, 22, "%i", i); + int len = strlen(number); + for(int i = 0; i < n - len; i++) + { + putchar(' '); + } + printf("%s", number); } typedef void (*TOutLn)(); static TOutLn * OutLnPtr; void ImplOutLn() { - printf("\n"); + putchar('\n'); } void init_system_modules() -- 2.29.2