X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=blobdiff_plain;f=src%2Foberon.c;h=59a5c3d5fa7f6f11dc9e65e6b1974f59fca12770;hp=064cfb10bd0b24955eb0b23655c12ee68d62cf52;hb=c535b4be889716bfd37a4f0dd888f398534bc306;hpb=879793eaf1d6378593f78a192f2961670f686530 diff --git a/src/oberon.c b/src/oberon.c index 064cfb1..59a5c3d 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -24,8 +24,6 @@ enum { BEGIN, ASSIGN, INTEGER, - TRUE, - FALSE, LPAREN, RPAREN, EQUAL, @@ -87,6 +85,9 @@ enum { // UTILS // ======================================================================= +static void +oberon_make_copy_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args); + static void oberon_error(oberon_context_t * ctx, const char * fmt, ...) { @@ -344,14 +345,6 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = BEGIN; } - else if(strcmp(ident, "TRUE") == 0) - { - ctx -> token = TRUE; - } - else if(strcmp(ident, "FALSE") == 0) - { - ctx -> token = FALSE; - } else if(strcmp(ident, "OR") == 0) { ctx -> token = OR; @@ -700,8 +693,6 @@ static void oberon_read_string(oberon_context_t * ctx) ctx -> token = STRING; ctx -> string = string; - - printf("oberon_read_string: string ((%s))\n", string); } static void oberon_read_token(oberon_context_t * ctx); @@ -996,11 +987,8 @@ oberno_make_record_cast(oberon_context_t * ctx, oberon_expr_t * expr, oberon_typ oberon_type_t * from = expr -> result; oberon_type_t * to = rec; - printf("oberno_make_record_cast: from class %i to class %i\n", from -> class, to -> class); - if(from -> class == OBERON_TYPE_POINTER && to -> class == OBERON_TYPE_POINTER) { - printf("oberno_make_record_cast: pointers\n"); from = from -> base; to = to -> base; } @@ -1070,6 +1058,11 @@ oberon_check_record_compatibility(oberon_context_t * ctx, oberon_type_t * from, static void oberon_check_dst(oberon_context_t * ctx, oberon_expr_t * dst) { + if(dst -> read_only) + { + oberon_error(ctx, "read-only destination"); + } + if(dst -> is_item == false) { oberon_error(ctx, "not variable"); @@ -1109,18 +1102,25 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * // Допускается: // Если классы типов равны // Если INTEGER переводится в REAL - // Есди STRING переводится в CHAR - // Есди STRING переводится в ARRAY OF CHAR + // Если STRING переводится в CHAR + // Если STRING переводится в ARRAY OF CHAR + // Если NIL переводится в POINTER + // Если NIL переводится в PROCEDURE oberon_check_src(ctx, expr); bool error = false; if(pref -> class != expr -> result -> class) { - printf("expr class %i\n", expr -> result -> class); - printf("pref class %i\n", pref -> class); - - if(expr -> result -> class == OBERON_TYPE_STRING) + if(expr -> result -> class == OBERON_TYPE_NIL) + { + if(pref -> class != OBERON_TYPE_POINTER + && pref -> class != OBERON_TYPE_PROCEDURE) + { + error = true; + } + } + else if(expr -> result -> class == OBERON_TYPE_STRING) { if(pref -> class == OBERON_TYPE_CHAR) { @@ -1194,17 +1194,18 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * else if(pref -> class == OBERON_TYPE_POINTER) { assert(pref -> base); - if(expr -> result -> base -> class == OBERON_TYPE_RECORD) + if(expr -> result -> class == OBERON_TYPE_NIL) + { + // do nothing + } + else if(expr -> result -> base -> class == OBERON_TYPE_RECORD) { oberon_check_record_compatibility(ctx, expr -> result, pref); expr = oberno_make_record_cast(ctx, expr, pref); } else if(expr -> result -> base != pref -> base) { - if(expr -> result -> base -> class != OBERON_TYPE_VOID) - { - oberon_error(ctx, "incompatible pointer types"); - } + oberon_error(ctx, "incompatible pointer types"); } } @@ -1303,7 +1304,7 @@ oberon_make_call_func(oberon_context_t * ctx, oberon_item_t * item, int num_args } else { - if(signature -> base -> class == OBERON_TYPE_VOID) + if(signature -> base -> class == OBERON_TYPE_NOTYPE) { oberon_error(ctx, "attempt to call procedure in expression"); } @@ -1340,7 +1341,7 @@ oberon_make_call_proc(oberon_context_t * ctx, oberon_item_t * item, int num_args } else { - if(signature -> base -> class != OBERON_TYPE_VOID) + if(signature -> base -> class != OBERON_TYPE_NOTYPE) { oberon_error(ctx, "attempt to call function as non-typed procedure"); } @@ -1364,14 +1365,11 @@ oberon_make_call_proc(oberon_context_t * ctx, oberon_item_t * item, int num_args || ((x) == STRING) \ || ((x) == NIL) \ || ((x) == LPAREN) \ - || ((x) == NOT) \ - || ((x) == TRUE) \ - || ((x) == FALSE)) + || ((x) == NOT)) static oberon_expr_t * oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr) { - printf("oberno_make_dereferencing\n"); if(expr -> result -> class != OBERON_TYPE_POINTER) { oberon_error(ctx, "not a pointer"); @@ -1463,7 +1461,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char * } } - int read_only = 0; + int read_only = expr -> read_only; if(field -> read_only) { if(field -> module != ctx -> mod) @@ -1583,11 +1581,53 @@ oberon_qualident_expr(oberon_context_t * ctx) return expr; } +static void +oberon_check_type_guard(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * type) +{ + /* Охрана типа применима, если */ + /* 1. v - параметр-переменная типа запись, или v - указатель, и если */ + /* 2. T - расширение статического типа v */ + + if(expr -> is_item + && expr -> item.mode == MODE_VAR + && expr -> item.var -> class == OBERON_CLASS_VAR_PARAM) + { + // accept + } + else if(expr -> result -> class == OBERON_TYPE_POINTER + || expr -> result -> class == OBERON_TYPE_RECORD) + { + // accept + } + else + { + oberon_error(ctx, "guard type used only with var-param or pointers"); + } + + oberon_check_record_compatibility(ctx, type, expr -> result); +} + +static oberon_expr_t * +oberon_make_type_guard(oberon_context_t * ctx, oberon_expr_t * expr, oberon_object_t * objtype) +{ + oberon_type_t * type; + + if(objtype -> class != OBERON_CLASS_TYPE) + { + oberon_error(ctx, "must be type"); + } + type = objtype -> type; + + oberon_check_type_guard(ctx, expr, type); + return oberno_make_record_cast(ctx, expr, objtype -> type); +} + static oberon_expr_t * oberon_designator(oberon_context_t * ctx) { char * name; oberon_expr_t * expr; + oberon_object_t * objtype; expr = oberon_qualident_expr(ctx); @@ -1619,13 +1659,9 @@ oberon_designator(oberon_context_t * ctx) break; case LPAREN: oberon_assert_token(ctx, LPAREN); - oberon_object_t * objtype = oberon_qualident(ctx, NULL, 1); - if(objtype -> class != OBERON_CLASS_TYPE) - { - oberon_error(ctx, "must be type"); - } + objtype = oberon_qualident(ctx, NULL, true); oberon_assert_token(ctx, RPAREN); - expr = oberno_make_record_cast(ctx, expr, objtype -> type); + expr = oberon_make_type_guard(ctx, expr, objtype); break; default: oberon_error(ctx, "oberon_designator: wat"); @@ -1770,6 +1806,15 @@ oberon_set(oberon_context_t * ctx) return set; } +static oberon_expr_t * +oberon_make_boolean(oberon_context_t * ctx, bool cond) +{ + oberon_expr_t * expr; + expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, true); + expr -> item.integer = cond; + return expr; +} + static oberon_expr_t * oberon_factor(oberon_context_t * ctx) { @@ -1804,16 +1849,6 @@ oberon_factor(oberon_context_t * ctx) expr -> item.real = ctx -> real; oberon_assert_token(ctx, REAL); break; - case TRUE: - expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, true); - expr -> item.boolean = true; - oberon_assert_token(ctx, TRUE); - break; - case FALSE: - expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, true); - expr -> item.boolean = false; - oberon_assert_token(ctx, FALSE); - break; case LBRACE: expr = oberon_set(ctx); break; @@ -1829,7 +1864,7 @@ oberon_factor(oberon_context_t * ctx) break; case NIL: oberon_assert_token(ctx, NIL); - expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type, true); + expr = oberon_new_item(MODE_NIL, ctx -> nil_type, true); break; default: oberon_error(ctx, "invalid expression"); @@ -1838,15 +1873,6 @@ oberon_factor(oberon_context_t * ctx) return expr; } -#define ITMAKESBOOLEAN(x) \ - (((x) >= EQUAL && (x) <= GEQ) || ((x) == OR) || ((x) == AND)) - -#define ITUSEONLYINTEGER(x) \ - ((x) >= LESS && (x) <= GEQ) - -#define ITUSEONLYBOOLEAN(x) \ - (((x) == OR) || ((x) == AND)) - static void oberon_autocast_to_real(oberon_context_t * ctx, oberon_expr_t ** e) { @@ -1868,6 +1894,49 @@ oberon_autocast_to_real(oberon_context_t * ctx, oberon_expr_t ** e) } } +static bool +oberon_is_numeric_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_INTEGER) || (t -> class == OBERON_TYPE_REAL); +} + +static bool +oberon_is_char_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_CHAR); +} + +static bool +oberon_is_string_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_STRING) + || (t -> class == OBERON_TYPE_ARRAY && t -> base -> class == OBERON_TYPE_CHAR); +} + +static bool +oberon_is_boolean_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_BOOLEAN); +} + +static bool +oberon_is_set_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_SET); +} + +static bool +oberon_is_pointer_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_POINTER) || (t -> class == OBERON_TYPE_NIL); +} + +static bool +oberon_is_procedure_type(oberon_type_t * t) +{ + return (t -> class == OBERON_TYPE_POINTER) || (t -> class == OBERON_TYPE_NIL); +} + static oberon_expr_t * oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b) { @@ -1892,66 +1961,82 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ } else if(token == IS) { - oberon_type_t * v = a -> result; - if(v -> class == OBERON_TYPE_POINTER) - { - v = v -> base; - if(v -> class != OBERON_TYPE_RECORD) - { - oberon_error(ctx, "must be record"); - } - } - else if(v -> class != OBERON_TYPE_RECORD) - { - oberon_error(ctx, "must be record"); - } - if(b -> is_item == false || b -> item.mode != MODE_TYPE) { oberon_error(ctx, "requires type"); } - oberon_type_t * t = b -> result; - if(t -> class == OBERON_TYPE_POINTER) - { - t = t -> base; - if(t -> class != OBERON_TYPE_RECORD) - { - oberon_error(ctx, "must be record"); - } - } - else if(t -> class != OBERON_TYPE_RECORD) - { - oberon_error(ctx, "must be record"); - } - result = ctx -> bool_type; + oberon_check_type_guard(ctx, a, b -> result); expr = oberon_new_operator(OP_IS, result, a, b); } - else if(ITMAKESBOOLEAN(token)) + else if((token >= EQUAL && token <= GEQ) || token == OR || token == AND) { - if(ITUSEONLYINTEGER(token)) + if(token >= LESS && token <= GEQ) { - 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) + if(oberon_is_numeric_type(a -> result) && oberon_is_numeric_type(b -> result)) + { + // accept + } + else if(oberon_is_char_type(a -> result) && oberon_is_char_type(b -> result)) + { + // accept + } + else if(oberon_is_string_type(a -> result) && oberon_is_string_type(b -> result)) + { + // accept + } + else + { + oberon_error(ctx, "invalid comparation"); + } + } + else if(token == EQUAL || token == NEQ) + { + if(oberon_is_numeric_type(a -> result) && oberon_is_numeric_type(b -> result)) + { + // accept + } + else if(oberon_is_char_type(a -> result) && oberon_is_char_type(b -> result)) + { + // accept + } + else if(oberon_is_string_type(a -> result) && oberon_is_string_type(b -> result)) + { + // accept + } + else if(oberon_is_boolean_type(a -> result) && oberon_is_boolean_type(b -> result)) + { + // accept + } + else if(oberon_is_set_type(a -> result) && oberon_is_set_type(b -> result)) + { + // accept + } + else if(oberon_is_pointer_type(a -> result) && oberon_is_pointer_type(b -> result)) + { + // accept + } + else if(oberon_is_procedure_type(a -> result) && oberon_is_procedure_type(b -> result)) { // accept } else { - oberon_error(ctx, "used only with numeric types"); + oberon_error(ctx, "invalid comparation"); } } - else if(ITUSEONLYBOOLEAN(token)) + else if(token == AND || token == OR) { - if(a -> result -> class != OBERON_TYPE_BOOLEAN - || b -> result -> class != OBERON_TYPE_BOOLEAN) + if(!oberon_is_boolean_type(a -> result) || !oberon_is_boolean_type(b -> result)) { - oberon_error(ctx, "used only with boolean type"); + oberon_error(ctx, "invalid comparation"); } } + else + { + oberon_error(ctx, "wat"); + } oberon_autocast_binary_op(ctx, &a, &b); result = ctx -> bool_type; @@ -2284,7 +2369,7 @@ oberon_var_decl(oberon_context_t * ctx) int num; oberon_object_t * list; oberon_type_t * type; - type = oberon_new_type_ptr(OBERON_TYPE_VOID); + type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_ident_list(ctx, OBERON_CLASS_VAR, false, &num, &list); oberon_assert_token(ctx, COLON); @@ -2315,7 +2400,7 @@ oberon_fp_section(oberon_context_t * ctx, int * num_decl) oberon_assert_token(ctx, COLON); oberon_type_t * type; - type = oberon_new_type_ptr(OBERON_TYPE_VOID); + type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_type(ctx, &type); oberon_object_t * param = list; @@ -2359,6 +2444,11 @@ oberon_formal_pars(oberon_context_t * ctx, oberon_type_t * signature) { oberon_error(ctx, "function result is not type"); } + if(typeobj -> type -> class == OBERON_TYPE_RECORD + || typeobj -> type -> class == OBERON_TYPE_ARRAY) + { + oberon_error(ctx, "records or arrays could not be result of function"); + } signature -> base = typeobj -> type; } } @@ -2370,7 +2460,7 @@ oberon_opt_formal_pars(oberon_context_t * ctx, oberon_type_t ** type) signature = *type; signature -> class = OBERON_TYPE_PROCEDURE; signature -> num_decl = 0; - signature -> base = ctx -> void_type; + signature -> base = ctx -> notype_type; signature -> decl = NULL; if(ctx -> token == LPAREN) @@ -2413,7 +2503,7 @@ oberon_make_return(oberon_context_t * ctx, oberon_expr_t * expr) oberon_object_t * proc = ctx -> decl -> parent; oberon_type_t * result_type = proc -> type -> base; - if(result_type -> class == OBERON_TYPE_VOID) + if(result_type -> class == OBERON_TYPE_NOTYPE) { if(expr != NULL) { @@ -2459,7 +2549,7 @@ oberon_proc_decl_body(oberon_context_t * ctx, oberon_object_t * proc) oberon_error(ctx, "procedure name not matched"); } - if(proc -> type -> base -> class == OBERON_TYPE_VOID + if(proc -> type -> base -> class == OBERON_TYPE_NOTYPE && proc -> has_return == 0) { oberon_make_return(ctx, NULL); @@ -2497,7 +2587,7 @@ oberon_proc_decl(oberon_context_t * ctx) ctx -> decl -> local = 1; oberon_type_t * signature; - signature = oberon_new_type_ptr(OBERON_TYPE_VOID); + signature = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_opt_formal_pars(ctx, &signature); //oberon_initialize_decl(ctx); @@ -2604,7 +2694,7 @@ oberon_qualident_type(oberon_context_t * ctx, oberon_type_t ** type) else { to = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, false, false, false); - to -> type = oberon_new_type_ptr(OBERON_TYPE_VOID); + to -> type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); } *type = to -> type; @@ -2626,7 +2716,7 @@ oberon_make_multiarray(oberon_context_t * ctx, oberon_expr_t * sizes, oberon_typ } oberon_type_t * dim; - dim = oberon_new_type_ptr(OBERON_TYPE_VOID); + dim = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_make_multiarray(ctx, sizes -> next, base, &dim); @@ -2649,7 +2739,7 @@ oberon_field_list(oberon_context_t * ctx, oberon_type_t * rec, oberon_scope_t * int num; oberon_object_t * list; oberon_type_t * type; - type = oberon_new_type_ptr(OBERON_TYPE_VOID); + type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_ident_list(ctx, OBERON_CLASS_FIELD, true, &num, &list); oberon_assert_token(ctx, COLON); @@ -2750,7 +2840,7 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type) oberon_assert_token(ctx, OF); oberon_type_t * base; - base = oberon_new_type_ptr(OBERON_TYPE_VOID); + base = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_type(ctx, &base); if(num_sizes == 0) @@ -2781,7 +2871,7 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type) oberon_assert_token(ctx, TO); oberon_type_t * base; - base = oberon_new_type_ptr(OBERON_TYPE_VOID); + base = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); oberon_type(ctx, &base); oberon_type_t * ptr; @@ -2818,7 +2908,7 @@ oberon_type_decl(oberon_context_t * ctx) if(newtype == NULL) { newtype = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, export, read_only, false); - newtype -> type = oberon_new_type_ptr(OBERON_TYPE_VOID); + newtype -> type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); assert(newtype -> type); } else @@ -2842,7 +2932,7 @@ oberon_type_decl(oberon_context_t * ctx) type = newtype -> type; oberon_type(ctx, &type); - if(type -> class == OBERON_TYPE_VOID) + if(type -> class == OBERON_TYPE_NOTYPE) { oberon_error(ctx, "recursive alias declaration"); } @@ -2896,6 +2986,11 @@ oberon_prevent_recursive_record(oberon_context_t * ctx, oberon_type_t * type) type -> recursive = 1; + if(type -> base) + { + oberon_prevent_recursive_record(ctx, type -> base); + } + int num_fields = type -> num_decl; oberon_object_t * field = type -> decl; for(int i = 0; i < num_fields; i++) @@ -3037,7 +3132,7 @@ oberon_initialize_record_fields(oberon_context_t * ctx, oberon_type_t * type) static void oberon_initialize_type(oberon_context_t * ctx, oberon_type_t * type) { - if(type -> class == OBERON_TYPE_VOID) + if(type -> class == OBERON_TYPE_NOTYPE) { oberon_error(ctx, "undeclarated type"); } @@ -3232,14 +3327,30 @@ oberon_statement_seq(oberon_context_t * ctx); static void oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) { - if(dst -> read_only) + if(src -> is_item + && src -> item.mode == MODE_STRING + && src -> result -> class == OBERON_TYPE_STRING + && dst -> result -> class == OBERON_TYPE_ARRAY + && dst -> result -> base -> class == OBERON_TYPE_CHAR + && dst -> result -> size > 0) { - oberon_error(ctx, "read-only destination"); - } - oberon_check_dst(ctx, dst); - src = oberon_autocast_to(ctx, src, dst -> result); - oberon_generate_assign(ctx, src, dst); + if(strlen(src -> item.string) < dst -> result -> size) + { + src -> next = dst; + oberon_make_copy_call(ctx, 2, src); + } + else + { + oberon_error(ctx, "string too long for destination"); + } + } + else + { + oberon_check_dst(ctx, dst); + src = oberon_autocast_to(ctx, src, dst -> result); + oberon_generate_assign(ctx, src, dst); + } } static oberon_expr_t * @@ -3538,11 +3649,11 @@ oberon_statement(oberon_context_t * ctx) index = oberon_ident_item(ctx, iname); oberon_assert_token(ctx, ASSIGN); from = oberon_expr(ctx); - oberon_assign(ctx, from, index); oberon_assert_token(ctx, TO); bound = oberon_make_temp_var_item(ctx, index -> result); to = oberon_expr(ctx); - oberon_assign(ctx, to, bound); + oberon_assign(ctx, to, bound); // сначала temp + oberon_assign(ctx, from, index); // потом i if(ctx -> token == BY) { oberon_assert_token(ctx, BY); @@ -3755,12 +3866,11 @@ oberon_parse_module(oberon_context_t * ctx) static void register_default_types(oberon_context_t * ctx) { - ctx -> void_type = oberon_new_type_ptr(OBERON_TYPE_VOID); - oberon_generator_init_type(ctx, ctx -> void_type); + ctx -> notype_type = oberon_new_type_ptr(OBERON_TYPE_NOTYPE); + oberon_generator_init_type(ctx, ctx -> notype_type); - ctx -> void_ptr_type = oberon_new_type_ptr(OBERON_TYPE_POINTER); - ctx -> void_ptr_type -> base = ctx -> void_type; - oberon_generator_init_type(ctx, ctx -> void_ptr_type); + ctx -> nil_type = oberon_new_type_ptr(OBERON_TYPE_NIL); + oberon_generator_init_type(ctx, ctx -> nil_type); ctx -> string_type = oberon_new_type_string(1); oberon_generator_init_type(ctx, ctx -> string_type); @@ -3768,17 +3878,20 @@ register_default_types(oberon_context_t * ctx) ctx -> bool_type = oberon_new_type_boolean(); oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1); + ctx -> char_type = oberon_new_type_char(1); + oberon_define_type(ctx -> world_scope, "CHAR", ctx -> char_type, 1); + ctx -> byte_type = oberon_new_type_integer(1); - oberon_define_type(ctx -> world_scope, "BYTE", ctx -> byte_type, 1); + oberon_define_type(ctx -> world_scope, "SHORTINT", ctx -> byte_type, 1); ctx -> shortint_type = oberon_new_type_integer(2); - oberon_define_type(ctx -> world_scope, "SHORTINT", ctx -> shortint_type, 1); + oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> shortint_type, 1); ctx -> int_type = oberon_new_type_integer(4); - oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1); + oberon_define_type(ctx -> world_scope, "LONGINT", ctx -> int_type, 1); ctx -> longint_type = oberon_new_type_integer(8); - oberon_define_type(ctx -> world_scope, "LONGINT", ctx -> longint_type, 1); + oberon_define_type(ctx -> world_scope, "HUGEINT", ctx -> longint_type, 1); ctx -> real_type = oberon_new_type_real(4); oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1); @@ -3786,9 +3899,6 @@ register_default_types(oberon_context_t * ctx) ctx -> longreal_type = oberon_new_type_real(8); oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1); - ctx -> char_type = oberon_new_type_char(1); - oberon_define_type(ctx -> world_scope, "CHAR", ctx -> char_type, 1); - ctx -> set_type = oberon_new_type_set(4); oberon_define_type(ctx -> world_scope, "SET", ctx -> set_type, 1); } @@ -3962,7 +4072,6 @@ oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ oberon_error(ctx, "too few arguments"); } - oberon_expr_t * dst; dst = list_args; oberon_check_dst(ctx, dst); @@ -4038,6 +4147,119 @@ oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ oberon_assign(ctx, src, dst); } +static void +oberon_make_copy_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args) +{ + if(num_args < 2) + { + oberon_error(ctx, "too few arguments"); + } + + if(num_args > 2) + { + oberon_error(ctx, "too mach arguments"); + } + + oberon_expr_t * src; + src = list_args; + oberon_check_src(ctx, src); + + oberon_expr_t * dst; + dst = list_args -> next; + oberon_check_dst(ctx, dst); + + if(!oberon_is_string_type(src -> result)) + { + oberon_error(ctx, "source must be string or array of char"); + } + + if(!oberon_is_string_type(dst -> result)) + { + oberon_error(ctx, "dst must be array of char"); + } + + oberon_generate_copy(ctx, src, dst); +} + +static void +oberon_make_assert_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 > 2) + { + oberon_error(ctx, "too mach arguments"); + } + + oberon_expr_t * cond; + cond = list_args; + oberon_check_src(ctx, cond); + + if(cond -> result -> class != OBERON_TYPE_BOOLEAN) + { + oberon_error(ctx, "expected boolean"); + } + + if(num_args == 1) + { + oberon_generate_assert(ctx, cond); + } + else + { + oberon_expr_t * num; + num = list_args -> next; + oberon_check_src(ctx, num); + + if(num -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "expected integer"); + } + + oberon_check_const(ctx, num); + + oberon_generate_assert_n(ctx, cond, num -> item.integer); + } +} + +static void +oberon_make_halt_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 * num; + num = list_args; + oberon_check_src(ctx, num); + + if(num -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "expected integer"); + } + + oberon_check_const(ctx, num); + + oberon_generate_halt(ctx, num -> item.integer); +} + +static void +oberon_new_const(oberon_context_t * ctx, char * name, oberon_expr_t * expr) +{ + oberon_object_t * constant; + constant = oberon_define_object(ctx -> decl, name, OBERON_CLASS_CONST, true, false, false); + oberon_check_const(ctx, expr); + constant -> value = (oberon_item_t *) expr; +} + oberon_context_t * oberon_create_context(ModuleImportCallback import_module) { @@ -4053,6 +4275,10 @@ oberon_create_context(ModuleImportCallback import_module) register_default_types(ctx); + /* Constants */ + oberon_new_const(ctx, "TRUE", oberon_make_boolean(ctx, true)); + oberon_new_const(ctx, "FALSE", oberon_make_boolean(ctx, false)); + /* Functions */ oberon_new_intrinsic(ctx, "ABS", oberon_make_abs_call, NULL); oberon_new_intrinsic(ctx, "MIN", oberon_make_min_call, NULL); @@ -4061,6 +4287,9 @@ oberon_create_context(ModuleImportCallback import_module) /* Procedures */ oberon_new_intrinsic(ctx, "NEW", NULL, oberon_make_new_call); + oberon_new_intrinsic(ctx, "COPY", NULL, oberon_make_copy_call); + oberon_new_intrinsic(ctx, "ASSERT", NULL, oberon_make_assert_call); + oberon_new_intrinsic(ctx, "HALT", NULL, oberon_make_halt_call); return ctx; }