From 2c43a7d73a91f64b1318306fa259a9337951a3a3 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Fri, 4 Aug 2017 22:22:19 +0300 Subject: [PATCH] =?utf8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?utf8?q?=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86?= =?utf8?q?=D0=B8=D1=8F=20CASE?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- jvm_test.sh | 2 +- notes | 1 - src/backends/jvm/generator-jvm.c | 4 +- src/oberon.c | 111 ++++++++++++++++++++++++++++++- src/test.c | 11 ++- 5 files changed, 121 insertions(+), 8 deletions(-) diff --git a/jvm_test.sh b/jvm_test.sh index 0ec37e7..6519656 100755 --- a/jvm_test.sh +++ b/jvm_test.sh @@ -16,7 +16,7 @@ jasmin -d classes *.j javac -d classes rtl/*.java # -a -- for asm as comments -#jad -o -b -noinner classes/* +jad -o -b -noinner classes/* proguard -injars classes \ -libraryjars /usr/lib/jvm/java-8-openjdk/jre/lib/rt.jar \ diff --git a/notes b/notes index 705055e..2c9c569 100644 --- a/notes +++ b/notes @@ -1,4 +1,3 @@ -- Нет конструкции CASE - Нет конструкции WITH - Нет модуля SYSTEM diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index 03b29f8..a107efc 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -1690,7 +1690,7 @@ jvm_generate_logical_or(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) /* a OR b -- если a, то TRUE, иначе b */ push_expr(p, a); - jvm_generate(p, 1, 0, "ifne %s", label_name_calc_b); + jvm_generate(p, 1, 0, "ifeq %s", label_name_calc_b); jvm_generate(p, 0, 1, "iconst_1"); jvm_generate(p, 0, 0, "goto %s", label_name_done); jvm_generate_label(p, label_calc_b); @@ -1709,7 +1709,7 @@ jvm_generate_logical_and(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) /* a AND b -- если a, то b, иначе FALSE */ push_expr(p, a); - jvm_generate(p, 1, 0, "ifne %s", label_name_false); + jvm_generate(p, 1, 0, "ifeq %s", label_name_false); push_expr(p, b); jvm_generate(p, 0, 0, "goto %s", label_name_done); jvm_generate_label(p, label_false); 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); diff --git a/src/test.c b/src/test.c index 25497b0..0eb787c 100644 --- a/src/test.c +++ b/src/test.c @@ -9,13 +9,18 @@ static char source_test[] = "MODULE Test;" "IMPORT Out;" "" + "VAR" + " i : INTEGER;" + "" "BEGIN" " Out.Open;" - " IF 8 IN { 2, 3, 7..10 } THEN" - " Out.String('Yes'); Out.Ln;" + " CASE 666 OF" + " 2, 3, 4, 5: Out.String('Zero');" + " | 10..20, 24: Out.String('Holy shit');" " ELSE" - " Out.String('No'); Out.Ln;" + " Out.String('Something else');" " END;" + " Out.Ln;" "END Test." ; -- 2.29.2