diff --git a/src/oberon.c b/src/oberon.c
index 382f4f182b2e98ca1032a7f720cc575e58ae9fc5..6a74f92c0aad16f6a3b13a6053e3e5b58e145fcc 100644 (file)
--- a/src/oberon.c
+++ b/src/oberon.c
// UTILS
// =======================================================================
// UTILS
// =======================================================================
-void
+static void
oberon_error(oberon_context_t * ctx, const char * fmt, ...)
{
va_list ptr;
oberon_error(oberon_context_t * ctx, const char * fmt, ...)
{
va_list ptr;
}
static oberon_type_t *
}
static oberon_type_t *
-oberon_new_type_boolean(int size)
+oberon_new_type_boolean()
{
oberon_type_t * x;
x = oberon_new_type_ptr(OBERON_TYPE_BOOLEAN);
{
oberon_type_t * x;
x = oberon_new_type_ptr(OBERON_TYPE_BOOLEAN);
- x -> size = size;
return x;
}
return x;
}
if(scope -> up)
{
if(scope -> up)
{
- scope -> parent = scope -> up -> parent;
scope -> local = scope -> up -> local;
scope -> local = scope -> up -> local;
+ scope -> parent = scope -> up -> parent;
+ scope -> parent_type = scope -> up -> parent_type;
}
ctx -> decl = scope;
}
ctx -> decl = scope;
@@ -168,6 +168,7 @@ 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 -> read_only = read_only;
newvar -> local = scope -> local;
newvar -> parent = scope -> parent;
+ newvar -> parent_type = scope -> parent_type;
newvar -> module = scope -> ctx -> mod;
x -> next = newvar;
newvar -> module = scope -> ctx -> mod;
x -> next = newvar;
memcpy(ident, &ctx -> code[start_i], len);
ident[len] = 0;
memcpy(ident, &ctx -> code[start_i], len);
ident[len] = 0;
+ ctx -> longmode = false;
if(mode == 3)
{
int i = exp_i - start_i;
ident[i] = 'E';
if(mode == 3)
{
int i = exp_i - start_i;
ident[i] = 'E';
+ ctx -> longmode = true;
}
switch(mode)
}
switch(mode)
@@ -764,26 +767,87 @@ oberon_expr_list(oberon_context_t * ctx, int * num_expr, oberon_expr_t ** first,
}
}
}
}
+static oberon_expr_t *
+oberon_cast_expr(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
+{
+ oberon_expr_t * cast;
+ cast = oberon_new_item(MODE_CAST, pref, expr -> read_only);
+ cast -> item.parent = expr;
+ cast -> next = expr -> next;
+ return cast;
+}
+
+static oberon_type_t *
+oberon_get_equal_expr_type(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b)
+{
+ oberon_type_t * result;
+ if(a -> class == OBERON_TYPE_REAL && b -> class == OBERON_TYPE_INTEGER)
+ {
+ result = a;
+ }
+ else if(b -> class == OBERON_TYPE_REAL && a -> class == OBERON_TYPE_INTEGER)
+ {
+ result = b;
+ }
+ else if(a -> class != b -> class)
+ {
+ oberon_error(ctx, "oberon_get_equal_expr_type: incompatible types");
+ }
+ else if(a -> size > b -> size)
+ {
+ result = a;
+ }
+ else
+ {
+ result = b;
+ }
+
+ return result;
+}
+
static oberon_expr_t *
oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
{
if(pref -> class != expr -> result -> class)
{
static oberon_expr_t *
oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
{
if(pref -> class != expr -> result -> class)
{
- if(pref -> class != OBERON_TYPE_PROCEDURE)
+ if(pref -> class == OBERON_TYPE_POINTER)
{
{
- if(expr -> result -> class != OBERON_TYPE_POINTER)
+ if(expr -> result -> class == OBERON_TYPE_POINTER)
+ {
+ // accept
+ }
+ else
{
oberon_error(ctx, "incompatible types");
}
}
{
oberon_error(ctx, "incompatible types");
}
}
+ else if(pref -> class == OBERON_TYPE_REAL)
+ {
+ if(expr -> result -> class == OBERON_TYPE_INTEGER)
+ {
+ // accept
+ }
+ else
+ {
+ oberon_error(ctx, "incompatible types");
+ }
+ }
+ else
+ {
+ oberon_error(ctx, "incompatible types");
+ }
}
}
- if(pref -> class == OBERON_TYPE_INTEGER)
+ if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL)
{
{
- if(expr -> result -> class > pref -> class)
+ if(expr -> result -> size > pref -> size)
{
oberon_error(ctx, "incompatible size");
}
{
oberon_error(ctx, "incompatible size");
}
+ else
+ {
+ expr = oberon_cast_expr(ctx, expr, pref);
+ }
}
else if(pref -> class == OBERON_TYPE_RECORD)
{
}
else if(pref -> class == OBERON_TYPE_RECORD)
{
@@ -804,11 +868,19 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
}
}
}
}
- // TODO cast
-
return expr;
}
return expr;
}
+static void
+oberon_autocast_binary_op(oberon_context_t * ctx, oberon_expr_t ** ea, oberon_expr_t ** eb)
+{
+ oberon_type_t * a = (*ea) -> result;
+ oberon_type_t * b = (*eb) -> result;
+ oberon_type_t * preq = oberon_get_equal_expr_type(ctx, a, b);
+ *ea = oberon_autocast_to(ctx, *ea, preq);
+ *eb = oberon_autocast_to(ctx, *eb, preq);
+}
+
static void
oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
{
static void
oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
{
oberon_error(ctx, "too many arguments");
}
oberon_error(ctx, "too many arguments");
}
+ /* Делаем проверку на запись и делаем автокаст */
+ oberon_expr_t * casted[num_args];
oberon_expr_t * arg = desig -> item.args;
oberon_object_t * param = fn -> decl;
for(int i = 0; i < num_args; i++)
oberon_expr_t * arg = desig -> item.args;
oberon_object_t * param = fn -> decl;
for(int i = 0; i < num_args; i++)
{
oberon_error(ctx, "assign to read-only var");
}
{
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);
+ casted[i] = oberon_autocast_to(ctx, arg, param -> type);
arg = arg -> next;
param = param -> next;
}
arg = arg -> next;
param = param -> next;
}
+
+ /* Создаём новый список выражений */
+ if(num_args > 0)
+ {
+ arg = casted[0];
+ for(int i = 0; i < num_args - 1; i++)
+ {
+ casted[i] -> next = casted[i + 1];
+ }
+ desig -> item.args = arg;
+ }
}
static oberon_expr_t *
}
static oberon_expr_t *
oberon_expr_t * selector;
selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only);
oberon_expr_t * selector;
selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only);
- selector -> item.parent = (oberon_item_t *) expr;
+ selector -> item.parent = expr;
return selector;
}
return selector;
}
@@ -1044,7 +1114,7 @@ oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, oberon
oberon_expr_t * selector;
selector = oberon_new_item(MODE_INDEX, base, desig -> read_only);
oberon_expr_t * selector;
selector = oberon_new_item(MODE_INDEX, base, desig -> read_only);
- selector -> item.parent = (oberon_item_t *) desig;
+ selector -> item.parent = desig;
selector -> item.num_args = 1;
selector -> item.args = index;
selector -> item.num_args = 1;
selector -> item.args = index;
@@ -1091,7 +1161,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
oberon_expr_t * selector;
selector = oberon_new_item(MODE_FIELD, field -> type, read_only);
selector -> item.var = field;
oberon_expr_t * selector;
selector = oberon_new_item(MODE_FIELD, field -> type, read_only);
selector -> item.var = field;
- selector -> item.parent = (oberon_item_t *) expr;
+ selector -> item.parent = expr;
return selector;
}
return selector;
}
oberon_make_call_proc(ctx, expr -> item.var, num_args, arguments);
}
oberon_make_call_proc(ctx, expr -> item.var, num_args, arguments);
}
+static oberon_type_t *
+oberon_get_type_of_int_value(oberon_context_t * ctx, int64_t i)
+{
+ if(i >= -128 && i <= 127)
+ {
+ return ctx -> byte_type;
+ }
+ else if(i >= -32768 && i <= 32767)
+ {
+ return ctx -> shortint_type;
+ }
+ else if(i >= -2147483648 && i <= 2147483647)
+ {
+ return ctx -> int_type;
+ }
+ else
+ {
+ return ctx -> longint_type;
+ }
+}
+
static oberon_expr_t *
oberon_factor(oberon_context_t * ctx)
{
oberon_expr_t * expr;
static oberon_expr_t *
oberon_factor(oberon_context_t * ctx)
{
oberon_expr_t * expr;
+ oberon_type_t * result;
switch(ctx -> token)
{
switch(ctx -> token)
{
expr = oberon_opt_func_parens(ctx, expr);
break;
case INTEGER:
expr = oberon_opt_func_parens(ctx, expr);
break;
case INTEGER:
- expr = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1);
+ result = oberon_get_type_of_int_value(ctx, ctx -> integer);
+ expr = oberon_new_item(MODE_INTEGER, result, 1);
expr -> item.integer = ctx -> integer;
oberon_assert_token(ctx, INTEGER);
break;
case REAL:
expr -> item.integer = ctx -> integer;
oberon_assert_token(ctx, INTEGER);
break;
case REAL:
- expr = oberon_new_item(MODE_REAL, ctx -> real_type, 1);
+ result = (ctx -> longmode) ? (ctx -> longreal_type) : (ctx -> real_type);
+ expr = oberon_new_item(MODE_REAL, result, 1);
expr -> item.real = ctx -> real;
oberon_assert_token(ctx, REAL);
break;
case TRUE:
expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
expr -> item.real = ctx -> real;
oberon_assert_token(ctx, REAL);
break;
case TRUE:
expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
- expr -> item.boolean = 1;
+ expr -> item.boolean = true;
oberon_assert_token(ctx, TRUE);
break;
case FALSE:
expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
oberon_assert_token(ctx, TRUE);
break;
case FALSE:
expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
- expr -> item.boolean = 0;
+ expr -> item.boolean = false;
oberon_assert_token(ctx, FALSE);
break;
case LPAREN:
oberon_assert_token(ctx, FALSE);
break;
case LPAREN:
return expr;
}
return expr;
}
-/*
- * oberon_autocast_binary_op автоматически переобразовывеат тип по след. правилам:
- * 1. Классы обоих типов должны быть одинаковы
- * 2. В качестве результата должен быть выбран больший тип.
- * 3. Если размер результат не должен быть меньше чем базовый int
- */
-
-static void
-oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b, oberon_type_t ** result)
-{
- if((a -> class) != (b -> class))
- {
- oberon_error(ctx, "incompatible types");
- }
-
- if((a -> size) > (b -> size))
- {
- *result = a;
- }
- else
- {
- *result = b;
- }
-
- if(((*result) -> class) == OBERON_TYPE_INTEGER)
- {
- if(((*result) -> size) < (ctx -> int_type -> size))
- {
- *result = ctx -> int_type;
- }
- }
-
- /* TODO: cast types */
-}
-
#define ITMAKESBOOLEAN(x) \
(((x) >= EQUAL && (x) <= GEQ) || ((x) == OR) || ((x) == AND))
#define ITMAKESBOOLEAN(x) \
(((x) >= EQUAL && (x) <= GEQ) || ((x) == OR) || ((x) == AND))
@@ -1352,6 +1411,27 @@ oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type
#define ITUSEONLYBOOLEAN(x) \
(((x) == OR) || ((x) == AND))
#define ITUSEONLYBOOLEAN(x) \
(((x) == OR) || ((x) == AND))
+static void
+oberon_autocast_to_real(oberon_context_t * ctx, oberon_expr_t ** e)
+{
+ oberon_expr_t * expr = *e;
+ if(expr -> result -> class == OBERON_TYPE_INTEGER)
+ {
+ if(expr -> result -> size <= ctx -> real_type -> size)
+ {
+ *e = oberon_cast_expr(ctx, expr, ctx -> real_type);
+ }
+ else
+ {
+ *e = oberon_cast_expr(ctx, expr, ctx -> longreal_type);
+ }
+ }
+ else if(expr -> result -> class != OBERON_TYPE_REAL)
+ {
+ oberon_error(ctx, "required numeric type");
+ }
+}
+
static oberon_expr_t *
oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
{
static oberon_expr_t *
oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
{
@@ -1362,10 +1442,12 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
{
if(ITUSEONLYINTEGER(token))
{
{
if(ITUSEONLYINTEGER(token))
{
- if(a -> result -> class != OBERON_TYPE_INTEGER
- || b -> result -> class != OBERON_TYPE_INTEGER)
+ if(a -> result -> class == OBERON_TYPE_INTEGER
+ || b -> result -> class == OBERON_TYPE_INTEGER
+ || a -> result -> class == OBERON_TYPE_REAL
+ || b -> result -> class == OBERON_TYPE_REAL)
{
{
- oberon_error(ctx, "used only with integer types");
+ oberon_error(ctx, "used only with numeric types");
}
}
else if(ITUSEONLYBOOLEAN(token))
}
}
else if(ITUSEONLYBOOLEAN(token))
@@ -1377,6 +1459,7 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
}
}
}
}
+ oberon_autocast_binary_op(ctx, &a, &b);
result = ctx -> bool_type;
if(token == EQUAL)
result = ctx -> bool_type;
if(token == EQUAL)
@@ -1418,32 +1501,10 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
}
else if(token == SLASH)
{
}
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);
+ 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);
}
else if(token == DIV)
{
}
else if(token == DIV)
{
@@ -1453,28 +1514,28 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
oberon_error(ctx, "operator DIV requires integer type");
}
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);
+ oberon_autocast_binary_op(ctx, &a, &b);
+ expr = oberon_new_operator(OP_DIV, a -> result, a, b);
}
else
{
}
else
{
- oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+ oberon_autocast_binary_op(ctx, &a, &b);
if(token == PLUS)
{
if(token == PLUS)
{
- expr = oberon_new_operator(OP_ADD, result, a, b);
+ expr = oberon_new_operator(OP_ADD, a -> result, a, b);
}
else if(token == MINUS)
{
}
else if(token == MINUS)
{
- expr = oberon_new_operator(OP_SUB, result, a, b);
+ expr = oberon_new_operator(OP_SUB, a -> result, a, b);
}
else if(token == STAR)
{
}
else if(token == STAR)
{
- expr = oberon_new_operator(OP_MUL, result, a, b);
+ expr = oberon_new_operator(OP_MUL, a -> result, a, b);
}
else if(token == MOD)
{
}
else if(token == MOD)
{
- expr = oberon_new_operator(OP_MOD, result, a, b);
+ expr = oberon_new_operator(OP_MOD, a -> result, a, b);
}
else
{
}
else
{
}
expr = oberon_term_expr(ctx);
}
expr = oberon_term_expr(ctx);
+
+ if(minus)
+ {
+ expr = oberon_make_unary_op(ctx, MINUS, expr);
+ }
+
while(ISADDOP(ctx -> token))
{
int token = ctx -> token;
while(ISADDOP(ctx -> token))
{
int token = ctx -> token;
expr = oberon_make_bin_op(ctx, token, expr, inter);
}
expr = oberon_make_bin_op(ctx, token, expr, inter);
}
- if(minus)
- {
- expr = oberon_make_unary_op(ctx, MINUS, expr);
- }
-
return expr;
}
return expr;
}
oberon_error(ctx, "procedure requires expression on result");
}
oberon_error(ctx, "procedure requires expression on result");
}
- oberon_autocast_to(ctx, expr, result_type);
+ expr = oberon_autocast_to(ctx, expr, result_type);
}
proc -> has_return = 1;
}
proc -> has_return = 1;
oberon_scope_t * record_scope;
record_scope = oberon_open_scope(ctx);
oberon_scope_t * record_scope;
record_scope = oberon_open_scope(ctx);
- // TODO parent object
- //record_scope -> parent = NULL;
record_scope -> local = 1;
record_scope -> local = 1;
+ record_scope -> parent = NULL;
+ record_scope -> parent_type = rec;
oberon_assert_token(ctx, RECORD);
oberon_field_list(ctx, rec);
oberon_assert_token(ctx, RECORD);
oberon_field_list(ctx, rec);
@@ -2198,7 +2260,8 @@ oberon_prevent_recursive_pointer(oberon_context_t * ctx, oberon_type_t * type)
oberon_error(ctx, "recursive pointer declaration");
}
oberon_error(ctx, "recursive pointer declaration");
}
- if(type -> base -> class == OBERON_TYPE_POINTER)
+ if(type -> class == OBERON_TYPE_POINTER
+ && type -> base -> class == OBERON_TYPE_POINTER)
{
oberon_error(ctx, "attempt to make pointer to pointer");
}
{
oberon_error(ctx, "attempt to make pointer to pointer");
}
@@ -2547,7 +2610,7 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
oberon_error(ctx, "read-only destination");
}
oberon_error(ctx, "read-only destination");
}
- oberon_autocast_to(ctx, src, dst -> result);
+ src = oberon_autocast_to(ctx, src, dst -> result);
oberon_generate_assign(ctx, src, dst);
}
oberon_generate_assign(ctx, src, dst);
}
{
oberon_error(ctx, "module name not matched");
}
{
oberon_error(ctx, "module name not matched");
}
+
+ oberon_generator_fini_module(ctx -> mod);
}
// =======================================================================
}
// =======================================================================
ctx -> void_ptr_type -> base = ctx -> void_type;
oberon_generator_init_type(ctx, ctx -> void_ptr_type);
ctx -> void_ptr_type -> base = ctx -> void_type;
oberon_generator_init_type(ctx, ctx -> void_ptr_type);
- ctx -> int_type = oberon_new_type_integer(sizeof(int));
+ ctx -> bool_type = oberon_new_type_boolean();
+ oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+
+ ctx -> byte_type = oberon_new_type_integer(1);
+ oberon_define_type(ctx -> world_scope, "BYTE", ctx -> byte_type, 1);
+
+ ctx -> shortint_type = oberon_new_type_integer(2);
+ oberon_define_type(ctx -> world_scope, "SHORTINT", ctx -> shortint_type, 1);
+
+ ctx -> int_type = oberon_new_type_integer(4);
oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1);
oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1);
- ctx -> bool_type = oberon_new_type_boolean(sizeof(bool));
- oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+ ctx -> longint_type = oberon_new_type_integer(8);
+ oberon_define_type(ctx -> world_scope, "LONGINT", ctx -> longint_type, 1);
- ctx -> real_type = oberon_new_type_real(sizeof(float));
+ ctx -> real_type = oberon_new_type_real(4);
oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1);
oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1);
+
+ ctx -> longreal_type = oberon_new_type_real(8);
+ oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1);
}
static void
}
static void
int token = ctx -> token;
char * string = ctx -> string;
int integer = ctx -> integer;
int token = ctx -> token;
char * string = ctx -> string;
int integer = ctx -> integer;
+ int real = ctx -> real;
+ bool longmode = ctx -> longmode;
oberon_scope_t * decl = ctx -> decl;
oberon_module_t * mod = ctx -> mod;
oberon_scope_t * decl = ctx -> decl;
oberon_module_t * mod = ctx -> mod;
ctx -> token = token;
ctx -> string = string;
ctx -> integer = integer;
ctx -> token = token;
ctx -> string = string;
ctx -> integer = integer;
+ ctx -> real = real;
+ ctx -> longmode = longmode;
ctx -> decl = decl;
ctx -> mod = mod;
ctx -> decl = decl;
ctx -> mod = mod;