DEADSOFTWARE

Добавлены открытые массивы
[dsw-obn.git] / oberon.c
index 817da1ae02b4f417f9c005f902bd2d26b0f5f3a1..16043c2f7aa0e4bdcd658130a5765b126b385b11 100644 (file)
--- a/oberon.c
+++ b/oberon.c
@@ -4,6 +4,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "oberon.h"
 #include "generator.h"
@@ -53,7 +54,8 @@ enum {
        TO,
        UPARROW,
        NIL,
-       IMPORT
+       IMPORT,
+       REAL
 };
 
 // =======================================================================
@@ -102,6 +104,15 @@ oberon_new_type_boolean(int size)
        return x;
 }
 
+static oberon_type_t *
+oberon_new_type_real(int size)
+{
+       oberon_type_t * x;
+       x = oberon_new_type_ptr(OBERON_TYPE_REAL);
+       x -> size = size;
+       return x;
+}
+
 // =======================================================================
 //   TABLE
 // ======================================================================= 
@@ -155,40 +166,13 @@ oberon_define_object(oberon_scope_t * scope, char * name, int class, int export,
        newvar -> read_only = read_only;
        newvar -> local = scope -> local;
        newvar -> parent = scope -> parent;
+       newvar -> module = scope -> ctx -> mod;
 
        x -> next = newvar;
 
        return newvar;
 }
 
-static void
-oberon_define_field(oberon_context_t * ctx, oberon_type_t * rec, char *  name, oberon_type_t * type)
-{
-       // TODO check base fields
-
-       oberon_object_t * x = rec -> decl;
-       while(x -> next && strcmp(x -> next -> name, name) != 0)
-       {
-               x = x -> next;
-       }
-
-       if(x -> next)
-       {
-               oberon_error(ctx, "multiple definition");
-       }
-
-       oberon_object_t * field = malloc(sizeof *field);
-       memset(field, 0, sizeof *field);
-       field -> name = name;
-       field -> class = OBERON_CLASS_FIELD;
-       field -> type = type;
-       field -> local = 1;
-       field -> parent = NULL;
-
-       rec -> num_decl += 1;
-       x -> next = field;
-}
-
 static oberon_object_t *
 oberon_find_object_in_list(oberon_object_t * list, char * name)
 {
@@ -239,24 +223,15 @@ oberon_find_field(oberon_context_t * ctx, oberon_type_t * rec, char * name)
 }
 
 static oberon_object_t *
-oberon_define_type(oberon_scope_t * scope, char * name, oberon_type_t * type, int export, int read_only)
+oberon_define_type(oberon_scope_t * scope, char * name, oberon_type_t * type, int export)
 {
        oberon_object_t * id;
-       id = oberon_define_object(scope, name, OBERON_CLASS_TYPE, export, read_only);
+       id = oberon_define_object(scope, name, OBERON_CLASS_TYPE, export, 0);
        id -> type = type;
        oberon_generator_init_type(scope -> ctx, type);
        return id;
 }
 
-static oberon_object_t *
-oberon_define_var(oberon_scope_t * scope, int class, char * name, oberon_type_t * type, int export, int read_only)
-{
-       oberon_object_t * var;
-       var = oberon_define_object(scope, name, class, export, read_only);
-       var -> type = type;
-       return var;
-}
-
 // =======================================================================
 //   SCANER
 // ======================================================================= 
@@ -264,8 +239,11 @@ oberon_define_var(oberon_scope_t * scope, int class, char * name, oberon_type_t
 static void
 oberon_get_char(oberon_context_t * ctx)
 {
-       ctx -> code_index += 1;
-       ctx -> c = ctx -> code[ctx -> code_index];
+       if(ctx -> code[ctx -> code_index])
+       {
+               ctx -> code_index += 1;
+               ctx -> c = ctx -> code[ctx -> code_index];
+       }
 }
 
 static void
@@ -382,28 +360,119 @@ oberon_read_ident(oberon_context_t * ctx)
 }
 
 static void
