DEADSOFTWARE

Добавлен тип SET
[dsw-obn.git] / src / oberon.c
index e88ff79159e28e93c010a73ebde045ee8a6c9132..50429645b22a713480253b1fb262128dc1b97af6 100644 (file)
@@ -52,8 +52,8 @@ enum {
        TYPE,
        ARRAY,
        OF,
-       LBRACE,
-       RBRACE,
+       LBRACK,
+       RBRACK,
        RECORD,
        POINTER,
        TO,
@@ -74,7 +74,10 @@ enum {
        FOR,
        BY,
        LOOP,
-       EXIT
+       EXIT,
+       LBRACE,
+       RBRACE,
+       DOTDOT
 };
 
 // =======================================================================
@@ -149,6 +152,15 @@ oberon_new_type_string(int size)
        return x;
 }
 
+static oberon_type_t *
+oberon_new_type_set(int size)
+{
+       oberon_type_t * x;
+       x = oberon_new_type_ptr(OBERON_TYPE_SET);
+       x -> size = size;
+       return x;
+}
+
 // =======================================================================
 //   TABLE
 // ======================================================================= 
@@ -505,37 +517,43 @@ oberon_read_number(oberon_context_t * ctx)
        }
        else if(ctx -> c == '.')
        {
-               mode = 2;
                oberon_get_char(ctx);
-
-               while(isdigit(ctx -> c))
+               if(ctx -> c == '.')
                {
-                       oberon_get_char(ctx);
+                       /* Чит: избегаем конфликта с DOTDOT */
+                       ctx -> code_index -= 1;
                }
-
-               if(ctx -> c == 'E' || ctx -> c == 'D')
+               else
                {
-                       exp_i = ctx -> code_index;
-
-                       if(ctx -> c == 'D')
-                       {
-                               mode = 3;
-                       }
-
-                       oberon_get_char(ctx);
+                       mode = 2;
 
-                       if(ctx -> c == '+' || ctx -> c == '-')
+                       while(isdigit(ctx -> c))
                        {
                                oberon_get_char(ctx);
                        }
 
-                       while(isdigit(ctx -> c))
+                       if(ctx -> c == 'E' || ctx -> c == 'D')
                        {
+                               exp_i = ctx -> code_index;
+
+                               if(ctx -> c == 'D')
+                               {
+                                       mode = 3;
+                               }
+
                                oberon_get_char(ctx);
-                       }
 
-               }
+                               if(ctx -> c == '+' || ctx -> c == '-')
+                               {
+                                       oberon_get_char(ctx);
+                               }
 
+                               while(isdigit(ctx -> c))
+                               {
+                                       oberon_get_char(ctx);
+                               }       
+                       }
+               }
                end_i = ctx -> code_index;
        }
 
@@ -699,6 +717,11 @@ oberon_read_symbol(oberon_context_t * ctx)
                case '.':
                        ctx -> token = DOT;
                        oberon_get_char(ctx);
+                       if(ctx -> c == '.')
+                       {
+                               ctx -> token = DOTDOT;
+                               oberon_get_char(ctx);
+                       }
                        break;
                case '(':
                        ctx -> token = LPAREN;
@@ -774,11 +797,11 @@ oberon_read_symbol(oberon_context_t * ctx)
                        oberon_get_char(ctx);
                        break;
                case '[':
-                       ctx -> token = LBRACE;
+                       ctx -> token = LBRACK;
                        oberon_get_char(ctx);
                        break;
                case ']':
-                       ctx -> token = RBRACE;
+                       ctx -> token = RBRACK;
                        oberon_get_char(ctx);
                        break;
                case '^':
@@ -791,6 +814,14 @@ oberon_read_symbol(oberon_context_t * ctx)
                case '\'':
                        oberon_read_string(ctx);
                        break;                  
+               case '{':
+                       ctx -> token = LBRACE;
+                       oberon_get_char(ctx);
+                       break;
+               case '}':
+                       ctx -> token = RBRACE;
+                       oberon_get_char(ctx);
+                       break;
                default:
                        oberon_error(ctx, "invalid char %c", ctx -> c);
                        break;
