DEADSOFTWARE

Добавлена процедура NEW для аллокации обычных массивов
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 20:01:34 +0000 (23:01 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 20:01:34 +0000 (23:01 +0300)
generator.c
make.sh
notes
oberon.c
oberon.h
test.c

index bad063d57adcac9ee2c45d5f1442febdf5839055..94bc1696a8f54f281e8868cfa02d7a51f1800cb0 100644 (file)
@@ -5,9 +5,23 @@
 #include <string.h>
 #include <assert.h>
 
+#include <gc.h>
+
 #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 286e5ff578a2f1b1586217a09e1931abaa63a860..1f95bcf593d5824856bf83e51bd355a2315c2a85 100755 (executable)
--- 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 fbb1be93c7374f5bc8a2f590932f0706c3640d5f..977d7cd3e9966f7e5280050849215b3eae712114 100644 (file)
--- a/notes
+++ b/notes
@@ -1,4 +1,7 @@
-- нету процедуры NEW
+- размеры типов не вычисляются (oberon_generator_get_type_size)
+    в libgccjit нет средств получения размера типов, в т.ч. структур
+    Придётся гадать.
+- процедура NEW создаёт массивы только статической размерности (и не создаёт структуры).
 - нету открытых массивов
 
 - нету операторов if, while и т.д.
@@ -10,7 +13,7 @@
 - не реализована свёртка констант
 - не протестированы типы разнных размеров
 
-- не реализовано присваивание к переменным-процедурам:
+- Ð½Ðµ Ñ\80еализовано Ð¿Ñ\80иÑ\81ваивание Ð¿Ñ\80оÑ\86едÑ\83Ñ\80 Ðº Ð¿ÐµÑ\80еменнÑ\8bм-пÑ\80оÑ\86едÑ\83Ñ\80ам:
     в libgccjit нет средств получения указателя на функцию.
     Как решение-костыль - получение указателя в основной программе и сохранение в переменной.
 - не реализовано расширение типа record:
index e857b1d1ec6f93e454b5439cdcf81f96c150d167..931d948c57bc15c0faf906e0a6f23b52f991a122 100644 (file)
--- 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;
 }
index ef9ad7f1c891223eb2241ef8d4020e3855a50645..4b785453befda47bbdcfe1ccf9c7b9a67ccfd1cc 100644 (file)
--- 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 c3a4b1467f51256bbec89e210374cb69d90a44d8..fc0033339d03fff36dbd6f52ba6989c3df777c0c 100644 (file)
--- 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()