-oberon_read_integer(oberon_context_t * ctx)
-{
-       int len = 0;
-       int i = ctx -> code_index;
+oberon_read_number(oberon_context_t * ctx)
+{
+       long integer;
+       double real;
+       char * ident;
+       int start_i;
+       int exp_i;
+       int end_i;
+
+       /*
+        * mode = 0 == DEC
+        * mode = 1 == HEX
+        * mode = 2 == REAL
+        * mode = 3 == LONGREAL
+        */
+       int mode = 0;
+       start_i = ctx -> code_index;
+
+       while(isdigit(ctx -> c))
+       {
+               oberon_get_char(ctx);
+       }
 
-       int c = ctx -> code[i];
-       while(isdigit(c))
+       end_i = ctx -> code_index;
+
+       if(isxdigit(ctx -> c))
        {
-               i += 1;
-               len += 1;
-               c = ctx -> code[i];
+               mode = 1;
+               while(isxdigit(ctx -> c))
+               {
+                       oberon_get_char(ctx);
+               }
+
+               end_i = ctx -> code_index;
+
+               if(ctx -> c != 'H')
+               {
+                       oberon_error(ctx, "invalid hex number");
+               }
+               oberon_get_char(ctx);
        }
+       else if(ctx -> c == '.')
+       {
+               mode = 2;
+               oberon_get_char(ctx);
 
-       char * ident = malloc(len + 2);
-       memcpy(ident, &ctx->code[ctx->code_index], len);
-       ident[len + 1] = 0;
+               while(isdigit(ctx -> c))
+               {
+                       oberon_get_char(ctx);
+               }
+
+               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;
+       }
+
+       int len = end_i - start_i;
+       ident = malloc(len + 1);
+       memcpy(ident, &ctx -> code[start_i], len);
+       ident[len] = 0;
+
+       if(mode == 3)
+       {
+               int i = exp_i - start_i;
+               ident[i] = 'E';
+       }
+
+       switch(mode)
+       {
+               case 0:
+                       integer = atol(ident);
+                       real = integer;
+                       ctx -> token = INTEGER;
+                       break;
+               case 1:
+                       sscanf(ident, "%lx", &integer);
+                       real = integer;
+                       ctx -> token = INTEGER;
+                       break;
+               case 2:
+               case 3:
+                       sscanf(ident, "%lf", &real);
+                       ctx -> token = REAL;
+                       break;
+               default:
+                       oberon_error(ctx, "oberon_read_number: wat");
+                       break;
+       }
 
-       ctx -> code_index = i;
-       ctx -> c = ctx -> code[i];
        ctx -> string = ident;
-       ctx -> integer = atoi(ident);
-       ctx -> token = INTEGER;
+       ctx -> integer = integer;
+       ctx -> real = real;
 }
 
 static void
@@ -415,6 +484,43 @@ oberon_skip_space(oberon_context_t * ctx)
        }
 }
 
