DEADSOFTWARE

Добавлен тип REAL
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 20:05:37 +0000 (23:05 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 20:05:37 +0000 (23:05 +0300)
generator.c
notes
oberon.c
oberon.h
test.c

index 179320aef7df8ffb4cf1aa4a6ecc3b4df4250f17..d54bbfdb408ad0dc720b6095e7b99f8e878ac4a9 100644 (file)
@@ -99,7 +99,33 @@ oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type)
        }
        else if(type -> class == OBERON_TYPE_BOOLEAN)
        {
-               gcc_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL);
+               if(type -> size == sizeof(bool))
+               {
+                       gcc_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL);
+               }
+               else
+               {
+                       oberon_error(ctx, "generator: unsupported boolean size");
+               }
+       }
+       else if(type -> class == OBERON_TYPE_REAL)
+       {
+               if(type -> size == sizeof(float))
+               {
+                       gcc_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_FLOAT);
+               }
+               else if(type -> size == sizeof(double))
+               {
+                       gcc_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_DOUBLE);
+               }
+               else if(type -> size == sizeof(long double))
+               {
+                       gcc_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_LONG_DOUBLE);
+               }
+               else
+               {
+                       oberon_error(ctx, "generator: unsupported real size");
+               }
        }
        else if(type -> class == OBERON_TYPE_ARRAY)
        {
@@ -647,6 +673,11 @@ rvalue_from_item(oberon_context_t * ctx, oberon_item_t * item)
                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 if(item -> mode == MODE_REAL)
+       {
+               gcc_jit_type * int_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_FLOAT);
+               right = gcc_jit_context_new_rvalue_from_int(gcc_context, int_type, item -> real);
+       }
        else
        {
                oberon_error(ctx, "rvalue_from_item: invalid mode %i", item -> mode);
diff --git a/notes b/notes
index d8331b14584b22f479cb511a9a1c786bcab1f6e8..ebd198db2fc9f0cb61fe90b31f496dbfa4a13cf9 100644 (file)
--- a/notes
+++ b/notes
@@ -1,6 +1,6 @@
-- нету типа real, оператор / должен возвращать дробный результат
 - нету открытых массивов
 - нет символов и строк
+- нужен автокаст int -> real для DIV. Да и вообще каст типов.
 
 - нету операторов if, while и т.д.
 
index dab60b0bb151dce64579a099f2aa59f5722a2eb6..4b20dad3d30de42797478959dc92d2cd1e8929b9 100644 (file)
--- a/oberon.c
+++ b/oberon.c
@@ -4,6 +4,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "oberon.h"
 #include "generator.h"
@@ -53,7 +54,8 @@ enum {
        TO,
        UPARROW,
        NIL,
-       IMPORT
+       IMPORT,
+       REAL
 };
 
 // =======================================================================
@@ -102,6 +104,15 @@ oberon_new_type_boolean(int size)
        return x;
 }
 
+static oberon_type_t *
+oberon_new_type_real(int size)
+{
+       oberon_type_t * x;
+       x = oberon_new_type_ptr(OBERON_TYPE_REAL);
+       x -> size = size;
+       return x;
+}
+
 // =======================================================================
 //   TABLE
 // ======================================================================= 
@@ -349,28 +360,119 @@ oberon_read_ident(oberon_context_t * ctx)
 }
 
 static void