@@ -871,12 +902,18 @@ oberon_make_unary_op(oberon_context_t * ctx, int token, oberon_expr_t * a)
 
        if(token == MINUS)
        {
-               if(result -> class != OBERON_TYPE_INTEGER)
+               if(result -> class == OBERON_TYPE_SET)
+               {
+                       expr = oberon_new_operator(OP_COMPLEMENTATION, result, a, NULL);
+               }
+               else if(result -> class == OBERON_TYPE_INTEGER)
+               {
+                       expr = oberon_new_operator(OP_UNARY_MINUS, result, a, NULL);
+               }
+               else
                {
                        oberon_error(ctx, "incompatible operator type");
                }
-
-               expr = oberon_new_operator(OP_UNARY_MINUS, result, a, NULL);
        }
        else if(token == NOT)
        {
@@ -1394,7 +1431,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
 }
 
 #define ISSELECTOR(x) \
-       (((x) == LBRACE) \
+       (((x) == LBRACK) \
        || ((x) == DOT) \
        || ((x) == UPARROW) \
        || ((x) == LPAREN))
@@ -1502,12 +1539,12 @@ oberon_designator(oberon_context_t * ctx)
                                name = oberon_assert_ident(ctx);
                                expr = oberon_make_record_selector(ctx, expr, name);
                                break;
-                       case LBRACE:
-                               oberon_assert_token(ctx, LBRACE);
+                       case LBRACK:
+                               oberon_assert_token(ctx, LBRACK);
                                int num_indexes = 0;
                                oberon_expr_t * indexes = NULL;
                                oberon_expr_list(ctx, &num_indexes, &indexes, 0);
-                               oberon_assert_token(ctx, RBRACE);
+                               oberon_assert_token(ctx, RBRACK);
 
                                for(int i = 0; i < num_indexes; i++)
                                {
@@ -1619,6 +1656,59 @@ oberon_integer_item(oberon_context_t * ctx, int64_t i)
        return expr;
 }
 
+static oberon_expr_t *
+oberon_element(oberon_context_t * ctx)
+{
+       oberon_expr_t * e1;
+       oberon_expr_t * e2;
+
+       e1 = oberon_expr(ctx);
+       if(e1 -> result -> class != OBERON_TYPE_INTEGER)
+       {
+               oberon_error(ctx, "expected integer");
+       }
+
+       e2 = NULL;
+       if(ctx -> token == DOTDOT)
+       {
+               oberon_assert_token(ctx, DOTDOT);
+               e2 = oberon_expr(ctx);
+               if(e2 -> result -> class != OBERON_TYPE_INTEGER)
+               {
+                       oberon_error(ctx, "expected integer");
+               }
+       }
+
+       oberon_expr_t * set;
+       set = oberon_new_operator(OP_RANGE, ctx -> set_type, e1, e2);
+       return set;
+}
+
+static oberon_expr_t *
+oberon_set(oberon_context_t * ctx)
+{
+       oberon_expr_t * set;
+       oberon_expr_t * elements;
+       set = oberon_new_item(MODE_SET, ctx -> set_type, true);
+       set -> item.integer = 0;
+
+       oberon_assert_token(ctx, LBRACE);
+       if(ISEXPR(ctx -> token))
+       {
+               elements = oberon_element(ctx);
+               set = oberon_new_operator(OP_UNION, ctx -> set_type, set, elements);
+               while(ctx -> token == COMMA)
+               {
+                       oberon_assert_token(ctx, COMMA);
+                       elements = oberon_element(ctx);
+                       set = oberon_new_operator(OP_UNION, ctx -> set_type, set, elements);
+               }
+       }
+       oberon_assert_token(ctx, RBRACE);
+
+       return set;
+}
+
 static oberon_expr_t *
 oberon_factor(oberon_context_t * ctx)
 {
@@ -1663,6 +1753,9 @@ oberon_factor(oberon_context_t * ctx)
                        expr -> item.boolean = false;
                        oberon_assert_token(ctx, FALSE);
                        break;
+               case LBRACE:
+                       expr = oberon_set(ctx);
+                       break;
                case LPAREN:
                        oberon_assert_token(ctx, LPAREN);
                        expr = oberon_expr(ctx);
@@ -1720,6 +1813,7 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
        oberon_expr_t * expr;
        oberon_type_t * result;
 
+       bool error = false;
        if(token == IS)
        {
                oberon_type_t * v = a -> result;
@@ -1825,10 +1919,21 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
        }
        else if(token == SLASH)
        {
-               oberon_autocast_to_real(ctx, &a);
-               oberon_autocast_to_real(ctx, &b);
-               oberon_autocast_binary_op(ctx, &a, &b);
-               expr = oberon_new_operator(OP_DIV, a -> result, a, b);
+               if(a -> result -> class == OBERON_TYPE_SET
+                       || b -> result -> class == OBERON_TYPE_SET)
+               {
+                       oberon_autocast_binary_op(ctx, &a, &b);
+                       result = a -> result;
+                       expr = oberon_new_operator(OP_SYM_DIFFERENCE, result, a, b);
+               }
+               else
+               {
+                       oberon_autocast_to_real(ctx, &a);
+                       oberon_autocast_to_real(ctx, &b);
+                       oberon_autocast_binary_op(ctx, &a, &b);
+                       result = a -> result;
+                       expr = oberon_new_operator(OP_DIV, result, a, b);
+               }
        }
        else if(token == DIV)
        {
@@ -1844,29 +1949,58 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
        else
        {
                oberon_autocast_binary_op(ctx, &a, &b);
-
-               if(token == PLUS)
+               result = a -> result;
+               if(result -> class == OBERON_TYPE_SET)
                {
-                       expr = oberon_new_operator(OP_ADD, a -> result, a, b);
-               }
-               else if(token == MINUS)
-               {
-                       expr = oberon_new_operator(OP_SUB, a -> result, a, b);
-               }
-               else if(token == STAR)
-               {
-                       expr = oberon_new_operator(OP_MUL, a -> result, a, b);
+                       switch(token)
+                       {
+                               case PLUS:
+                                       expr = oberon_new_operator(OP_UNION, result, a, b);
+                                       break;
+                               case MINUS:
+                                       expr = oberon_new_operator(OP_DIFFERENCE, result, a, b);
+                                       break;
+                               case STAR:
+                                       expr = oberon_new_operator(OP_INTERSECTION, result, a, b);
+                                       break;
+                               default:
+                                       error = true;
+                                       break;
+                       }
                }
-               else if(token == MOD)
+               else if(result -> class == OBERON_TYPE_INTEGER
+                       || result -> class == OBERON_TYPE_REAL)
                {
-                       expr = oberon_new_operator(OP_MOD, a -> result, a, b);
+                       switch(token)
+                       {
+                               case PLUS:
+                                       expr = oberon_new_operator(OP_ADD, result, a, b);
+                                       break;
+                               case MINUS:
+                                       expr = oberon_new_operator(OP_SUB, result, a, b);
+                                       break;
+                               case STAR:
+                                       expr = oberon_new_operator(OP_MUL, result, a, b);
+                                       break;
+                               case MOD:
+                                       expr = oberon_new_operator(OP_MOD, result, a, b);
+                                       break;
+                               default:
+                                       error = true;
+                                       break;
+                       }
                }
                else
                {
-                       oberon_error(ctx, "oberon_make_bin_op: bin wat");
+                       error = true;
                }
        }
 
+       if(error)
+       {
+               oberon_error(ctx, "invalid operation");
+       }
+
        return expr;
 }
 
@@ -3399,6 +3533,9 @@ register_default_types(oberon_context_t * ctx)
 
        ctx -> char_type = oberon_new_type_char(1);
        oberon_define_type(ctx -> world_scope, "CHAR", ctx -> char_type, 1);
+
+       ctx -> set_type = oberon_new_type_set(4);
+       oberon_define_type(ctx -> world_scope, "SET", ctx -> set_type, 1);
 }
 
 static void
@@ -3440,6 +3577,9 @@ oberon_make_min_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
                case OBERON_TYPE_INTEGER:
                        expr = oberon_integer_item(ctx, -powl(2, bits - 1));
                        break;
+               case OBERON_TYPE_SET:
+                       expr = oberon_integer_item(ctx, 0);
+                       break;
                default:
                        oberon_error(ctx, "allowed only basic types");
                        break;
@@ -3476,6 +3616,9 @@ oberon_make_max_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
                case OBERON_TYPE_INTEGER:
                        expr = oberon_integer_item(ctx, powl(2, bits - 1) - 1);
                        break;
+               case OBERON_TYPE_SET:
+                       expr = oberon_integer_item(ctx, bits);
+                       break;
                default:
                        oberon_error(ctx, "allowed only basic types");
                        break;
@@ -3513,6 +3656,8 @@ oberon_make_size_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list
                case OBERON_TYPE_INTEGER:
                case OBERON_TYPE_BOOLEAN:
                case OBERON_TYPE_REAL:
+               case OBERON_TYPE_CHAR:
+               case OBERON_TYPE_SET:
                        size = type -> size;
                        break;
                default: