X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=blobdiff_plain;f=src%2Foberon.c;h=e4b9157d151cafa6075c86bbc1a07ebf2e845bef;hp=3b4a3747b904d0dbef91c4bb3f2ee11960e19679;hb=3edc4e955c943735543e2c94ecd28f94d75b32fb;hpb=2c43a7d73a91f64b1318306fa259a9337951a3a3 diff --git a/src/oberon.c b/src/oberon.c index 3b4a374..e4b9157 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -79,7 +79,8 @@ enum { RBRACE, DOTDOT, CASE, - BAR + BAR, + WITH }; // ======================================================================= @@ -467,6 +468,10 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = CASE; } + else if(strcmp(ident, "WITH") == 0) + { + ctx -> token = WITH; + } } static void @@ -1500,9 +1505,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; @@ -1538,8 +1542,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) @@ -3276,6 +3292,72 @@ oberon_case_statement(oberon_context_t * ctx) 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) { @@ -3486,6 +3568,10 @@ oberon_statement(oberon_context_t * ctx) { oberon_case_statement(ctx); } + else if(ctx -> token == WITH) + { + oberon_with_statement(ctx); + } else if(ctx -> token == RETURN) { oberon_assert_token(ctx, RETURN);