-oberon_read_integer(oberon_context_t * ctx)
-{
-       int len = 0;
-       int i = ctx -> code_index;
+oberon_read_number(oberon_context_t * ctx)
+{
+       long integer;
+       double real;
+       char * ident;
+       int start_i;
+       int exp_i;
+       int end_i;
+
+       /*
+        * mode = 0 == DEC
+        * mode = 1 == HEX
+        * mode = 2 == REAL
+        * mode = 3 == LONGREAL
+        */
+       int mode = 0;
+       start_i = ctx -> code_index;
+
+       while(isdigit(ctx -> c))
+       {
+               oberon_get_char(ctx);
+       }
 
-       int c = ctx -> code[i];
-       while(isdigit(c))
+       end_i = ctx -> code_index;
+
+       if(isxdigit(ctx -> c))
        {
-               i += 1;
-               len += 1;
-               c = ctx -> code[i];
+               mode = 1;
+               while(isxdigit(ctx -> c))
+               {
+                       oberon_get_char(ctx);
+               }
+
+               end_i = ctx -> code_index;
+
+               if(ctx -> c != 'H')
+               {
+                       oberon_error(ctx, "invalid hex number");
+               }
+               oberon_get_char(ctx);
        }
+       else if(ctx -> c == '.')
+       {
+               mode = 2;
+               oberon_get_char(ctx);
 
-       char * ident = malloc(len + 2);
-       memcpy(ident, &ctx->code[ctx->code_index], len);
-       ident[len + 1] = 0;
+               while(isdigit(ctx -> c))
+               {
+                       oberon_get_char(ctx);
+               }
+
+               if(ctx -> c == 'E' || ctx -> c == 'D')
+               {
+                       exp_i = ctx -> code_index;
+
+                       if(ctx -> c == 'D')
+                       {
+                               mode = 3;
+                       }
+
+                       oberon_get_char(ctx);
+
+                       if(ctx -> c == '+' || ctx -> c == '-')
+                       {
+                               oberon_get_char(ctx);
+                       }
+
+                       while(isdigit(ctx -> c))
+                       {
+                               oberon_get_char(ctx);
+                       }
+
+               }
+
+               end_i = ctx -> code_index;
+       }
+
+       int len = end_i - start_i;
+       ident = malloc(len + 1);
+       memcpy(ident, &ctx -> code[start_i], len);
+       ident[len] = 0;
+
+       if(mode == 3)
+       {
+               int i = exp_i - start_i;
+               ident[i] = 'E';
+       }
+
+       switch(mode)
+       {
+               case 0:
+                       integer = atol(ident);
+                       real = integer;
+                       ctx -> token = INTEGER;
+                       break;
+               case 1:
+                       sscanf(ident, "%lx", &integer);
+                       real = integer;
+                       ctx -> token = INTEGER;
+                       break;
+               case 2:
+               case 3:
+                       sscanf(ident, "%lf", &real);
+                       ctx -> token = REAL;
+                       break;
+               default:
+                       oberon_error(ctx, "oberon_read_number: wat");
+                       break;
+       }
 
-       ctx -> code_index = i;
-       ctx -> c = ctx -> code[i];
        ctx -> string = ident;
-       ctx -> integer = atoi(ident);
-       ctx -> token = INTEGER;
+       ctx -> integer = integer;
+       ctx -> real = real;
 }
 
 static void
@@ -548,7 +650,7 @@ oberon_read_token(oberon_context_t * ctx)
        }
        else if(isdigit(c))
        {
-               oberon_read_integer(ctx);
+               oberon_read_number(ctx);
        }
        else
        {
@@ -1165,6 +1267,11 @@ oberon_factor(oberon_context_t * ctx)
                        expr -> item.integer = ctx -> integer;
                        oberon_assert_token(ctx, INTEGER);
                        break;
+               case REAL:
+                       expr = oberon_new_item(MODE_REAL, ctx -> real_type, 1);
+                       expr -> item.real = ctx -> real;
+                       oberon_assert_token(ctx, REAL);
+                       break;
                case TRUE:
                        expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
                        expr -> item.boolean = 1;
@@ -1304,6 +1411,46 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                        oberon_error(ctx, "oberon_make_bin_op: bool wat");
                }
        }
+       else if(token == SLASH)
+       {
+               if(a -> result -> class != OBERON_TYPE_REAL)
+               {
+                       if(a -> result -> class == OBERON_TYPE_INTEGER)
+                       {
+                               oberon_error(ctx, "TODO cast int -> real");
+                       }
+                       else
+                       {
+                               oberon_error(ctx, "operator / requires numeric type");
+                       }
+               }
+
+               if(b -> result -> class != OBERON_TYPE_REAL)
+               {
+                       if(b -> result -> class == OBERON_TYPE_INTEGER)
+                       {
+                               oberon_error(ctx, "TODO cast int -> real");
+                       }
+                       else
+                       {
+                               oberon_error(ctx, "operator / requires numeric type");
+                       }
+               }
+
+               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+               expr = oberon_new_operator(OP_DIV, result, a, b);
+       }
+       else if(token == DIV)
+       {
+               if(a -> result -> class != OBERON_TYPE_INTEGER
+                       || b -> result -> class != OBERON_TYPE_INTEGER)
+               {
+                       oberon_error(ctx, "operator DIV requires integer type");
+               }
+
+               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+               expr = oberon_new_operator(OP_DIV, result, a, b);
+       }
        else
        {
                oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
@@ -1320,14 +1467,6 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                {
                        expr = oberon_new_operator(OP_MUL, result, a, b);
                }
-               else if(token == SLASH)
-               {
-                       expr = oberon_new_operator(OP_DIV, result, a, b);
-               }
-               else if(token == DIV)
-               {
-                       expr = oberon_new_operator(OP_DIV, result, a, b);
-               }
                else if(token == MOD)
                {
                        expr = oberon_new_operator(OP_MOD, result, a, b);
@@ -2530,8 +2669,11 @@ register_default_types(oberon_context_t * ctx)
        ctx -> int_type = oberon_new_type_integer(sizeof(int));
        oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1);
 
-       ctx -> bool_type = oberon_new_type_boolean(sizeof(int));
+       ctx -> bool_type = oberon_new_type_boolean(sizeof(bool));
        oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+
+       ctx -> real_type = oberon_new_type_real(sizeof(float));
+       oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1);
 }
 
 static void
