X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Foberon.c;h=6a74f92c0aad16f6a3b13a6053e3e5b58e145fcc;hb=b224b07b1d47fd3ae165d652be4a9a3a10d52181;hp=09a6b8850c988e64986859aa3f2a73e3cd17d2ae;hpb=351f950548241d4c4bd799acabbcd98a39b096cc;p=dsw-obn.git diff --git a/src/oberon.c b/src/oberon.c index 09a6b88..6a74f92 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -64,7 +64,7 @@ enum { // UTILS // ======================================================================= -void +static void oberon_error(oberon_context_t * ctx, const char * fmt, ...) { va_list ptr; @@ -98,11 +98,10 @@ oberon_new_type_integer(int size) } static oberon_type_t * -oberon_new_type_boolean(int size) +oberon_new_type_boolean() { oberon_type_t * x; x = oberon_new_type_ptr(OBERON_TYPE_BOOLEAN); - x -> size = size; return x; } @@ -446,10 +445,12 @@ oberon_read_number(oberon_context_t * ctx) memcpy(ident, &ctx -> code[start_i], len); ident[len] = 0; + ctx -> longmode = false; if(mode == 3) { int i = exp_i - start_i; ident[i] = 'E'; + ctx -> longmode = true; } switch(mode) @@ -766,26 +767,87 @@ oberon_expr_list(oberon_context_t * ctx, int * num_expr, oberon_expr_t ** first, } } +static oberon_expr_t * +oberon_cast_expr(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref) +{ + oberon_expr_t * cast; + cast = oberon_new_item(MODE_CAST, pref, expr -> read_only); + cast -> item.parent = expr; + cast -> next = expr -> next; + return cast; +} + +static oberon_type_t * +oberon_get_equal_expr_type(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b) +{ + oberon_type_t * result; + if(a -> class == OBERON_TYPE_REAL && b -> class == OBERON_TYPE_INTEGER) + { + result = a; + } + else if(b -> class == OBERON_TYPE_REAL && a -> class == OBERON_TYPE_INTEGER) + { + result = b; + } + else if(a -> class != b -> class) + { + oberon_error(ctx, "oberon_get_equal_expr_type: incompatible types"); + } + else if(a -> size > b -> size) + { + result = a; + } + else + { + result = b; + } + + return result; +} + static oberon_expr_t * oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref) { if(pref -> class != expr -> result -> class) { - if(pref -> class != OBERON_TYPE_PROCEDURE) + if(pref -> class == OBERON_TYPE_POINTER) { - if(expr -> result -> class != OBERON_TYPE_POINTER) + if(expr -> result -> class == OBERON_TYPE_POINTER) + { + // accept + } + else { oberon_error(ctx, "incompatible types"); } } + else if(pref -> class == OBERON_TYPE_REAL) + { + if(expr -> result -> class == OBERON_TYPE_INTEGER) + { + // accept + } + else + { + oberon_error(ctx, "incompatible types"); + } + } + else + { + oberon_error(ctx, "incompatible types"); + } } - if(pref -> class == OBERON_TYPE_INTEGER) + if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL) { - if(expr -> result -> class > pref -> class) + if(expr -> result -> size > pref -> size) { oberon_error(ctx, "incompatible size"); } + else + { + expr = oberon_cast_expr(ctx, expr, pref); + } } else if(pref -> class == OBERON_TYPE_RECORD) { @@ -806,11 +868,19 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * } } - // TODO cast - return expr; } +static void +oberon_autocast_binary_op(oberon_context_t * ctx, oberon_expr_t ** ea, oberon_expr_t ** eb) +{ + oberon_type_t * a = (*ea) -> result; + oberon_type_t * b = (*eb) -> result; + oberon_type_t * preq = oberon_get_equal_expr_type(ctx, a, b); + *ea = oberon_autocast_to(ctx, *ea, preq); + *eb = oberon_autocast_to(ctx, *eb, preq); +} + static void oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig) { @@ -842,6 +912,8 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig) oberon_error(ctx, "too many arguments"); } + /* Делаем проверку на запись и делаем автокаст */ + oberon_expr_t * casted[num_args]; oberon_expr_t * arg = desig -> item.args; oberon_object_t * param = fn -> decl; for(int i = 0; i < num_args; i++) @@ -852,27 +924,23 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig) { 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); + casted[i] = oberon_autocast_to(ctx, arg, param -> type); arg = arg -> next; param = param -> next; } + + /* Создаём новый список выражений */ + if(num_args > 0) + { + arg = casted[0]; + for(int i = 0; i < num_args - 1; i++) + { + casted[i] -> next = casted[i + 1]; + } + desig -> item.args = arg; + } } static oberon_expr_t * @@ -999,7 +1067,7 @@ oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr) oberon_expr_t * selector; selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only); - selector -> item.parent = (oberon_item_t *) expr; + selector -> item.parent = expr; return selector; } @@ -1046,7 +1114,7 @@ oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, oberon oberon_expr_t * selector; selector = oberon_new_item(MODE_INDEX, base, desig -> read_only); - selector -> item.parent = (oberon_item_t *) desig; + selector -> item.parent = desig; selector -> item.num_args = 1; selector -> item.args = index; @@ -1093,7 +1161,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char * oberon_expr_t * selector; selector = oberon_new_item(MODE_FIELD, field -> type, read_only); selector -> item.var = field; - selector -> item.parent = (oberon_item_t *) expr; + selector -> item.parent = expr; return selector; } @@ -1258,10 +1326,32 @@ oberon_opt_proc_parens(oberon_context_t * ctx, oberon_expr_t * expr) oberon_make_call_proc(ctx, expr -> item.var, num_args, arguments); } +static oberon_type_t * +oberon_get_type_of_int_value(oberon_context_t * ctx, int64_t i) +{ + if(i >= -128 && i <= 127) + { + return ctx -> byte_type; + } + else if(i >= -32768 && i <= 32767) + { + return ctx -> shortint_type; + } + else if(i >= -2147483648 && i <= 2147483647) + { + return ctx -> int_type; + } + else + { + return ctx -> longint_type; + } +} + static oberon_expr_t * oberon_factor(oberon_context_t * ctx) { oberon_expr_t * expr; + oberon_type_t * result; switch(ctx -> token) { @@ -1270,23 +1360,25 @@ oberon_factor(oberon_context_t * ctx) expr = oberon_opt_func_parens(ctx, expr); break; case INTEGER: - expr = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1); + result = oberon_get_type_of_int_value(ctx, ctx -> integer); + expr = oberon_new_item(MODE_INTEGER, result, 1); expr -> item.integer = ctx -> integer; oberon_assert_token(ctx, INTEGER); break; case REAL: - expr = oberon_new_item(MODE_REAL, ctx -> real_type, 1); + result = (ctx -> longmode) ? (ctx -> longreal_type) : (ctx -> real_type); + expr = oberon_new_item(MODE_REAL, result, 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; + expr -> item.boolean = true; oberon_assert_token(ctx, TRUE); break; case FALSE: expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1); - expr -> item.boolean = 0; + expr -> item.boolean = false; oberon_assert_token(ctx, FALSE); break; case LPAREN: @@ -1310,41 +1402,6 @@ oberon_factor(oberon_context_t * ctx) return expr; } -/* - * oberon_autocast_binary_op автоматически переобразовывеат тип по след. правилам: - * 1. Классы обоих типов должны быть одинаковы - * 2. В качестве результата должен быть выбран больший тип. - * 3. Если размер результат не должен быть меньше чем базовый int - */ - -static void -oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b, oberon_type_t ** result) -{ - if((a -> class) != (b -> class)) - { - oberon_error(ctx, "incompatible types"); - } - - if((a -> size) > (b -> size)) - { - *result = a; - } - else - { - *result = b; - } - - if(((*result) -> class) == OBERON_TYPE_INTEGER) - { - if(((*result) -> size) < (ctx -> int_type -> size)) - { - *result = ctx -> int_type; - } - } - - /* TODO: cast types */ -} - #define ITMAKESBOOLEAN(x) \ (((x) >= EQUAL && (x) <= GEQ) || ((x) == OR) || ((x) == AND)) @@ -1354,6 +1411,27 @@ oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type #define ITUSEONLYBOOLEAN(x) \ (((x) == OR) || ((x) == AND)) +static void +oberon_autocast_to_real(oberon_context_t * ctx, oberon_expr_t ** e) +{ + oberon_expr_t * expr = *e; + if(expr -> result -> class == OBERON_TYPE_INTEGER) + { + if(expr -> result -> size <= ctx -> real_type -> size) + { + *e = oberon_cast_expr(ctx, expr, ctx -> real_type); + } + else + { + *e = oberon_cast_expr(ctx, expr, ctx -> longreal_type); + } + } + else if(expr -> result -> class != OBERON_TYPE_REAL) + { + oberon_error(ctx, "required numeric type"); + } +} + static oberon_expr_t * oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b) { @@ -1364,10 +1442,12 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ { if(ITUSEONLYINTEGER(token)) { - if(a -> result -> class != OBERON_TYPE_INTEGER - || b -> result -> class != OBERON_TYPE_INTEGER) + if(a -> result -> class == OBERON_TYPE_INTEGER + || b -> result -> class == OBERON_TYPE_INTEGER + || a -> result -> class == OBERON_TYPE_REAL + || b -> result -> class == OBERON_TYPE_REAL) { - oberon_error(ctx, "used only with integer types"); + oberon_error(ctx, "used only with numeric types"); } } else if(ITUSEONLYBOOLEAN(token)) @@ -1379,6 +1459,7 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ } } + oberon_autocast_binary_op(ctx, &a, &b); result = ctx -> bool_type; if(token == EQUAL) @@ -1420,32 +1501,10 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ } 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); + oberon_autocast_to_real(ctx, &a); + oberon_autocast_to_real(ctx, &b); + oberon_autocast_binary_op(ctx, &a, &b); + expr = oberon_new_operator(OP_DIV, a -> result, a, b); } else if(token == DIV) { @@ -1455,28 +1514,28 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ 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); + oberon_autocast_binary_op(ctx, &a, &b); + expr = oberon_new_operator(OP_DIV, a -> result, a, b); } else { - oberon_autocast_binary_op(ctx, a -> result, b -> result, &result); + oberon_autocast_binary_op(ctx, &a, &b); if(token == PLUS) { - expr = oberon_new_operator(OP_ADD, result, a, b); + expr = oberon_new_operator(OP_ADD, a -> result, a, b); } else if(token == MINUS) { - expr = oberon_new_operator(OP_SUB, result, a, b); + expr = oberon_new_operator(OP_SUB, a -> result, a, b); } else if(token == STAR) { - expr = oberon_new_operator(OP_MUL, result, a, b); + expr = oberon_new_operator(OP_MUL, a -> result, a, b); } else if(token == MOD) { - expr = oberon_new_operator(OP_MOD, result, a, b); + expr = oberon_new_operator(OP_MOD, a -> result, a, b); } else { @@ -1814,7 +1873,7 @@ oberon_make_return(oberon_context_t * ctx, oberon_expr_t * expr) oberon_error(ctx, "procedure requires expression on result"); } - oberon_autocast_to(ctx, expr, result_type); + expr = oberon_autocast_to(ctx, expr, result_type); } proc -> has_return = 1; @@ -2201,7 +2260,8 @@ oberon_prevent_recursive_pointer(oberon_context_t * ctx, oberon_type_t * type) oberon_error(ctx, "recursive pointer declaration"); } - if(type -> base -> class == OBERON_TYPE_POINTER) + if(type -> class == OBERON_TYPE_POINTER + && type -> base -> class == OBERON_TYPE_POINTER) { oberon_error(ctx, "attempt to make pointer to pointer"); } @@ -2550,7 +2610,7 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) oberon_error(ctx, "read-only destination"); } - oberon_autocast_to(ctx, src, dst -> result); + src = oberon_autocast_to(ctx, src, dst -> result); oberon_generate_assign(ctx, src, dst); } @@ -2701,6 +2761,8 @@ oberon_parse_module(oberon_context_t * ctx) { oberon_error(ctx, "module name not matched"); } + + oberon_generator_fini_module(ctx -> mod); } // ======================================================================= @@ -2717,14 +2779,26 @@ register_default_types(oberon_context_t * ctx) ctx -> void_ptr_type -> base = ctx -> void_type; oberon_generator_init_type(ctx, ctx -> void_ptr_type); - ctx -> int_type = oberon_new_type_integer(sizeof(int)); + ctx -> bool_type = oberon_new_type_boolean(); + oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1); + + ctx -> byte_type = oberon_new_type_integer(1); + oberon_define_type(ctx -> world_scope, "BYTE", ctx -> byte_type, 1); + + ctx -> shortint_type = oberon_new_type_integer(2); + oberon_define_type(ctx -> world_scope, "SHORTINT", ctx -> shortint_type, 1); + + ctx -> int_type = oberon_new_type_integer(4); oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1); - ctx -> bool_type = oberon_new_type_boolean(sizeof(bool)); - oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1); + ctx -> longint_type = oberon_new_type_integer(8); + oberon_define_type(ctx -> world_scope, "LONGINT", ctx -> longint_type, 1); - ctx -> real_type = oberon_new_type_real(sizeof(float)); + ctx -> real_type = oberon_new_type_real(4); oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1); + + ctx -> longreal_type = oberon_new_type_real(8); + oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1); } static void @@ -2885,6 +2959,8 @@ oberon_compile_module(oberon_context_t * ctx, const char * newcode) int token = ctx -> token; char * string = ctx -> string; int integer = ctx -> integer; + int real = ctx -> real; + bool longmode = ctx -> longmode; oberon_scope_t * decl = ctx -> decl; oberon_module_t * mod = ctx -> mod; @@ -2910,6 +2986,8 @@ oberon_compile_module(oberon_context_t * ctx, const char * newcode) ctx -> token = token; ctx -> string = string; ctx -> integer = integer; + ctx -> real = real; + ctx -> longmode = longmode; ctx -> decl = decl; ctx -> mod = mod;