diff --git a/src/oberon.c b/src/oberon.c
index a2a567036598a90f005bcc1780531e18e6d54701..50429645b22a713480253b1fb262128dc1b97af6 100644 (file)
--- a/src/oberon.c
+++ b/src/oberon.c
TYPE,
ARRAY,
OF,
- LBRACE,
- RBRACE,
+ LBRACK,
+ RBRACK,
RECORD,
POINTER,
TO,
FOR,
BY,
LOOP,
- EXIT
+ EXIT,
+ LBRACE,
+ RBRACE,
+ DOTDOT
};
// =======================================================================
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
// =======================================================================
}
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;
+ mode = 2;
- if(ctx -> c == 'D')
- {
- mode = 3;
- }
-
- oberon_get_char(ctx);
-
- 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;
}
case '.':
ctx -> token = DOT;
oberon_get_char(ctx);
+ if(ctx -> c == '.')
+ {
+ ctx -> token = DOTDOT;
+ oberon_get_char(ctx);
+ }
break;
case '(':
ctx -> token = LPAREN;
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 '^':
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;
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))
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++)
{
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)
{
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,7 +1813,46 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
oberon_expr_t * expr;
oberon_type_t * result;
- if(ITMAKESBOOLEAN(token))
+ bool error = false;
+ if(token == IS)
+ {
+ oberon_type_t * v = a -> result;
+ if(v -> class == OBERON_TYPE_POINTER)
+ {
+ v = v -> base;
+ if(v -> class != OBERON_TYPE_RECORD)
+ {
+ oberon_error(ctx, "must be record");
+ }
+ }
+ else if(v -> class != OBERON_TYPE_RECORD)
+ {
+ oberon_error(ctx, "must be record");
+ }
+
+ if(b -> is_item == false || b -> item.mode != MODE_TYPE)
+ {
+ oberon_error(ctx, "requires type");
+ }
+
+ oberon_type_t * t = b -> result;
+ if(t -> class == OBERON_TYPE_POINTER)
+ {
+ t = t -> base;
+ if(t -> class != OBERON_TYPE_RECORD)
+ {
+ oberon_error(ctx, "must be record");
+ }
+ }
+ else if(t -> class != OBERON_TYPE_RECORD)
+ {
+ oberon_error(ctx, "must be record");
+ }
+
+ result = ctx -> bool_type;
+ expr = oberon_new_operator(OP_IS, result, a, b);
+ }
+ else if(ITMAKESBOOLEAN(token))
{
if(ITUSEONLYINTEGER(token))
{
@@ -1787,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)
{
@@ -1806,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)
- {
- expr = oberon_new_operator(OP_ADD, a -> result, a, b);
- }
- else if(token == MINUS)
+ result = a -> result;
+ if(result -> class == OBERON_TYPE_SET)
{
- 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;
}
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
@@ -3402,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;
@@ -3438,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;
@@ -3475,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:
@@ -3501,6 +3684,7 @@ oberon_make_abs_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
oberon_expr_t * arg;
arg = list_args;
+ oberon_check_src(ctx, arg);
oberon_type_t * result_type;
result_type = arg -> result;
@@ -3523,8 +3707,10 @@ oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
oberon_error(ctx, "too few arguments");
}
+
oberon_expr_t * dst;
dst = list_args;
+ oberon_check_dst(ctx, dst);
oberon_type_t * type;
type = dst -> result;
@@ -3573,6 +3759,7 @@ oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
oberon_expr_t * arg = size_list;
for(int i = 0; i < max_args - 1; i++)
{
+ oberon_check_src(ctx, arg);
if(arg -> result -> class != OBERON_TYPE_INTEGER)
{
oberon_error(ctx, "size must be integer");