+static void
+oberon_read_comment(oberon_context_t * ctx)
+{
+       int nesting = 1;
+       while(nesting >= 1)
+       {
+               if(ctx -> c == '(')
+               {
+                       oberon_get_char(ctx);
+                       if(ctx -> c == '*')
+                       {
+                               oberon_get_char(ctx);
+                               nesting += 1;
+                       }
+               }
+               else if(ctx -> c == '*')
+               {
+                       oberon_get_char(ctx);
+                       if(ctx -> c == ')')
+                       {
+                               oberon_get_char(ctx);
+                               nesting -= 1;
+                       }
+               }
+               else if(ctx -> c == 0)
+               {
+                       oberon_error(ctx, "unterminated comment");
+               }
+               else
+               {
+                       oberon_get_char(ctx);
+               }
+       }
+}
+
+static void oberon_read_token(oberon_context_t * ctx);
+
 static void
 oberon_read_symbol(oberon_context_t * ctx)
 {
@@ -444,6 +550,12 @@ oberon_read_symbol(oberon_context_t * ctx)
                case '(':
                        ctx -> token = LPAREN;
                        oberon_get_char(ctx);
+                       if(ctx -> c == '*')
+                       {
+                               oberon_get_char(ctx);
+                               oberon_read_comment(ctx);
+                               oberon_read_token(ctx);
+                       }
                        break;
                case ')':
                        ctx -> token = RPAREN;
@@ -486,6 +598,11 @@ oberon_read_symbol(oberon_context_t * ctx)
                case '*':
                        ctx -> token = STAR;
                        oberon_get_char(ctx);
+                       if(ctx -> c == ')')
+                       {
+                               oberon_get_char(ctx);
+                               oberon_error(ctx, "unstarted comment");
+                       }
                        break;
                case '/':
                        ctx -> token = SLASH;
@@ -516,7 +633,7 @@ oberon_read_symbol(oberon_context_t * ctx)
                        oberon_get_char(ctx);
                        break;
                default:
-                       oberon_error(ctx, "invalid char");
+                       oberon_error(ctx, "invalid char %c", ctx -> c);
                        break;
        }
 }
@@ -533,7 +650,7 @@ oberon_read_token(oberon_context_t * ctx)
        }
        else if(isdigit(c))
        {
-               oberon_read_integer(ctx);
+               oberon_read_number(ctx);
        }
        else
        {
@@ -561,6 +678,7 @@ oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon
 
        operator -> is_item = 0;
        operator -> result = result;
+       operator -> read_only = 1;
        operator -> op = op;
        operator -> left = left;
        operator -> right = right;
@@ -569,7 +687,7 @@ oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon
 }
 
 static oberon_expr_t *
-oberon_new_item(int mode, oberon_type_t * result)
+oberon_new_item(int mode, oberon_type_t * result, int read_only)
 {
        oberon_item_t * item;
         item = malloc(sizeof *item);
@@ -577,6 +695,7 @@ oberon_new_item(int mode, oberon_type_t * result)
 
        item -> is_item = 1;
        item -> result = result;
+       item -> read_only = read_only;
        item -> mode = mode;
 
        return (oberon_expr_t *)item;
@@ -648,7 +767,13 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
 {
        if(pref -> class != expr -> result -> class)
        {
-               oberon_error(ctx, "incompatible types");
+               if(pref -> class != OBERON_TYPE_PROCEDURE)
+               {
+                       if(expr -> result -> class != OBERON_TYPE_POINTER)
+                       {
+                               oberon_error(ctx, "incompatible types");
+                       }
+               }
        }
 
        if(pref -> class == OBERON_TYPE_INTEGER)
@@ -719,21 +844,26 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
        {
                if(param -> class == OBERON_CLASS_VAR_PARAM)
                {
-                       if(arg -> is_item)
+                       if(arg -> read_only)
                        {
-                               switch(arg -> item.mode)
-                               {
-                                       case MODE_VAR:
-                                       case MODE_INDEX:
-                                       case MODE_FIELD:
-                                       // Допустимо разыменование?
-                                       //case MODE_DEREF:
-                                               break;
-                                       default:
-                                               oberon_error(ctx, "var-parameter accept only variables");
-                                               break;
-                               }
+                               oberon_error(ctx, "assign to read-only var");
                        }
+
+                       //if(arg -> is_item)
+                       //{
+                       //      switch(arg -> item.mode)
+                       //      {
+                       //              case MODE_VAR:
+                       //              case MODE_INDEX:
+                       //              case MODE_FIELD:
+                       //              // Допустимо разыменование?
+                       //              //case MODE_DEREF:
+                       //                      break;
+                       //              default:
+                       //                      oberon_error(ctx, "var-parameter accept only variables");
+                       //                      break;
+                       //      }
+                       //}
                }
                oberon_autocast_to(ctx, arg, param -> type);
                arg = arg -> next;
@@ -783,7 +913,7 @@ oberon_make_call_func(oberon_context_t * ctx, oberon_object_t * proc, int num_ar
                        oberon_error(ctx, "attempt to call procedure in expression");
                }
 
-               call = oberon_new_item(MODE_CALL, proc -> type -> base);
+               call = oberon_new_item(MODE_CALL, proc -> type -> base, 1);
                call -> item.var = proc;
                call -> item.num_args = num_args;
                call -> item.args = list_args;
@@ -834,7 +964,7 @@ oberon_make_call_proc(oberon_context_t * ctx, oberon_object_t * proc, int num_ar
                }
 
                oberon_expr_t * call;
-               call = oberon_new_item(MODE_CALL, proc -> type -> base);
+               call = oberon_new_item(MODE_CALL, proc -> type -> base, 1);
                call -> item.var = proc;
                call -> item.num_args = num_args;
                call -> item.args = list_args;
@@ -864,7 +994,7 @@ oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr)
        assert(expr -> is_item);
 
        oberon_expr_t * selector;
-       selector = oberon_new_item(MODE_DEREF, expr -> result -> base);
+       selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only);
        selector -> item.parent = (oberon_item_t *) expr;
 
        return selector;
@@ -894,21 +1024,24 @@ oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, oberon
        }
 
        // Статическая проверка границ массива
