From: DeaDDooMER Date: Fri, 4 Aug 2017 22:07:55 +0000 (+0300) Subject: Добавлена конструкция WITH X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=commitdiff_plain;h=3edc4e955c943735543e2c94ecd28f94d75b32fb Добавлена конструкция WITH --- diff --git a/notes b/notes index 2c9c569..b6f9cdd 100644 --- a/notes +++ b/notes @@ -1,15 +1,14 @@ -- Нет конструкции WITH - - Нет модуля SYSTEM - Нет функций ASH CAP CHR ENTIER LEN LONG ODD ORD SHORT - Нет процедур ASSERT COPY DEC EXCL HALT INC INCL - Нет счёта строк / столбцов - Не реализована свёртка констант +- Нужно пробежаться по стандарту и всё перепроверить. - JVM: Не реализованы VAR-параметры. - JVM: Не реализованы локальные процедуры. - -- Нужно пробежаться по стандарту и всё перепроверить. +- JVM: Не реализовано полное сранение массивов. +- JVM: Не реализовано полное сранение записей. - Нужны средства создания биндингов. На данный момент реализуемо как заглушки для модулей. - Любая ошибка фатальна 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); diff --git a/src/test.c b/src/test.c index 0eb787c..dab2914 100644 --- a/src/test.c +++ b/src/test.c @@ -8,15 +8,30 @@ static char source_test[] = "(* Main module *)" "MODULE Test;" "IMPORT Out;" + "TYPE" + " R1 = POINTER TO R1Desc;" + " R1Desc = RECORD a : INTEGER; END;" + " R2 = POINTER TO R2Desc;" + " R2Desc = RECORD (R1Desc) b : INTEGER; END;" + " Y1 = POINTER TO Y1Desc;" + " Y1Desc = RECORD END;" "" "VAR" - " i : INTEGER;" + " r1 : R1;" + " r2 : R2;" + " y1 : Y1;" "" "BEGIN" + " NEW(r1);" + " NEW(r2);" + " NEW(y1);" + " r1 := r2;" " Out.Open;" - " CASE 666 OF" - " 2, 3, 4, 5: Out.String('Zero');" - " | 10..20, 24: Out.String('Holy shit');" + " WITH r1 : R2 DO" + " r1.b := 666;" + " Out.String('R2 branch');" + " | y1 : Y1 DO" + " Out.String('Y1 branch');" " ELSE" " Out.String('Something else');" " END;"