X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Foberon.c;h=8de42d912fbb0ed03442b54072db6e353316d594;hb=25b73915e7fe0ae7dc51cf6f4a012f021257a35d;hp=d636fba6b19d253c65a167420a25f21547bef892;hpb=9e6d0f74f74926a9c73d15418c2e9668689061f2;p=dsw-obn.git diff --git a/src/oberon.c b/src/oberon.c index d636fba..8de42d9 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; } @@ -131,8 +130,9 @@ oberon_open_scope(oberon_context_t * ctx) if(scope -> up) { - scope -> parent = scope -> up -> parent; scope -> local = scope -> up -> local; + scope -> parent = scope -> up -> parent; + scope -> parent_type = scope -> up -> parent_type; } ctx -> decl = scope; @@ -168,6 +168,7 @@ oberon_define_object(oberon_scope_t * scope, char * name, int class, int export, newvar -> read_only = read_only; newvar -> local = scope -> local; newvar -> parent = scope -> parent; + newvar -> parent_type = scope -> parent_type; newvar -> module = scope -> ctx -> mod; x -> next = newvar; @@ -444,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) @@ -764,26 +767,88 @@ 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) +{ + assert(expr -> is_item); + oberon_expr_t * cast; + cast = oberon_new_item(MODE_CAST, pref, expr -> read_only); + cast -> item.parent = (oberon_item_t *) 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) { @@ -804,11 +869,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) { @@ -840,6 +913,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++) @@ -850,27 +925,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 * @@ -1256,10 +1327,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) { @@ -1268,23 +1361,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: @@ -1308,41 +1403,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)) @@ -1442,8 +1502,8 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ } } - 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 if(token == DIV) { @@ -1453,28 +1513,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 { @@ -1527,6 +1587,12 @@ oberon_simple_expr(oberon_context_t * ctx) } expr = oberon_term_expr(ctx); + + if(minus) + { + expr = oberon_make_unary_op(ctx, MINUS, expr); + } + while(ISADDOP(ctx -> token)) { int token = ctx -> token; @@ -1536,11 +1602,6 @@ oberon_simple_expr(oberon_context_t * ctx) expr = oberon_make_bin_op(ctx, token, expr, inter); } - if(minus) - { - expr = oberon_make_unary_op(ctx, MINUS, expr); - } - return expr; } @@ -1811,7 +1872,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; @@ -2083,12 +2144,13 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type) oberon_type_t * rec; rec = *type; rec -> class = OBERON_TYPE_RECORD; + rec -> module = ctx -> mod; oberon_scope_t * record_scope; record_scope = oberon_open_scope(ctx); - // TODO parent object - //record_scope -> parent = NULL; record_scope -> local = 1; + record_scope -> parent = NULL; + record_scope -> parent_type = rec; oberon_assert_token(ctx, RECORD); oberon_field_list(ctx, rec); @@ -2197,7 +2259,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"); } @@ -2546,7 +2609,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); } @@ -2672,6 +2735,8 @@ oberon_parse_module(oberon_context_t * ctx) oberon_assert_token(ctx, SEMICOLON); ctx -> mod -> name = name1; + oberon_generator_init_module(ctx, ctx -> mod); + if(ctx -> token == IMPORT) { oberon_import_list(ctx); @@ -2695,6 +2760,8 @@ oberon_parse_module(oberon_context_t * ctx) { oberon_error(ctx, "module name not matched"); } + + oberon_generator_fini_module(ctx -> mod); } // ======================================================================= @@ -2711,14 +2778,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 @@ -2879,6 +2958,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; @@ -2904,6 +2985,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;