-       if(index -> is_item)
+       if(desig -> result -> size != 0)
        {
-               if(index -> item.mode == MODE_INTEGER)
+               if(index -> is_item)
                {
-                       int arr_size = desig -> result -> size;
-                       int index_int = index -> item.integer;
-                       if(index_int < 0 || index_int > arr_size - 1)
+                       if(index -> item.mode == MODE_INTEGER)
                        {
-                               oberon_error(ctx, "not in range (dimension size 0..%i)", arr_size - 1);
+                               int arr_size = desig -> result -> size;
+                               int index_int = index -> item.integer;
+                               if(index_int < 0 || index_int > arr_size - 1)
+                               {
+                                       oberon_error(ctx, "not in range (dimension size 0..%i)", arr_size - 1);
+                               }
                        }
                }
        }
 
        oberon_expr_t * selector;
-       selector = oberon_new_item(MODE_INDEX, base);
+       selector = oberon_new_item(MODE_INDEX, base, desig -> read_only);
        selector -> item.parent = (oberon_item_t *) desig;
        selector -> item.num_args = 1;
        selector -> item.args = index;
@@ -936,8 +1069,25 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
        oberon_object_t * field;
        field = oberon_find_field(ctx, rec, name);
 
+       if(field -> export == 0)
+       {
+               if(field -> module != ctx -> mod)
+               {
+                       oberon_error(ctx, "field not exported");
+               }
+       }
+
+       int read_only = 0;
+       if(field -> read_only)
+       {
+               if(field -> module != ctx -> mod)
+               {
+                       read_only = 1;
+               }
+       }
+
        oberon_expr_t * selector;
-       selector = oberon_new_item(MODE_FIELD, field -> type);
+       selector = oberon_new_item(MODE_FIELD, field -> type, read_only);
        selector -> item.var = field;
        selector -> item.parent = (oberon_item_t *) expr;
 
@@ -991,6 +1141,15 @@ oberon_designator(oberon_context_t * ctx)
 
        var = oberon_qualident(ctx, NULL, 1);
 