index 53693a79629e8b772c38497cfc0c00046891cbed..189369b9c0cb324564b82aca21b21000a416e944 100644 (file)
--- a/oberon.h
+++ b/oberon.h
@@ -85,7 +85,8 @@ enum
        OBERON_TYPE_PROCEDURE,
        OBERON_TYPE_ARRAY,
        OBERON_TYPE_RECORD,
-       OBERON_TYPE_POINTER
+       OBERON_TYPE_POINTER,
+       OBERON_TYPE_REAL
 };
 
 /*
@@ -231,7 +232,8 @@ struct oberon_context_s
        char c;
        int token;
        char * string;
-       int integer;
+       long integer;
+       double real;
        /*** END SCANER DATA ***/
 
        /*** PARSER DATA ***/
@@ -241,6 +243,7 @@ struct oberon_context_s
 
        oberon_type_t * int_type;
        oberon_type_t * bool_type;
+       oberon_type_t * real_type;
        oberon_type_t * void_type;
        oberon_type_t * void_ptr_type;
        oberon_scope_t * world_scope;
@@ -259,7 +262,8 @@ enum
        MODE_FIELD,
        MODE_DEREF,
        MODE_NIL,
-       MODE_NEW
+       MODE_NEW,
+       MODE_REAL
 };
 
 enum
@@ -296,7 +300,8 @@ struct oberon_item_s
        int read_only;
 
        int mode;
-       int integer;
+       long integer;
+       double real;
        int boolean;
        oberon_object_t * var;
 
diff --git a/test.c b/test.c
index 1f440779e411b51f514c9409fddf97b033019685..1780bafa8ad900781c4af6e7f6b77868710a5119 100644 (file)
--- a/test.c
+++ b/test.c
@@ -8,6 +8,8 @@ static char source_test[] =
        "(* Main module *)"
        "MODULE Test;"
        "IMPORT Out;"
+       "CONST"
+       "  real = 0.1E3;"
        ""
        "VAR"
        "  nx- : INTEGER;"
@@ -28,6 +30,8 @@ static char source_test[] =
        "  ChParam(nx);"
        "  Out.Int(nx, 0);"
        "  Out.Ln;"
+       "  Out.Real(real / 3.0, 0);"
+       "  Out.Ln;"
        "END Test."
 ;
 
@@ -40,7 +44,7 @@ static char source_out[] =
 //     "  String-   : PROCEDURE(str : ARRAY OF CHAR)"
 //     "  Int-      : PROCEDURE(i, n : LONGINT);"
        "  Int-      : PROCEDURE(i, n : INTEGER);"
-//     "  Real-     : PROCEDURE(x : REAL; n : INTEGER);"
+       "  Real-     : PROCEDURE(x : REAL; n : INTEGER);"
 //     "  LongReal- : PROCEDURE(x : LONGREAL; n : INTEGER);"
        "  Ln-       : PROCEDURE;"
        "END Out."
@@ -77,7 +81,21 @@ static TOutInt * OutIntPtr;
 void ImplOutInt(int i, int n)
 {
        char number[22];
-       snprintf(number, 22, "%i", i);
+       snprintf(number, 22, "%d", i);
+       int len = strlen(number);
+       for(int i = 0; i < n - len; i++)
+       {
+               putchar(' ');
+       }
+       printf("%s", number);
+}
+
+typedef void (*TOutReal)(float, int);
+static TOutReal * OutRealPtr;
+void ImplOutReal(float i, int n)
+{
+       char number[32];
+       snprintf(number, 32, "%F", i);
        int len = strlen(number);
        for(int i = 0; i < n - len; i++)
        {
@@ -99,6 +117,8 @@ void init_system_modules()
        *OutOpenPtr = ImplOutOpen;
        OutIntPtr = oberon_generator_get_var(ctx, "Out_Int");
        *OutIntPtr = ImplOutInt;
+       OutRealPtr = oberon_generator_get_var(ctx, "Out_Real");
+       *OutRealPtr = ImplOutReal;
        OutLnPtr = oberon_generator_get_var(ctx, "Out_Ln");
        *OutLnPtr = ImplOutLn;
 }