X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=oberon.c;h=16043c2f7aa0e4bdcd658130a5765b126b385b11;hb=e763da864f7330c2b53029782c6b0d85543eb4d2;hp=5b4c4ea84efada1e388a0c775f4d363e16df49d8;hpb=3818049ca3679e8fcc432345d41a2d930f7874e4;p=dsw-obn.git diff --git a/oberon.c b/oberon.c index 5b4c4ea..16043c2 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 // ======================================================================= @@ -155,42 +166,13 @@ 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 -> module = scope -> ctx -> mod; x -> next = newvar; return newvar; } -/* -static void -oberon_define_field(oberon_context_t * ctx, oberon_type_t * rec, char * name, oberon_type_t * type) -{ - // TODO check base fields - - oberon_object_t * x = rec -> decl; - while(x -> next && strcmp(x -> next -> name, name) != 0) - { - x = x -> next; - } - - if(x -> next) - { - oberon_error(ctx, "multiple definition"); - } - - oberon_object_t * field = malloc(sizeof *field); - memset(field, 0, sizeof *field); - field -> name = name; - field -> class = OBERON_CLASS_FIELD; - field -> type = type; - field -> local = 1; - field -> parent = NULL; - - rec -> num_decl += 1; - x -> next = field; -} -*/ - static oberon_object_t * oberon_find_object_in_list(oberon_object_t * list, char * name) { @@ -257,8 +239,11 @@ oberon_define_type(oberon_scope_t * scope, char * name, oberon_type_t * type, in static void oberon_get_char(oberon_context_t * ctx) { - ctx -> code_index += 1; - ctx -> c = ctx -> code[ctx -> code_index]; + if(ctx -> code[ctx -> code_index]) + { + ctx -> code_index += 1; + ctx -> c = ctx -> code[ctx -> code_index]; + } } static void @@ -375,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 @@ -408,6 +484,43 @@ oberon_skip_space(oberon_context_t * ctx) } } +static void +oberon_read_comment(oberon_context_t * ctx) +{ + int nesting = 1; + while(nesting >= 1) + { + if(ctx -> c == '(') + { + oberon_get_char(ctx); + if(ctx -> c == '*') + { + oberon_get_char(ctx); + nesting += 1; + } + } + else if(ctx -> c == '*') + { + oberon_get_char(ctx); + if(ctx -> c == ')') + { + oberon_get_char(ctx); + nesting -= 1; + } + } + else if(ctx -> c == 0) + { + oberon_error(ctx, "unterminated comment"); + } + else + { + oberon_get_char(ctx); + } + } +} + +static void oberon_read_token(oberon_context_t * ctx); + static void oberon_read_symbol(oberon_context_t * ctx) { @@ -437,6 +550,12 @@ oberon_read_symbol(oberon_context_t * ctx) case '(': ctx -> token = LPAREN; oberon_get_char(ctx); + if(ctx -> c == '*') + { + oberon_get_char(ctx); + oberon_read_comment(ctx); + oberon_read_token(ctx); + } break; case ')': ctx -> token = RPAREN; @@ -479,6 +598,11 @@ oberon_read_symbol(oberon_context_t * ctx) case '*': ctx -> token = STAR; oberon_get_char(ctx); + if(ctx -> c == ')') + { + oberon_get_char(ctx); + oberon_error(ctx, "unstarted comment"); + } break; case '/': ctx -> token = SLASH; @@ -509,7 +633,7 @@ oberon_read_symbol(oberon_context_t * ctx) oberon_get_char(ctx); break; default: - oberon_error(ctx, "invalid char"); + oberon_error(ctx, "invalid char %c", ctx -> c); break; } } @@ -526,7 +650,7 @@ oberon_read_token(oberon_context_t * ctx) } else if(isdigit(c)) { - oberon_read_integer(ctx); + oberon_read_number(ctx); } else { @@ -554,6 +678,7 @@ oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon operator -> is_item = 0; operator -> result = result; + operator -> read_only = 1; operator -> op = op; operator -> left = left; operator -> right = right; @@ -562,7 +687,7 @@ oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon } static oberon_expr_t * -oberon_new_item(int mode, oberon_type_t * result) +oberon_new_item(int mode, oberon_type_t * result, int read_only) { oberon_item_t * item; item = malloc(sizeof *item); @@ -570,6 +695,7 @@ oberon_new_item(int mode, oberon_type_t * result) item -> is_item = 1; item -> result = result; + item -> read_only = read_only; item -> mode = mode; return (oberon_expr_t *)item; @@ -641,7 +767,13 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * { if(pref -> class != expr -> result -> class) { - oberon_error(ctx, "incompatible types"); + if(pref -> class != OBERON_TYPE_PROCEDURE) + { + if(expr -> result -> class != OBERON_TYPE_POINTER) + { + oberon_error(ctx, "incompatible types"); + } + } } if(pref -> class == OBERON_TYPE_INTEGER) @@ -712,21 +844,26 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig) { if(param -> class == OBERON_CLASS_VAR_PARAM) { - if(arg -> is_item) + if(arg -> read_only) { - 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_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); arg = arg -> next; @@ -776,7 +913,7 @@ oberon_make_call_func(oberon_context_t * ctx, oberon_object_t * proc, int num_ar oberon_error(ctx, "attempt to call procedure in expression"); } - call = oberon_new_item(MODE_CALL, proc -> type -> base); + call = oberon_new_item(MODE_CALL, proc -> type -> base, 1); call -> item.var = proc; call -> item.num_args = num_args; call -> item.args = list_args; @@ -827,7 +964,7 @@ oberon_make_call_proc(oberon_context_t * ctx, oberon_object_t * proc, int num_ar } oberon_expr_t * call; - call = oberon_new_item(MODE_CALL, proc -> type -> base); + call = oberon_new_item(MODE_CALL, proc -> type -> base, 1); call -> item.var = proc; call -> item.num_args = num_args; call -> item.args = list_args; @@ -857,7 +994,7 @@ oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr) assert(expr -> is_item); oberon_expr_t * selector; - selector = oberon_new_item(MODE_DEREF, expr -> result -> base); + selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only); selector -> item.parent = (oberon_item_t *) expr; return selector; @@ -887,21 +1024,24 @@ oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, oberon } // Статическая проверка границ массива - if(index -> is_item) + if(desig -> result -> size != 0) { - if(index -> item.mode == MODE_INTEGER) + if(index -> is_item) { - int arr_size = desig -> result -> size; - int index_int = index -> item.integer; - if(index_int < 0 || index_int > arr_size - 1) + if(index -> item.mode == MODE_INTEGER) { - oberon_error(ctx, "not in range (dimension size 0..%i)", arr_size - 1); + int arr_size = desig -> result -> size; + int index_int = index -> item.integer; + if(index_int < 0 || index_int > arr_size - 1) + { + oberon_error(ctx, "not in range (dimension size 0..%i)", arr_size - 1); + } } } } oberon_expr_t * selector; - selector = oberon_new_item(MODE_INDEX, base); + selector = oberon_new_item(MODE_INDEX, base, desig -> read_only); selector -> item.parent = (oberon_item_t *) desig; selector -> item.num_args = 1; selector -> item.args = index; @@ -929,8 +1069,25 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char * oberon_object_t * field; field = oberon_find_field(ctx, rec, name); + if(field -> export == 0) + { + if(field -> module != ctx -> mod) + { + oberon_error(ctx, "field not exported"); + } + } + + int read_only = 0; + if(field -> read_only) + { + if(field -> module != ctx -> mod) + { + read_only = 1; + } + } + oberon_expr_t * selector; - selector = oberon_new_item(MODE_FIELD, field -> type); + selector = oberon_new_item(MODE_FIELD, field -> type, read_only); selector -> item.var = field; selector -> item.parent = (oberon_item_t *) expr; @@ -984,6 +1141,15 @@ oberon_designator(oberon_context_t * ctx) var = oberon_qualident(ctx, NULL, 1); + int read_only = 0; + if(var -> read_only) + { + if(var -> module != ctx -> mod) + { + read_only = 1; + } + } + switch(var -> class) { case OBERON_CLASS_CONST: @@ -993,8 +1159,10 @@ oberon_designator(oberon_context_t * ctx) case OBERON_CLASS_VAR: case OBERON_CLASS_VAR_PARAM: case OBERON_CLASS_PARAM: + expr = oberon_new_item(MODE_VAR, var -> type, read_only); + break; case OBERON_CLASS_PROC: - expr = oberon_new_item(MODE_VAR, var -> type); + expr = oberon_new_item(MODE_VAR, var -> type, 1); break; default: oberon_error(ctx, "invalid designator"); @@ -1098,17 +1266,22 @@ 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); + expr = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1); 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); + expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1); expr -> item.boolean = 1; oberon_assert_token(ctx, TRUE); break; case FALSE: - expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type); + expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1); expr -> item.boolean = 0; oberon_assert_token(ctx, FALSE); break; @@ -1124,7 +1297,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); + expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type, 1); break; default: oberon_error(ctx, "invalid expression"); @@ -1241,6 +1414,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); @@ -1257,14 +1470,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); @@ -1829,6 +2034,14 @@ oberon_make_multiarray(oberon_context_t * ctx, oberon_expr_t * sizes, oberon_typ oberon_make_array_type(ctx, sizes, dim, type); } +static void +oberon_make_open_array(oberon_context_t * ctx, oberon_type_t * base, oberon_type_t * type) +{ + type -> class = OBERON_TYPE_ARRAY; + type -> size = 0; + type -> base = base; +} + static void oberon_type(oberon_context_t * ctx, oberon_type_t ** type) { @@ -1842,7 +2055,11 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type) int num_sizes = 0; oberon_expr_t * sizes; - oberon_expr_list(ctx, &num_sizes, &sizes, 1); + + if(ISEXPR(ctx -> token)) + { + oberon_expr_list(ctx, &num_sizes, &sizes, 1); + } oberon_assert_token(ctx, OF); @@ -1850,7 +2067,14 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type) base = oberon_new_type_ptr(OBERON_TYPE_VOID); oberon_type(ctx, &base); - oberon_make_multiarray(ctx, sizes, base, type); + if(num_sizes == 0) + { + oberon_make_open_array(ctx, base, *type); + } + else + { + oberon_make_multiarray(ctx, sizes, base, type); + } } else if(ctx -> token == RECORD) { @@ -2158,6 +2382,17 @@ oberon_initialize_type(oberon_context_t * ctx, oberon_type_t * type) } else if(type -> class == OBERON_TYPE_ARRAY) { + if(type -> size != 0) + { + if(type -> base -> class == OBERON_TYPE_ARRAY) + { + if(type -> base -> size == 0) + { + oberon_error(ctx, "open array not allowed as array element"); + } + } + } + oberon_initialize_type(ctx, type -> base); oberon_generator_init_type(ctx, type); } @@ -2200,9 +2435,19 @@ oberon_initialize_object(oberon_context_t * ctx, oberon_object_t * x) oberon_initialize_type(ctx, x -> type); break; case OBERON_CLASS_VAR: + case OBERON_CLASS_FIELD: + if(x -> type -> class == OBERON_TYPE_ARRAY) + { + if(x -> type -> size == 0) + { + oberon_error(ctx, "open array not allowed as variable or field"); + } + } + oberon_initialize_type(ctx, x -> type); + oberon_generator_init_var(ctx, x); + break; case OBERON_CLASS_PARAM: case OBERON_CLASS_VAR_PARAM: - case OBERON_CLASS_FIELD: oberon_initialize_type(ctx, x -> type); oberon_generator_init_var(ctx, x); break; @@ -2294,6 +2539,11 @@ oberon_decl_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) + { + oberon_error(ctx, "read-only destination"); + } + oberon_autocast_to(ctx, src, dst -> result); oberon_generate_assign(ctx, src, dst); } @@ -2420,17 +2670,11 @@ oberon_parse_module(oberon_context_t * ctx) oberon_assert_token(ctx, SEMICOLON); ctx -> mod -> name = name1; - oberon_object_t * this_module; - this_module = oberon_define_object(ctx -> decl, name1, OBERON_CLASS_MODULE, 0, 0); - this_module -> module = ctx -> mod; - if(ctx -> token == IMPORT) { oberon_import_list(ctx); } - ctx -> decl -> parent = this_module; - oberon_decl_seq(ctx); oberon_generate_begin_module(ctx); @@ -2468,8 +2712,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 @@ -2513,6 +2760,87 @@ oberon_make_abs_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ return expr; } +static void +oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args) +{ + if(num_args < 1) + { + oberon_error(ctx, "too few arguments"); + } + + oberon_expr_t * dst; + dst = list_args; + + oberon_type_t * type; + type = dst -> result; + + if(type -> class != OBERON_TYPE_POINTER) + { + oberon_error(ctx, "not a pointer"); + } + + type = type -> base; + + oberon_expr_t * src; + src = oberon_new_item(MODE_NEW, dst -> result, 0); + src -> item.num_args = 0; + src -> item.args = NULL; + + int max_args = 1; + if(type -> class == OBERON_TYPE_ARRAY) + { + if(type -> size == 0) + { + oberon_type_t * x = type; + while(x -> class == OBERON_TYPE_ARRAY) + { + if(x -> size == 0) + { + max_args += 1; + } + x = x -> base; + } + } + + if(num_args < max_args) + { + oberon_error(ctx, "too few arguments"); + } + + if(num_args > max_args) + { + oberon_error(ctx, "too mach arguments"); + } + + int num_sizes = max_args - 1; + oberon_expr_t * size_list = list_args -> next; + + oberon_expr_t * arg = size_list; + for(int i = 0; i < max_args - 1; i++) + { + if(arg -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "size must be integer"); + } + arg = arg -> next; + } + + src -> item.num_args = num_sizes; + src -> item.args = size_list; + } + else if(type -> class != OBERON_TYPE_RECORD) + { + oberon_error(ctx, "oberon_make_new_call: wat"); + } + + if(num_args > max_args) + { + oberon_error(ctx, "too mach arguments"); + } + + oberon_assign(ctx, src, dst); +} + oberon_context_t * oberon_create_context(ModuleImportCallback import_module) { @@ -2528,6 +2856,7 @@ oberon_create_context(ModuleImportCallback import_module) register_default_types(ctx); oberon_new_intrinsic(ctx, "ABS", oberon_make_abs_call, NULL); + oberon_new_intrinsic(ctx, "NEW", NULL, oberon_make_new_call); return ctx; }