+       int read_only = 0;
+       if(var -> read_only)
+       {
+               if(var -> module != ctx -> mod)
+               {
+                       read_only = 1;
+               }
+       }
+
        switch(var -> class)
        {
                case OBERON_CLASS_CONST:
@@ -1000,8 +1159,10 @@ oberon_designator(oberon_context_t * ctx)
                case OBERON_CLASS_VAR:
                case OBERON_CLASS_VAR_PARAM:
                case OBERON_CLASS_PARAM:
+                       expr = oberon_new_item(MODE_VAR, var -> type, read_only);
+                       break;
                case OBERON_CLASS_PROC:
-                       expr = oberon_new_item(MODE_VAR, var -> type);
+                       expr = oberon_new_item(MODE_VAR, var -> type, 1);
                        break;
                default:
                        oberon_error(ctx, "invalid designator");
@@ -1105,17 +1266,22 @@ oberon_factor(oberon_context_t * ctx)
                        expr = oberon_opt_func_parens(ctx, expr);
                        break;
                case INTEGER:
-                       expr = oberon_new_item(MODE_INTEGER, ctx -> int_type);
+                       expr = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1);
                        expr -> item.integer = ctx -> integer;
                        oberon_assert_token(ctx, INTEGER);
                        break;
+               case REAL:
+                       expr = oberon_new_item(MODE_REAL, ctx -> real_type, 1);
+                       expr -> item.real = ctx -> real;
+                       oberon_assert_token(ctx, REAL);
+                       break;
                case TRUE:
-                       expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
+                       expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
                        expr -> item.boolean = 1;
                        oberon_assert_token(ctx, TRUE);
                        break;
                case FALSE:
-                       expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
+                       expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
                        expr -> item.boolean = 0;
                        oberon_assert_token(ctx, FALSE);
                        break;
@@ -1131,7 +1297,7 @@ oberon_factor(oberon_context_t * ctx)
                        break;
                case NIL:
                        oberon_assert_token(ctx, NIL);
-                       expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type);
+                       expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type, 1);
                        break;
                default:
                        oberon_error(ctx, "invalid expression");
@@ -1248,6 +1414,46 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                        oberon_error(ctx, "oberon_make_bin_op: bool wat");
                }
        }
