X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=blobdiff_plain;f=src%2Foberon.c;h=5a93489b35ed197ee2ac10b262a95c042583d146;hp=e88ff79159e28e93c010a73ebde045ee8a6c9132;hb=a0ff807fe0e69c50469e506836467da32f23f754;hpb=72048038b5be32cc940c8452541b8bb3e75958a9 diff --git a/src/oberon.c b/src/oberon.c index e88ff79..5a93489 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -24,8 +24,6 @@ enum { BEGIN, ASSIGN, INTEGER, - TRUE, - FALSE, LPAREN, RPAREN, EQUAL, @@ -52,8 +50,8 @@ enum { TYPE, ARRAY, OF, - LBRACE, - RBRACE, + LBRACK, + RBRACK, RECORD, POINTER, TO, @@ -74,7 +72,13 @@ enum { FOR, BY, LOOP, - EXIT + EXIT, + LBRACE, + RBRACE, + DOTDOT, + CASE, + BAR, + WITH }; // ======================================================================= @@ -149,6 +153,15 @@ oberon_new_type_string(int size) return x; } +static oberon_type_t * +oberon_new_type_set(int size) +{ + oberon_type_t * x; + x = oberon_new_type_ptr(OBERON_TYPE_SET); + x -> size = size; + return x; +} + // ======================================================================= // TABLE // ======================================================================= @@ -329,14 +342,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; @@ -449,8 +454,19 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = EXIT; } + else if(strcmp(ident, "CASE") == 0) + { + ctx -> token = CASE; + } + else if(strcmp(ident, "WITH") == 0) + { + ctx -> token = WITH; + } } +#define ISHEXDIGIT(x) \ + (((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F')) + static void oberon_read_number(oberon_context_t * ctx) { @@ -478,10 +494,10 @@ oberon_read_number(oberon_context_t * ctx) end_i = ctx -> code_index; - if(isxdigit(ctx -> c)) + if(ISHEXDIGIT(ctx -> c)) { mode = 1; - while(isxdigit(ctx -> c)) + while(ISHEXDIGIT(ctx -> c)) { oberon_get_char(ctx); } @@ -505,37 +521,43 @@ oberon_read_number(oberon_context_t * ctx) } else if(ctx -> c == '.') { - mode = 2; oberon_get_char(ctx); - - while(isdigit(ctx -> c)) + if(ctx -> c == '.') { - oberon_get_char(ctx); + /* Чит: избегаем конфликта с DOTDOT */ + ctx -> code_index -= 1; } - - if(ctx -> c == 'E' || ctx -> c == 'D') + else { - exp_i = ctx -> code_index; - - if(ctx -> c == 'D') - { - mode = 3; - } + mode = 2; - oberon_get_char(ctx); - - if(ctx -> c == '+' || ctx -> c == '-') + while(isdigit(ctx -> c)) { oberon_get_char(ctx); } - while(isdigit(ctx -> c)) + 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; } @@ -668,8 +690,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); @@ -699,6 +719,11 @@ oberon_read_symbol(oberon_context_t * ctx) case '.': ctx -> token = DOT; oberon_get_char(ctx); + if(ctx -> c == '.') + { + ctx -> token = DOTDOT; + oberon_get_char(ctx); + } break; case '(': ctx -> token = LPAREN; @@ -774,11 +799,11 @@ oberon_read_symbol(oberon_context_t * ctx) oberon_get_char(ctx); break; case '[': - ctx -> token = LBRACE; + ctx -> token = LBRACK; oberon_get_char(ctx); break; case ']': - ctx -> token = RBRACE; + ctx -> token = RBRACK; oberon_get_char(ctx); break; case '^': @@ -791,6 +816,18 @@ oberon_read_symbol(oberon_context_t * ctx) case '\'': oberon_read_string(ctx); break; + case '{': + ctx -> token = LBRACE; + oberon_get_char(ctx); + break; + case '}': + ctx -> token = RBRACE; + oberon_get_char(ctx); + break; + case '|': + ctx -> token = BAR; + oberon_get_char(ctx); + break; default: oberon_error(ctx, "invalid char %c", ctx -> c); break; @@ -871,12 +908,18 @@ oberon_make_unary_op(oberon_context_t * ctx, int token, oberon_expr_t * a) if(token == MINUS) { - if(result -> class != OBERON_TYPE_INTEGER) + if(result -> class == OBERON_TYPE_SET) + { + expr = oberon_new_operator(OP_COMPLEMENTATION, result, a, NULL); + } + else if(result -> class == OBERON_TYPE_INTEGER) + { + expr = oberon_new_operator(OP_UNARY_MINUS, result, a, NULL); + } + else { oberon_error(ctx, "incompatible operator type"); } - - expr = oberon_new_operator(OP_UNARY_MINUS, result, a, NULL); } else if(token == NOT) { @@ -941,11 +984,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; } @@ -1054,19 +1094,41 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * // Допускается: // Если классы типов равны // Если INTEGER переводится в REAL - // Есди 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_ARRAY) + if(pref -> class == OBERON_TYPE_CHAR) + { + if(expr -> is_item && expr -> item.mode == MODE_STRING) + { + if(strlen(expr -> item.string) != 1) + { + error = true; + } + } + else + { + error = true; + } + } + else if(pref -> class == OBERON_TYPE_ARRAY) { if(pref -> base -> class != OBERON_TYPE_CHAR) { @@ -1096,7 +1158,16 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * oberon_error(ctx, "oberon_autocast_to: incompatible types"); } - if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL) + if(pref -> class == OBERON_TYPE_CHAR) + { + if(expr -> result -> class == OBERON_TYPE_STRING) + { + int c = expr -> item.string[0]; + expr = oberon_new_item(MODE_CHAR, ctx -> char_type, true); + expr -> item.integer = c; + } + } + else if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL) { if(expr -> result -> size > pref -> size) { @@ -1115,17 +1186,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"); } } @@ -1171,13 +1243,21 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_item_t * desig) { if(param -> class == OBERON_CLASS_VAR_PARAM) { + if(arg -> result != param -> type) + { + oberon_error(ctx, "incompatible type"); + } if(arg -> read_only) { oberon_error(ctx, "assign to read-only var"); } + casted[i] = arg; + } + else + { + casted[i] = oberon_autocast_to(ctx, arg, param -> type); } - casted[i] = oberon_autocast_to(ctx, arg, param -> type); arg = arg -> next; param = param -> next; } @@ -1216,7 +1296,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"); } @@ -1253,7 +1333,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"); } @@ -1277,14 +1357,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"); @@ -1394,7 +1471,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char * } #define ISSELECTOR(x) \ - (((x) == LBRACE) \ + (((x) == LBRACK) \ || ((x) == DOT) \ || ((x) == UPARROW) \ || ((x) == LPAREN)) @@ -1453,9 +1530,8 @@ oberon_ident_item(oberon_context_t * ctx, char * name) } static oberon_expr_t * -oberon_designator(oberon_context_t * ctx) +oberon_qualident_expr(oberon_context_t * ctx) { - char * name; oberon_object_t * var; oberon_expr_t * expr; @@ -1491,8 +1567,20 @@ oberon_designator(oberon_context_t * ctx) oberon_error(ctx, "invalid designator"); break; } + expr -> item.var = var; + return expr; +} + +static oberon_expr_t * +oberon_designator(oberon_context_t * ctx) +{ + char * name; + oberon_expr_t * expr; + + expr = oberon_qualident_expr(ctx); + while(expr -> result -> class != OBERON_TYPE_PROCEDURE && ISSELECTOR(ctx -> token)) { switch(ctx -> token) @@ -1502,12 +1590,12 @@ oberon_designator(oberon_context_t * ctx) name = oberon_assert_ident(ctx); expr = oberon_make_record_selector(ctx, expr, name); break; - case LBRACE: - oberon_assert_token(ctx, LBRACE); + case LBRACK: + oberon_assert_token(ctx, LBRACK); int num_indexes = 0; oberon_expr_t * indexes = NULL; oberon_expr_list(ctx, &num_indexes, &indexes, 0); - oberon_assert_token(ctx, RBRACE); + oberon_assert_token(ctx, RBRACK); for(int i = 0; i < num_indexes; i++) { @@ -1619,6 +1707,68 @@ oberon_integer_item(oberon_context_t * ctx, int64_t i) return expr; } +static oberon_expr_t * +oberon_element(oberon_context_t * ctx) +{ + oberon_expr_t * e1; + oberon_expr_t * e2; + + e1 = oberon_expr(ctx); + if(e1 -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "expected integer"); + } + + e2 = NULL; + if(ctx -> token == DOTDOT) + { + oberon_assert_token(ctx, DOTDOT); + e2 = oberon_expr(ctx); + if(e2 -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "expected integer"); + } + } + + oberon_expr_t * set; + set = oberon_new_operator(OP_RANGE, ctx -> set_type, e1, e2); + return set; +} + +static oberon_expr_t * +oberon_set(oberon_context_t * ctx) +{ + oberon_expr_t * set; + oberon_expr_t * elements; + set = oberon_new_item(MODE_SET, ctx -> set_type, true); + set -> item.integer = 0; + + oberon_assert_token(ctx, LBRACE); + if(ISEXPR(ctx -> token)) + { + elements = oberon_element(ctx); + set = oberon_new_operator(OP_UNION, ctx -> set_type, set, elements); + while(ctx -> token == COMMA) + { + oberon_assert_token(ctx, COMMA); + elements = oberon_element(ctx); + set = oberon_new_operator(OP_UNION, ctx -> set_type, set, elements); + } + } + oberon_assert_token(ctx, RBRACE); + + 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) { @@ -1653,15 +1803,8 @@ 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); + case LBRACE: + expr = oberon_set(ctx); break; case LPAREN: oberon_assert_token(ctx, LPAREN); @@ -1675,7 +1818,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"); @@ -1720,7 +1863,23 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ oberon_expr_t * expr; oberon_type_t * result; - if(token == IS) + bool error = false; + if(token == IN) + { + if(a -> result -> class != OBERON_TYPE_INTEGER) + { + oberon_error(ctx, "must be integer"); + } + + if(b -> result -> class != OBERON_TYPE_SET) + { + oberon_error(ctx, "must be set"); + } + + result = ctx -> bool_type; + expr = oberon_new_operator(OP_IN, result, a, b); + } + else if(token == IS) { oberon_type_t * v = a -> result; if(v -> class == OBERON_TYPE_POINTER) @@ -1825,10 +1984,21 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ } else if(token == SLASH) { - 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); + if(a -> result -> class == OBERON_TYPE_SET + || b -> result -> class == OBERON_TYPE_SET) + { + oberon_autocast_binary_op(ctx, &a, &b); + result = a -> result; + expr = oberon_new_operator(OP_SYM_DIFFERENCE, result, a, b); + } + else + { + oberon_autocast_to_real(ctx, &a); + oberon_autocast_to_real(ctx, &b); + oberon_autocast_binary_op(ctx, &a, &b); + result = a -> result; + expr = oberon_new_operator(OP_DIV, result, a, b); + } } else if(token == DIV) { @@ -1844,29 +2014,58 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ else { oberon_autocast_binary_op(ctx, &a, &b); - - if(token == PLUS) + result = a -> result; + if(result -> class == OBERON_TYPE_SET) { - expr = oberon_new_operator(OP_ADD, a -> result, a, b); - } - else if(token == MINUS) - { - expr = oberon_new_operator(OP_SUB, a -> result, a, b); - } - else if(token == STAR) - { - expr = oberon_new_operator(OP_MUL, a -> result, a, b); + switch(token) + { + case PLUS: + expr = oberon_new_operator(OP_UNION, result, a, b); + break; + case MINUS: + expr = oberon_new_operator(OP_DIFFERENCE, result, a, b); + break; + case STAR: + expr = oberon_new_operator(OP_INTERSECTION, result, a, b); + break; + default: + error = true; + break; + } } - else if(token == MOD) + else if(result -> class == OBERON_TYPE_INTEGER + || result -> class == OBERON_TYPE_REAL) { - expr = oberon_new_operator(OP_MOD, a -> result, a, b); + switch(token) + { + case PLUS: + expr = oberon_new_operator(OP_ADD, result, a, b); + break; + case MINUS: + expr = oberon_new_operator(OP_SUB, result, a, b); + break; + case STAR: + expr = oberon_new_operator(OP_MUL, result, a, b); + break; + case MOD: + expr = oberon_new_operator(OP_MOD, result, a, b); + break; + default: + error = true; + break; + } } else { - oberon_error(ctx, "oberon_make_bin_op: bin wat"); + error = true; } } + if(error) + { + oberon_error(ctx, "invalid operation"); + } + return expr; } @@ -1951,12 +2150,9 @@ oberon_expr(oberon_context_t * ctx) return expr; } -static oberon_item_t * -oberon_const_expr(oberon_context_t * ctx) +static void +oberon_check_const(oberon_context_t * ctx, oberon_expr_t * expr) { - oberon_expr_t * expr; - expr = oberon_expr(ctx); - if(expr -> is_item == 0) { oberon_error(ctx, "const expression are required"); @@ -1977,7 +2173,14 @@ oberon_const_expr(oberon_context_t * ctx) oberon_error(ctx, "const expression are required"); break; } +} +static oberon_item_t * +oberon_const_expr(oberon_context_t * ctx) +{ + oberon_expr_t * expr; + expr = oberon_expr(ctx); + oberon_check_const(ctx, expr); return (oberon_item_t *) expr; } @@ -2070,7 +2273,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); @@ -2101,7 +2304,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; @@ -2156,7 +2359,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) @@ -2199,7 +2402,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) { @@ -2245,7 +2448,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); @@ -2283,16 +2486,23 @@ 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); + //oberon_initialize_decl(ctx); oberon_generator_init_type(ctx, signature); oberon_close_scope(ctx -> decl); oberon_object_t * proc; proc = oberon_find_object(ctx -> decl, name, 0); - if(proc != NULL) + if(proc == NULL) + { + proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, export, read_only, false); + proc -> type = signature; + proc -> scope = proc_scope; + oberon_generator_init_proc(ctx, proc); + } + else { if(proc -> class != OBERON_CLASS_PROC) { @@ -2314,16 +2524,15 @@ oberon_proc_decl(oberon_context_t * ctx) oberon_compare_signatures(ctx, proc -> type, signature); } - else + + proc_scope -> parent = proc; + oberon_object_t * param = proc_scope -> list -> next; + while(param) { - proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, export, read_only, false); - proc -> type = signature; - proc -> scope = proc_scope; - oberon_generator_init_proc(ctx, proc); + param -> parent = proc; + param = param -> next; } - proc -> scope -> parent = proc; - if(forward == 0) { proc -> linked = 1; @@ -2384,7 +2593,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; @@ -2406,7 +2615,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); @@ -2429,7 +2638,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); @@ -2530,7 +2739,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) @@ -2561,7 +2770,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; @@ -2598,7 +2807,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 @@ -2622,7 +2831,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"); } @@ -2676,6 +2885,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++) @@ -2817,7 +3031,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"); } @@ -3022,6 +3236,167 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) oberon_generate_assign(ctx, src, dst); } +static oberon_expr_t * +oberon_case_labels(oberon_context_t * ctx, oberon_expr_t * val) +{ + oberon_expr_t * e1; + oberon_expr_t * e2; + oberon_expr_t * cond; + oberon_expr_t * cond2; + + e1 = (oberon_expr_t *) oberon_const_expr(ctx); + oberon_autocast_to(ctx, e1, val -> result); + + e2 = NULL; + if(ctx -> token == DOTDOT) + { + oberon_assert_token(ctx, DOTDOT); + e2 = (oberon_expr_t *) oberon_const_expr(ctx); + oberon_autocast_to(ctx, e2, val -> result); + } + + if(e2 == NULL) + { + /* val == e1 */ + cond = oberon_make_bin_op(ctx, EQUAL, val, e1); + } + else + { + /* val >= e1 && val <= e2 */ + cond = oberon_make_bin_op(ctx, GEQ, val, e1); + cond2 = oberon_make_bin_op(ctx, LEQ, val, e2); + cond = oberon_make_bin_op(ctx, AND, cond, cond2); + } + + return cond; +} + +static void +oberon_case(oberon_context_t * ctx, oberon_expr_t * val, gen_label_t * end) +{ + oberon_expr_t * cond; + oberon_expr_t * cond2; + gen_label_t * this_end; + + if(ISEXPR(ctx -> token)) + { + this_end = oberon_generator_reserve_label(ctx); + + cond = oberon_case_labels(ctx, val); + while(ctx -> token == COMMA) + { + oberon_assert_token(ctx, COMMA); + /* cond || cond2 */ + cond2 = oberon_case_labels(ctx, val); + cond = oberon_make_bin_op(ctx, OR, cond, cond2); + } + oberon_assert_token(ctx, COLON); + + oberon_generate_branch(ctx, cond, false, this_end); + oberon_statement_seq(ctx); + oberon_generate_goto(ctx, end); + + oberon_generate_label(ctx, this_end); + } +} + +static void +oberon_case_statement(oberon_context_t * ctx) +{ + oberon_expr_t * val; + oberon_expr_t * expr; + gen_label_t * end; + + end = oberon_generator_reserve_label(ctx); + + oberon_assert_token(ctx, CASE); + expr = oberon_expr(ctx); + val = oberon_make_temp_var_item(ctx, expr -> result); + oberon_assign(ctx, expr, val); + oberon_assert_token(ctx, OF); + oberon_case(ctx, val, end); + while(ctx -> token == BAR) + { + oberon_assert_token(ctx, BAR); + oberon_case(ctx, val, end); + } + + if(ctx -> token == ELSE) + { + oberon_assert_token(ctx, ELSE); + oberon_statement_seq(ctx); + } + + oberon_generate_label(ctx, end); + oberon_assert_token(ctx, END); +} + +static void +oberon_with_guard_do(oberon_context_t * ctx, gen_label_t * end) +{ + oberon_expr_t * val; + oberon_expr_t * var; + oberon_expr_t * type; + oberon_expr_t * cond; + oberon_expr_t * cast; + oberon_type_t * old_type; + gen_var_t * old_var; + gen_label_t * this_end; + + this_end = oberon_generator_reserve_label(ctx); + + var = oberon_qualident_expr(ctx); + oberon_assert_token(ctx, COLON); + type = oberon_qualident_expr(ctx); + cond = oberon_make_bin_op(ctx, IS, var, type); + + oberon_assert_token(ctx, DO); + oberon_generate_branch(ctx, cond, false, this_end); + + /* Сохраняем ссылку во временной переменной */ + val = oberon_make_temp_var_item(ctx, type -> result); + cast = oberno_make_record_cast(ctx, var, type -> result); + oberon_assign(ctx, cast, val); + /* Подменяем тип у оригинальной переменной */ + old_type = var -> item.var -> type; + var -> item.var -> type = type -> result; + /* Подменяем ссылку на переменную */ + old_var = var -> item.var -> gen_var; + var -> item.var -> gen_var = val -> item.var -> gen_var; + + oberon_statement_seq(ctx); + oberon_generate_goto(ctx, end); + oberon_generate_label(ctx, this_end); + + /* Возвращаем исходное состояние */ + var -> item.var -> gen_var = old_var; + var -> item.var -> type = old_type; +} + +static void +oberon_with_statement(oberon_context_t * ctx) +{ + gen_label_t * end; + end = oberon_generator_reserve_label(ctx); + + oberon_assert_token(ctx, WITH); + oberon_with_guard_do(ctx, end); + while(ctx -> token == BAR) + { + oberon_assert_token(ctx, BAR); + oberon_with_guard_do(ctx, end); + } + + if(ctx -> token == ELSE) + { + oberon_assert_token(ctx, ELSE); + oberon_statement_seq(ctx); + } + + oberon_generate_label(ctx, end); + oberon_assert_token(ctx, END); +} + static void oberon_statement(oberon_context_t * ctx) { @@ -3228,6 +3603,14 @@ oberon_statement(oberon_context_t * ctx) } oberon_generate_goto(ctx, ctx -> decl -> exit_label); } + else if(ctx -> token == CASE) + { + oberon_case_statement(ctx); + } + else if(ctx -> token == WITH) + { + oberon_with_statement(ctx); + } else if(ctx -> token == RETURN) { oberon_assert_token(ctx, RETURN); @@ -3349,7 +3732,7 @@ oberon_parse_module(oberon_context_t * ctx) oberon_assert_token(ctx, END); name2 = oberon_assert_ident(ctx); - oberon_assert_token(ctx, DOT); + oberon_expect_token(ctx, DOT); if(strcmp(name1, name2) != 0) { @@ -3366,12 +3749,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); @@ -3379,17 +3761,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); @@ -3397,8 +3782,8 @@ 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); } static void @@ -3440,6 +3825,9 @@ oberon_make_min_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ case OBERON_TYPE_INTEGER: expr = oberon_integer_item(ctx, -powl(2, bits - 1)); break; + case OBERON_TYPE_SET: + expr = oberon_integer_item(ctx, 0); + break; default: oberon_error(ctx, "allowed only basic types"); break; @@ -3476,6 +3864,9 @@ oberon_make_max_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ case OBERON_TYPE_INTEGER: expr = oberon_integer_item(ctx, powl(2, bits - 1) - 1); break; + case OBERON_TYPE_SET: + expr = oberon_integer_item(ctx, bits); + break; default: oberon_error(ctx, "allowed only basic types"); break; @@ -3513,6 +3904,8 @@ oberon_make_size_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list case OBERON_TYPE_INTEGER: case OBERON_TYPE_BOOLEAN: case OBERON_TYPE_REAL: + case OBERON_TYPE_CHAR: + case OBERON_TYPE_SET: size = type -> size; break; default: @@ -3638,6 +4031,15 @@ oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_ oberon_assign(ctx, src, dst); } +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) { @@ -3653,6 +4055,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);