From ea5cf056abf2bf42e9f328b9c1f2d94ee96bcc4c Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Mon, 24 Jul 2017 23:05:37 +0300 Subject: [PATCH] =?utf8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?utf8?q?=20=D1=82=D0=B8=D0=BF=20REAL?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- generator.c | 33 ++++++++- notes | 2 +- oberon.c | 196 ++++++++++++++++++++++++++++++++++++++++++++-------- oberon.h | 13 ++-- test.c | 24 ++++++- 5 files changed, 233 insertions(+), 35 deletions(-) diff --git a/generator.c b/generator.c index 179320a..d54bbfd 100644 --- a/generator.c +++ b/generator.c @@ -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 d8331b1..ebd198d 100644 --- a/notes +++ b/notes @@ -1,6 +1,6 @@ -- нету типа real, оператор / должен возвращать дробный результат - нету открытых массивов - нет символов и строк +- нужен автокаст int -> real для DIV. Да и вообще каст типов. - нету операторов if, while и т.д. diff --git a/oberon.c b/oberon.c index dab60b0..4b20dad 100644 --- a/oberon.c +++ b/oberon.c @@ -4,6 +4,7 @@ #include #include #include +#include #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 diff --git a/oberon.h b/oberon.h index 53693a7..189369b 100644 --- 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 1f44077..1780baf 100644 --- 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; } -- 2.29.2