+       else if(token == SLASH)
+       {
+               if(a -> result -> class != OBERON_TYPE_REAL)
+               {
+                       if(a -> result -> class == OBERON_TYPE_INTEGER)
+                       {
+                               oberon_error(ctx, "TODO cast int -> real");
+                       }
+                       else
+                       {
+                               oberon_error(ctx, "operator / requires numeric type");
+                       }
+               }
+
+               if(b -> result -> class != OBERON_TYPE_REAL)
+               {
+                       if(b -> result -> class == OBERON_TYPE_INTEGER)
+                       {
+                               oberon_error(ctx, "TODO cast int -> real");
+                       }
+                       else
+                       {
+                               oberon_error(ctx, "operator / requires numeric type");
+                       }
+               }
+
+               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+               expr = oberon_new_operator(OP_DIV, result, a, b);
+       }
+       else if(token == DIV)
+       {
+               if(a -> result -> class != OBERON_TYPE_INTEGER
+                       || b -> result -> class != OBERON_TYPE_INTEGER)
+               {
+                       oberon_error(ctx, "operator DIV requires integer type");
+               }
+
+               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+               expr = oberon_new_operator(OP_DIV, result, a, b);
+       }
        else
        {
                oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
@@ -1264,14 +1470,6 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                {
                        expr = oberon_new_operator(OP_MUL, result, a, b);
                }
-               else if(token == SLASH)
-               {
-                       expr = oberon_new_operator(OP_DIV, result, a, b);
-               }
-               else if(token == DIV)
-               {
-                       expr = oberon_new_operator(OP_DIV, result, a, b);
-               }
                else if(token == MOD)
                {
                        expr = oberon_new_operator(OP_MOD, result, a, b);
@@ -1449,51 +1647,52 @@ oberon_ident_def(oberon_context_t * ctx, int class)
        return x;
 }
 
+static void
+oberon_ident_list(oberon_context_t * ctx, int class, int * num, oberon_object_t ** list)
+{
+       *num = 1;
+       *list = oberon_ident_def(ctx, class);
+       while(ctx -> token == COMMA)
+       {
+               oberon_assert_token(ctx, COMMA);
+               oberon_ident_def(ctx, class);
+               *num += 1;
+       }
+}
+
 static void
 oberon_var_decl(oberon_context_t * ctx)
 {
-       oberon_object_t * var;
+       int num;
+       oberon_object_t * list;
        oberon_type_t * type;
        type = oberon_new_type_ptr(OBERON_TYPE_VOID);
 
-       var = oberon_ident_def(ctx, OBERON_CLASS_VAR);
+       oberon_ident_list(ctx, OBERON_CLASS_VAR, &num, &list);
        oberon_assert_token(ctx, COLON);
        oberon_type(ctx, &type);
-       var -> type = type;
-}
 
-static oberon_object_t *
-oberon_make_param(oberon_context_t * ctx, int token, char * name, oberon_type_t * type)
-{
-       oberon_object_t * param;
-
-       if(token == VAR)
-       {
-               param = oberon_define_var(ctx -> decl, OBERON_CLASS_VAR_PARAM, name, type, 0, 0);
-       }
-       else if(token == IDENT)
+       oberon_object_t * var = list;
+       for(int i = 0; i < num; i++)
        {
-               param = oberon_define_var(ctx -> decl, OBERON_CLASS_PARAM, name, type, 0, 0);
+               var -> type = type;
+               var = var -> next;
        }
-       else
-       {
-               oberon_error(ctx, "oberon_make_param: wat");
-       }
-
-       return param;
 }
 
 static oberon_object_t *
 oberon_fp_section(oberon_context_t * ctx, int * num_decl)
 {
-       int modifer_token = ctx -> token;
+       int class = OBERON_CLASS_PARAM;
        if(ctx -> token == VAR)
        {
                oberon_read_token(ctx);
+               class = OBERON_CLASS_VAR_PARAM;
        }
 
-       char * name;
-       name = oberon_assert_ident(ctx);
+       int num;
+       oberon_object_t * list;
+       oberon_ident_list(ctx, class, &num, &list);
 
        oberon_assert_token(ctx, COLON);
 
@@ -1501,11 +1700,15 @@ oberon_fp_section(oberon_context_t * ctx, int * num_decl)
        type = oberon_new_type_ptr(OBERON_TYPE_VOID);
        oberon_type(ctx, &type);
 
-       oberon_object_t * first;
-       first = oberon_make_param(ctx, modifer_token, name, type);
+       oberon_object_t * param = list;
+       for(int i = 0; i < num; i++)
+       {
+               param -> type = type;
+               param = param -> next;
+       }
 
-       *num_decl += 1;
-       return first;
+       *num_decl += num;
+       return list;
 }
 
 #define ISFPSECTION \
@@ -1761,14 +1964,23 @@ oberon_field_list(oberon_context_t * ctx, oberon_type_t * rec)
 {
        if(ctx -> token == IDENT)
        {
-               char * name;
+               int num;
+               oberon_object_t * list;
                oberon_type_t * type;
                type = oberon_new_type_ptr(OBERON_TYPE_VOID);
 
-               name = oberon_assert_ident(ctx);
+               oberon_ident_list(ctx, OBERON_CLASS_FIELD, &num, &list);
                oberon_assert_token(ctx, COLON);
                oberon_type(ctx, &type);
-               oberon_define_field(ctx, rec, name, type);
+
+               oberon_object_t * field = list;
+               for(int i = 0; i < num; i++)
+               {
+                       field -> type = type;
+                       field = field -> next;
+               }
+
+               rec -> num_decl += num;
        }
 }
 
@@ -1822,6 +2034,14 @@ oberon_make_multiarray(oberon_context_t * ctx, oberon_expr_t * sizes, oberon_typ
        oberon_make_array_type(ctx, sizes, dim, type);
 }
 
+static void
+oberon_make_open_array(oberon_context_t * ctx, oberon_type_t * base, oberon_type_t * type)
+{
+       type -> class = OBERON_TYPE_ARRAY;
+       type -> size = 0;
+       type -> base = base;
+}
+
 static void
 oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
 {
@@ -1835,7 +2055,11 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
 
                int num_sizes = 0;
                oberon_expr_t * sizes;
-               oberon_expr_list(ctx, &num_sizes, &sizes, 1);
+
+               if(ISEXPR(ctx -> token))
+               {
+                       oberon_expr_list(ctx, &num_sizes, &sizes, 1);
+               }
 
                oberon_assert_token(ctx, OF);
 
@@ -1843,18 +2067,26 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
                base = oberon_new_type_ptr(OBERON_TYPE_VOID);
                oberon_type(ctx, &base);
 
-               oberon_make_multiarray(ctx, sizes, base, type);
+               if(num_sizes == 0)
+               {
+                       oberon_make_open_array(ctx, base, *type);
+               }
+               else
+               {
+                       oberon_make_multiarray(ctx, sizes, base, type);
+               }
        }
        else if(ctx -> token == RECORD)
        {
                oberon_type_t * rec;
                rec = *type;
                rec -> class = OBERON_TYPE_RECORD;
-               oberon_object_t * list = malloc(sizeof *list);
-               memset(list, 0, sizeof *list);
-               rec -> num_decl = 0;
-               rec -> base = NULL;
-               rec -> decl = list;
+
+               oberon_scope_t * record_scope;
+               record_scope = oberon_open_scope(ctx);
+               // TODO parent object
+               //record_scope -> parent = NULL;
+               record_scope -> local = 1;
 
                oberon_assert_token(ctx, RECORD);
                oberon_field_list(ctx, rec);
@@ -1865,7 +2097,9 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
                }
                oberon_assert_token(ctx, END);
 
-               rec -> decl = rec -> decl -> next;
+               rec -> decl = record_scope -> list -> next;
+               oberon_close_scope(record_scope);
+
                *type = rec;
        }
        else if(ctx -> token == POINTER)
