From: DeaDDooMER Date: Wed, 2 Aug 2017 18:29:29 +0000 (+0300) Subject: Добавлена конструкция IF-THEN-ELSE-END X-Git-Url: http://deadsoftware.ru/gitweb?p=dsw-obn.git;a=commitdiff_plain;h=51a1ab2543ec5c221d4a3a9ab89968ae7dd39981 Добавлена конструкция IF-THEN-ELSE-END --- diff --git a/src/backends/jvm/generator-jvm-basic.c b/src/backends/jvm/generator-jvm-basic.c index 88de2e2..44046a1 100644 --- a/src/backends/jvm/generator-jvm-basic.c +++ b/src/backends/jvm/generator-jvm-basic.c @@ -365,6 +365,10 @@ jvm_cell_size_for_type(oberon_type_t * type) return 2; } } + else if(type -> class == OBERON_TYPE_VOID) + { + return 0; + } return 1; } diff --git a/src/backends/jvm/generator-jvm.c b/src/backends/jvm/generator-jvm.c index f111fd1..b17711b 100644 --- a/src/backends/jvm/generator-jvm.c +++ b/src/backends/jvm/generator-jvm.c @@ -1247,6 +1247,70 @@ oberon_generate_end_proc(oberon_context_t * ctx) jvm_generate_function_end(p); } +gen_label_t * +oberon_generator_reserve_label(oberon_context_t * ctx) +{ + gen_module_t * m; + gen_proc_t * p; + gen_label_t * l; + + m = ctx -> mod -> gen_mod; + p = m -> class -> p; + + l = GC_MALLOC(sizeof *l); + memset(l, 0, sizeof *l); + + l -> id = jvm_new_label_id(p); + return l; +} + +void +oberon_generate_label(oberon_context_t * ctx, gen_label_t * l) +{ + gen_module_t * m; + gen_proc_t * p; + + m = ctx -> mod -> gen_mod; + p = m -> class -> p; + + jvm_generate_label(p, l -> id); +} + +void +oberon_generate_goto(oberon_context_t * ctx, gen_label_t * l) +{ + gen_module_t * m; + gen_proc_t * p; + + m = ctx -> mod -> gen_mod; + p = m -> class -> p; + + jvm_generate(p, 0, 0, "goto L%i", l -> id); +} + +void +oberon_generate_branch(oberon_context_t * ctx, oberon_expr_t * cond, bool gotoif, gen_label_t * l) +{ + gen_module_t * m; + gen_proc_t * p; + + m = ctx -> mod -> gen_mod; + p = m -> class -> p; + + push_expr(p, cond); + + if(gotoif == false) + { + /* переход если false */ + jvm_generate(p, 1, 0, "ifeq L%i", l -> id); + } + else + { + /* переход если true */ + jvm_generate(p, 1, 0, "ifne L%i", l -> id); + } +} + static void jvm_generate_call_proc(gen_proc_t * p, oberon_item_t * desig) { @@ -1458,7 +1522,7 @@ jvm_generate_abs(gen_proc_t * p, char prefix) } static void -jvm_generate_compare_op(gen_proc_t * p, char prefix, int op) +jvm_generate_compare_op(gen_proc_t * p, oberon_type_t * t, char prefix, int op) { int label_true = jvm_new_label_id(p); int label_done = jvm_new_label_id(p); @@ -1503,7 +1567,7 @@ jvm_generate_compare_op(gen_proc_t * p, char prefix, int op) } static void -jvm_generate_operator(gen_proc_t * p, char prefix, int op) +jvm_generate_operator(gen_proc_t * p, oberon_type_t * t, char prefix, int op) { int cell_size = jvm_cell_size_for_postfix(prefix); switch(op) @@ -1553,7 +1617,7 @@ jvm_generate_operator(gen_proc_t * p, char prefix, int op) case OP_LEQ: case OP_GRT: case OP_GEQ: - jvm_generate_compare_op(p, prefix, op); + jvm_generate_compare_op(p, t, prefix, op); break; default: gen_error("jvm_generate_operator: unk op %i", op); @@ -1602,6 +1666,7 @@ jvm_generate_logical_and(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b) static void push_operator(gen_proc_t * p, oberon_oper_t * oper) { + oberon_type_t * preq = oper -> left -> result; char prefix = jvm_get_prefix(oper -> result); int op = oper -> op; switch(op) @@ -1615,7 +1680,7 @@ push_operator(gen_proc_t * p, oberon_oper_t * oper) case OP_LOGIC_NOT: case OP_ABS: push_expr(p, oper -> left); - jvm_generate_operator(p, prefix, op); + jvm_generate_operator(p, preq, prefix, op); break; case OP_ADD: @@ -1635,7 +1700,7 @@ push_operator(gen_proc_t * p, oberon_oper_t * oper) case OP_GEQ: push_expr(p, oper -> left); push_expr(p, oper -> right); - jvm_generate_operator(p, prefix, op); + jvm_generate_operator(p, preq, prefix, op); break; case OP_LOGIC_OR: diff --git a/src/backends/jvm/generator-jvm.h b/src/backends/jvm/generator-jvm.h index 67abe23..3095a49 100644 --- a/src/backends/jvm/generator-jvm.h +++ b/src/backends/jvm/generator-jvm.h @@ -66,3 +66,8 @@ struct gen_module_t struct gen_class * class; int rec_id; }; + +struct gen_label_t +{ + int id; +}; diff --git a/src/generator.h b/src/generator.h index e988ba0..23901dd 100644 --- a/src/generator.h +++ b/src/generator.h @@ -27,6 +27,11 @@ void oberon_generate_begin_proc(oberon_context_t * ctx, oberon_object_t * proc); void oberon_generate_end_proc(oberon_context_t * ctx); void oberon_generate_call_proc(oberon_context_t * ctx, oberon_expr_t * desig); +gen_label_t * oberon_generator_reserve_label(oberon_context_t * ctx); +void oberon_generate_label(oberon_context_t * ctx, gen_label_t * l); +void oberon_generate_branch(oberon_context_t * ctx, oberon_expr_t * cond, bool gotoif, gen_label_t * l); +void oberon_generate_goto(oberon_context_t * ctx, gen_label_t * l); + /* * Функции генерации операторов */ diff --git a/src/oberon-internals.h b/src/oberon-internals.h index 0b45349..f0a6bed 100644 --- a/src/oberon-internals.h +++ b/src/oberon-internals.h @@ -8,7 +8,7 @@ typedef struct gen_module_t gen_module_t; typedef struct gen_proc_t gen_proc_t; typedef struct gen_type_t gen_type_t; typedef struct gen_var_t gen_var_t; -typedef struct gen_block_t gen_block_t; +typedef struct gen_label_t gen_label_t; typedef struct gen_context_t gen_context_t; typedef struct oberon_type_t oberon_type_t; diff --git a/src/oberon.c b/src/oberon.c index f2310db..5816c2b 100644 --- a/src/oberon.c +++ b/src/oberon.c @@ -61,7 +61,10 @@ enum { IMPORT, REAL, CHAR, - STRING + STRING, + IF, + THEN, + ELSE }; // ======================================================================= @@ -380,6 +383,18 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = IS; } + else if(strcmp(ident, "IF") == 0) + { + ctx -> token = IF; + } + else if(strcmp(ident, "THEN") == 0) + { + ctx -> token = THEN; + } + else if(strcmp(ident, "ELSE") == 0) + { + ctx -> token = ELSE; + } } static void @@ -1641,6 +1656,10 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_ || b -> result -> class == OBERON_TYPE_INTEGER || a -> result -> class == OBERON_TYPE_REAL || b -> result -> class == OBERON_TYPE_REAL) + { + // accept + } + else { oberon_error(ctx, "used only with numeric types"); } @@ -2845,6 +2864,9 @@ oberon_decl_seq(oberon_context_t * ctx) oberon_prevent_undeclarated_procedures(ctx); } +static void +oberon_statement_seq(oberon_context_t * ctx); + static void oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst) { @@ -2877,6 +2899,36 @@ oberon_statement(oberon_context_t * ctx) oberon_opt_proc_parens(ctx, item1); } } + else if(ctx -> token == IF) + { + gen_label_t * end; + gen_label_t * els; + oberon_expr_t * cond; + + els = oberon_generator_reserve_label(ctx); + end = oberon_generator_reserve_label(ctx); + + oberon_assert_token(ctx, IF); + cond = oberon_expr(ctx); + if(cond -> result -> class != OBERON_TYPE_BOOLEAN) + { + oberon_error(ctx, "condition must be boolean"); + } + oberon_assert_token(ctx, THEN); + oberon_generate_branch(ctx, cond, false, els); + oberon_statement_seq(ctx); + oberon_generate_goto(ctx, end); + + if(ctx -> token == ELSE) + { + oberon_generate_label(ctx, els); + oberon_assert_token(ctx, ELSE); + oberon_statement_seq(ctx); + } + + oberon_generate_label(ctx, end); + oberon_assert_token(ctx, END); + } else if(ctx -> token == RETURN) { oberon_assert_token(ctx, RETURN); diff --git a/src/test.c b/src/test.c index cacf00d..a144f36 100644 --- a/src/test.c +++ b/src/test.c @@ -4,52 +4,41 @@ #include "../include/oberon.h" -/* static char source_test[] = "(* Main module *)" "MODULE Test;" "IMPORT Out;" - "VAR" - " msg : ARRAY 20 OF CHAR;" - "BEGIN" - " msg := ''" - "END Test." -; -*/ - -static char source_test[] = - "(* Main module *)" - "MODULE Test;" - "IMPORT Out;" - "CONST" - " helloworld = 'Hello World!';" - " null = 0X;" - " space = 020X;" - " bang = 021X;" - " h = 048X;" - " e = 045X;" - " l = 04CX;" - " o = 04FX;" - " w = 057X;" - " r = 052X;" - " d = 044X;" "" "TYPE" - " Ident = ARRAY 20 OF CHAR;" - " PrintString = PROCEDURE (str : ARRAY OF CHAR);" + " R = INTEGER;" "" - "VAR" - " msg : Ident;" - " print : PrintString;" + "PROCEDURE Factorial(n : R) : R;" + "BEGIN" + " IF n <= 1 THEN" + " RETURN 1;" + " ELSE" + " RETURN n * Factorial(n - 1);" + " END;" + " RETURN 0; (* Детектор ретурнов - дерьмо *)" + "END Factorial;" "" "BEGIN" - " msg := helloworld;" - " print := Out.String;" - " Out.Open;" - " print(msg);" - " Out.Ln;" - " print(\"It's works!\");" - " Out.Ln;" + " Out.Open();" + " Out.Int(Factorial(0), 0); Out.Ln;" + " Out.Int(Factorial(1), 0); Out.Ln;" + " Out.Int(Factorial(2), 0); Out.Ln;" + " Out.Int(Factorial(3), 0); Out.Ln;" + " Out.Int(Factorial(4), 0); Out.Ln;" + " Out.Int(Factorial(5), 0); Out.Ln;" + " Out.Int(Factorial(6), 0); Out.Ln;" + " Out.Int(Factorial(7), 0); Out.Ln;" + " Out.Int(Factorial(8), 0); Out.Ln;" + " Out.Int(Factorial(9), 0); Out.Ln;" + " Out.Int(Factorial(10), 0); Out.Ln;" + " Out.Int(Factorial(11), 0); Out.Ln;" + " Out.Int(Factorial(12), 0); Out.Ln;" + " Out.Int(Factorial(13), 0); Out.Ln;" + " Out.Int(Factorial(14), 0); Out.Ln;" "END Test." ;