summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: eaa8fd7)
raw | patch | inline | side by side (parent: eaa8fd7)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 30 Jul 2017 13:59:34 +0000 (16:59 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 30 Jul 2017 13:59:34 +0000 (16:59 +0300) |
jvm_test.sh | patch | blob | history | |
notes | patch | blob | history | |
rtl/Out.java | patch | blob | history | |
src/backends/jvm/generator-jvm.c | patch | blob | history | |
src/oberon-internals.h | patch | blob | history | |
src/oberon.c | patch | blob | history | |
src/test.c | patch | blob | history |
diff --git a/jvm_test.sh b/jvm_test.sh
index 0c94910fd7632fb183005bdb9c157990d5bfad51..6519656ef1f13317b42551fb8e3b63bf9a35f1cc 100755 (executable)
--- a/jvm_test.sh
+++ b/jvm_test.sh
set -e
./make.sh jvm
-./run.sh
rm -rf classes
+rm -f *.j *.jad
mkdir -p classes
+
+./run.sh
+
javac -d classes Launcher.java
jasmin -d classes *.j
index 2cfcb16fd6c024c7bd3df454f5e55456851fa8f7..79510a02b93db54f93aee3d4508dd2a6391e10d1 100644 (file)
--- a/notes
+++ b/notes
- Нужно изменить передачу информации о вызываемой процедуре в MODE_CALL
На данный момент конкретная процедура передаётся в поле var, вместо parent
Что не позволяет делать процедуры-переменные в полях записей, массивах и т.д.
-- Ð\9dÑ\83жнÑ\8b Ñ\81Ñ\80едÑ\81Ñ\82ва Ñ\81озданиÑ\8f биндингов. ХоÑ\82Ñ\8f бÑ\8b как заглушки для модулей.
+- Ð\9dÑ\83жнÑ\8b Ñ\81Ñ\80едÑ\81Ñ\82ва Ñ\81озданиÑ\8f биндингов. Ð\9dа даннÑ\8bй моменÑ\82 Ñ\80еализÑ\83емо как заглушки для модулей.
- нужен автокаст int -> real для DIV. Да и вообще каст типов.
- нет символов и строк
diff --git a/rtl/Out.java b/rtl/Out.java
index ca773d2c167f858dc7def8fd7d72977e57233791..309578afe881cccdb7078a6bc2cdca151fcb0bf8 100644 (file)
--- a/rtl/Out.java
+++ b/rtl/Out.java
}
- public static void Int(int i, int n)
+ public static void Int(long i, long n)
{
System.out.print(i);
}
System.out.print(x);
}
+ public static void LongReal(double x, int n)
+ {
+ System.out.print(x);
+ }
+
public static void Ln()
{
System.out.println();
index 497b99ed278453c093a55685c29b1ceae6b523e4..1225a86a23b4a0f1479b6a8fc0a0265b574a654b 100644 (file)
va_end(ptr);
}
+static void
+jvm_generate_comment(gen_proc_t * p, char * format, ...)
+{
+ va_list ptr;
+ va_start(ptr, format);
+
+ fprintf(p -> class -> fp, " ;;;; ");
+ vfprintf(p -> class -> fp, format, ptr);
+ fprintf(p -> class -> fp, "\n");
+
+ va_end(ptr);
+}
+
static void
jvm_generate_push_int(gen_proc_t * p, int64_t i)
{
}
}
+static void
+jvm_generate_push_int_size(gen_proc_t * p, int64_t i, int size)
+{
+ int pushed_cell = 1;
+
+ if(i == -1)
+ {
+ jvm_generate(p, 0, 1, "iconst_m1");
+ }
+ else if(i >= 0 && i <= 5)
+ {
+ jvm_generate(p, 0, 1, "iconst_%li", i);
+ }
+ else if(i >= -128 && i <= 127)
+ {
+ jvm_generate(p, 0, 1, "bipush %li", i);
+ }
+ else if(i >= -32768 && i <= 32767)
+ {
+ jvm_generate(p, 0, 1, "sipush %li", i);
+ }
+ else if(i >= -2147483648 && i <= 2147483647)
+ {
+ jvm_generate(p, 0, 1, "ldc %li", i);
+ }
+ else
+ {
+ pushed_cell = 2;
+ jvm_generate(p, 0, 2, "ldc2 %li", i);
+ }
+
+ assert(size <= 8);
+ if(size > 4 && pushed_cell == 1)
+ {
+ jvm_generate(p, pushed_cell, 2, "i2l");
+ }
+ else if(size <= 4)
+ {
+ if(pushed_cell > 1)
+ {
+ jvm_generate(p, 2, 1, "l2i");
+ }
+
+ if(size == 2)
+ {
+ jvm_generate(p, 1, 1, "i2s");
+ }
+ else if(size == 1)
+ {
+ jvm_generate(p, 1, 1, "i2b");
+ }
+ }
+}
+
static void
jvm_generate_push_float(gen_proc_t * p, double f, int size)
{
@@ -1229,6 +1296,24 @@ jvm_generate_expr_new_pointer(gen_proc_t * p, oberon_type_t * type, int num, obe
jvm_generate_new(p, type -> base, num);
}
+static void
+jvm_generate_cast_type(gen_proc_t * p, oberon_type_t * from, oberon_type_t * to)
+{
+ char prefix = jvm_get_prefix(from);
+ char postfix = jvm_get_postfix(to);
+ int from_cell_size = jvm_cell_size_for_type(from);
+ int to_cell_size = jvm_cell_size_for_type(to);
+
+ jvm_generate_comment(p, "cast type class from %i(%i) to %i(%i)", from -> class, from -> size, to -> class, to -> size);
+
+ if(prefix == postfix)
+ {
+ return;
+ }
+
+ jvm_generate(p, from_cell_size, to_cell_size, "%c2%c", prefix, postfix);
+}
+
static void
push_item(gen_proc_t * p, oberon_item_t * item)
{
}
break;
case MODE_INTEGER:
- jvm_generate_push_int(p, item -> integer);
+ jvm_generate_push_int_size(p, item -> integer, item -> result -> size);
break;
case MODE_BOOLEAN:
- jvm_generate_push_int(p, item -> boolean);
+ jvm_generate_push_int_size(p, item -> boolean, item -> result -> size);
break;
case MODE_CALL:
jvm_generate_call_proc(p, (oberon_expr_t *) item);
case MODE_REAL:
jvm_generate_push_float(p, item -> real, item -> result -> size);
break;
+ case MODE_CAST:
+ push_item(p, item -> parent);
+ jvm_generate_cast_type(p, item -> parent -> result, item -> result);
+ break;
default:
gen_error("push_item: unk mode %i", item -> mode);
break;
diff --git a/src/oberon-internals.h b/src/oberon-internals.h
index ac6b6959ff7799fb2d3a0ed35576fce40dd99ac8..b01a1d71958aa8e43cd9a4b10190291b8357802f 100644 (file)
--- a/src/oberon-internals.h
+++ b/src/oberon-internals.h
#ifndef OBERON_INTERNALS_H
#define OBERON_INTERNALS_H
+#include <stdint.h>
+#include <stdbool.h>
+
typedef struct gen_module_t gen_module_t;
typedef struct gen_proc_t gen_proc_t;
typedef struct gen_type_t gen_type_t;
char c;
int token;
char * string;
- long integer;
+ int64_t integer;
double real;
+ bool longmode;
/*** END SCANER DATA ***/
/*** PARSER DATA ***/
oberon_module_t * mod;
/*** END PARSER DATA ***/
- oberon_type_t * int_type;
oberon_type_t * bool_type;
+ oberon_type_t * byte_type;
+ oberon_type_t * shortint_type;
+ oberon_type_t * int_type;
+ oberon_type_t * longint_type;
oberon_type_t * real_type;
+ oberon_type_t * longreal_type;
oberon_type_t * void_type;
oberon_type_t * void_ptr_type;
+
oberon_scope_t * world_scope;
oberon_module_t * module_list;
ModuleImportCallback import_module;
MODE_DEREF,
MODE_NIL,
MODE_NEW,
- MODE_REAL
+ MODE_REAL,
+ MODE_CAST
};
enum
diff --git a/src/oberon.c b/src/oberon.c
index 251a7df597c9887a7d2d319940bc99d70a812c35..8de42d912fbb0ed03442b54072db6e353316d594 100644 (file)
--- a/src/oberon.c
+++ b/src/oberon.c
}
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);
- x -> size = size;
return x;
}
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';
+ ctx -> longmode = true;
}
switch(mode)
@@ -766,26 +767,88 @@ 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)
+{
+ assert(expr -> is_item);
+ oberon_expr_t * cast;
+ cast = oberon_new_item(MODE_CAST, pref, expr -> read_only);
+ cast -> item.parent = (oberon_item_t *) 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)
{
- 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");
+ }
+ }
+ 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");
}
+ else
+ {
+ expr = oberon_cast_expr(ctx, expr, pref);
+ }
}
else if(pref -> class == OBERON_TYPE_RECORD)
{
@@ -806,11 +869,19 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
}
}
- // TODO cast
-
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)
{
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_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;
}
+
+ /* Создаём новый список выражений */
+ 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 *
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;
+ oberon_type_t * result;
switch(ctx -> token)
{
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 = 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.boolean = 1;
+ expr -> item.boolean = true;
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:
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))
@@ -1444,8 +1502,8 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
}
}
- 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 if(token == DIV)
{
@@ -1455,28 +1513,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_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
{
- oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+ oberon_autocast_binary_op(ctx, &a, &b);
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)
{
- expr = oberon_new_operator(OP_SUB, result, a, b);
+ expr = oberon_new_operator(OP_SUB, a -> result, a, b);
}
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)
{
- expr = oberon_new_operator(OP_MOD, result, a, b);
+ expr = oberon_new_operator(OP_MOD, a -> result, a, b);
}
else
{
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;
@@ -2551,7 +2609,7 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
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);
}
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);
- 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);
+
+ ctx -> longreal_type = oberon_new_type_real(8);
+ oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1);
}
static void
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;
ctx -> token = token;
ctx -> string = string;
ctx -> integer = integer;
+ ctx -> real = real;
+ ctx -> longmode = longmode;
ctx -> decl = decl;
ctx -> mod = mod;
diff --git a/src/test.c b/src/test.c
index 5939fb6d50dd5dafe933c31cdab8e73a27d37b0d..2c5fb0462c6cb482a0d66fbd593af3fa4f85f5d8 100644 (file)
--- a/src/test.c
+++ b/src/test.c
"(* Main module *)"
"MODULE Test;"
"IMPORT Out;"
- "TYPE"
- " P = PROCEDURE;"
- " F = PROCEDURE (x : INTEGER) : INTEGER;"
""
"VAR"
- " p : P;"
- " f : F;"
- " i : INTEGER;"
+ " byte : BYTE;"
+ " short : SHORTINT;"
+ " int : INTEGER;"
+ " long : LONGINT;"
+ " real : REAL;"
+ " longreal : LONGREAL;"
""
- "PROCEDURE Pow(x : INTEGER) : INTEGER;"
"BEGIN"
- " RETURN x * x;"
- "END Pow;"
- ""
- "PROCEDURE Do;"
- "END Do;"
- ""
- "BEGIN;"
- " p := Do;"
- " f := Pow;"
- " i := f(7);"
- " p;"
" Out.Open;"
- " Out.Int(i, 0); Out.Ln;"
+ " byte := 127;"
+ " int := 666;"
+ " long := int;"
+ " real := int;"
+ " longreal := int;"
" Out.Int(666, 0); Out.Ln;"
+ " Out.Int(byte, 0); Out.Ln;"
+ " Out.LongReal(real, 0); Out.Ln;"
"END Test."
;
// PROCEDURE Char* (ch : CHAR);
// PROCEDURE String* (str : ARRAY OF CHAR);
-// PROCEDURE Int* (i, n : LONGINT); // Должно быть в таком виде
-// PROCEDURE LongReal* (x : LONGREAL; n : INTEGER);
static char source_out[] =
"MODULE Out;"
" PROCEDURE Open*;"
" END Open;"
""
- " PROCEDURE Int*(i, n : INTEGER);"
+ " PROCEDURE Int*(i, n : LONGINT);"
" END Int;"
""
" PROCEDURE Real*(x : REAL; n : INTEGER);"
" END Real;"
""
+ " PROCEDURE LongReal*(x : LONGREAL; n : INTEGER);"
+ " END LongReal;"
+ ""
" PROCEDURE Ln*;"
" END Ln;"
""