@@ -2148,6 +2382,17 @@ oberon_initialize_type(oberon_context_t * ctx, oberon_type_t * type)
        }
        else if(type -> class == OBERON_TYPE_ARRAY)
        {
+               if(type -> size != 0)
+               {
+                       if(type -> base -> class == OBERON_TYPE_ARRAY)
+                       {
+                               if(type -> base -> size == 0)
+                               {
+                                       oberon_error(ctx, "open array not allowed as array element");
+                               }
+                       }
+               }
+
                oberon_initialize_type(ctx, type -> base);              
                oberon_generator_init_type(ctx, type);
        }
@@ -2190,9 +2435,19 @@ oberon_initialize_object(oberon_context_t * ctx, oberon_object_t * x)
                        oberon_initialize_type(ctx, x -> type);
                        break;
                case OBERON_CLASS_VAR:
+               case OBERON_CLASS_FIELD:
+                       if(x -> type -> class == OBERON_TYPE_ARRAY)
+                       {
+                               if(x -> type -> size == 0)
+                               {
+                                       oberon_error(ctx, "open array not allowed as variable or field");
+                               }
+                       }
+                       oberon_initialize_type(ctx, x -> type);
+                       oberon_generator_init_var(ctx, x);
+                       break;
                case OBERON_CLASS_PARAM:
                case OBERON_CLASS_VAR_PARAM:
-               case OBERON_CLASS_FIELD:
                        oberon_initialize_type(ctx, x -> type);
                        oberon_generator_init_var(ctx, x);
                        break;
@@ -2284,6 +2539,11 @@ oberon_decl_seq(oberon_context_t * ctx)
 static void
 oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
 {
+       if(dst -> read_only)
+       {
+               oberon_error(ctx, "read-only destination");
+       }
+
        oberon_autocast_to(ctx, src, dst -> result);
        oberon_generate_assign(ctx, src, dst);
 }
