X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=blobdiff_plain;f=src%2Foberon.c;h=3b4a3747b904d0dbef91c4bb3f2ee11960e19679;hp=38e24a8da8b963669a406220cef798290e3b43ef;hb=2c43a7d73a91f64b1318306fa259a9337951a3a3;hpb=b7a2685d39da39f69ee4530dda2ec5977159dc0c diff --git a/src/oberon.c b/src/oberon.c index 38e24a8..3b4a374 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -77,7 +77,9 @@ enum { EXIT, LBRACE, RBRACE, - DOTDOT + DOTDOT, + CASE, + BAR }; // ======================================================================= @@ -461,6 +463,10 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = EXIT; } + else if(strcmp(ident, "CASE") == 0) + { + ctx -> token = CASE; + } } static void @@ -822,6 +828,10 @@ oberon_read_symbol(oberon_context_t * ctx) 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; @@ -3171,6 +3181,101 @@ 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_statement(oberon_context_t * ctx) { @@ -3377,6 +3482,10 @@ 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 == RETURN) { oberon_assert_token(ctx, RETURN);