@@ -2410,17 +2670,11 @@ oberon_parse_module(oberon_context_t * ctx)
        oberon_assert_token(ctx, SEMICOLON);
        ctx -> mod -> name = name1;
 
-       oberon_object_t * this_module;
-       this_module = oberon_define_object(ctx -> decl, name1, OBERON_CLASS_MODULE, 0, 0);
-       this_module -> module = ctx -> mod;
-
        if(ctx -> token == IMPORT)
        {
                oberon_import_list(ctx);
        }
 
-       ctx -> decl -> parent = this_module;
-
        oberon_decl_seq(ctx);
 
        oberon_generate_begin_module(ctx);
@@ -2456,10 +2710,13 @@ register_default_types(oberon_context_t * ctx)
        oberon_generator_init_type(ctx, ctx -> void_ptr_type);
 
        ctx -> int_type = oberon_new_type_integer(sizeof(int));
-       oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1, 0);
+       oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1);
 
-       ctx -> bool_type = oberon_new_type_boolean(sizeof(int));
-       oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1, 0);
+       ctx -> bool_type = oberon_new_type_boolean(sizeof(bool));
+       oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+
+       ctx -> real_type = oberon_new_type_real(sizeof(float));
+       oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1);
 }
 
 static void
@@ -2503,6 +2760,87 @@ oberon_make_abs_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
        return expr;
 }
 
+static void
+oberon_make_new_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args)
+{
+       if(num_args < 1)
+       {
+               oberon_error(ctx, "too few arguments");
+       }
+
+       oberon_expr_t * dst;
+       dst = list_args;
+
+       oberon_type_t * type;
+       type = dst -> result;
+
+       if(type -> class != OBERON_TYPE_POINTER)
+       {
+               oberon_error(ctx, "not a pointer");
+       }
+
+       type = type -> base;
+
+       oberon_expr_t * src;
+       src = oberon_new_item(MODE_NEW, dst -> result, 0);
+       src -> item.num_args = 0;
+       src -> item.args = NULL;
+
+       int max_args = 1;
+       if(type -> class == OBERON_TYPE_ARRAY)
+       {
+               if(type -> size == 0)
+               {
+                       oberon_type_t * x = type;
+                       while(x -> class == OBERON_TYPE_ARRAY)
+                       {
+                               if(x -> size == 0)
+                               {
+                                       max_args += 1;
+                               }
+                               x = x -> base;
+                       }
+               }
+
+               if(num_args < max_args)
+               {
+                       oberon_error(ctx, "too few arguments");
+               }
+
+               if(num_args > max_args)
+               {
+                       oberon_error(ctx, "too mach arguments");
+               }
+
+               int num_sizes = max_args - 1;
+               oberon_expr_t * size_list = list_args -> next;
+
+               oberon_expr_t * arg = size_list;
+               for(int i = 0; i < max_args - 1; i++)
+               {
+                       if(arg -> result -> class != OBERON_TYPE_INTEGER)
+                       {
+                               oberon_error(ctx, "size must be integer");
+                       }
+                       arg = arg -> next;
+               }
+
+               src -> item.num_args = num_sizes;
+               src -> item.args = size_list;
+       }
+       else if(type -> class != OBERON_TYPE_RECORD)
+       {
+               oberon_error(ctx, "oberon_make_new_call: wat");
+       }
+
+       if(num_args > max_args)
+       {
+               oberon_error(ctx, "too mach arguments");
+       }
+
+       oberon_assign(ctx, src, dst);
+}
+
 oberon_context_t *
 oberon_create_context(ModuleImportCallback import_module)
 {
@@ -2518,6 +2856,7 @@ oberon_create_context(ModuleImportCallback import_module)
 
        register_default_types(ctx);
        oberon_new_intrinsic(ctx, "ABS", oberon_make_abs_call, NULL);
+       oberon_new_intrinsic(ctx, "NEW", NULL, oberon_make_new_call);
 
        return ctx;
 }