summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 19dd806)
raw | patch | inline | side by side (parent: 19dd806)
author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 13 Aug 2017 07:40:37 +0000 (10:40 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Sun, 13 Aug 2017 07:40:37 +0000 (10:40 +0300) |
12 files changed:
Test.obn | patch | blob | history | |
Test10.obn | patch | blob | history | |
Test11.obn | patch | blob | history | |
Test12.obn | [new file with mode: 0644] | patch | blob |
Test13.obn | [new file with mode: 0644] | patch | blob |
Test7.obn | patch | blob | history | |
notes | patch | blob | history | |
obn-run-tests.sh | patch | blob | history | |
src/backends/jvm/generator-jvm.c | patch | blob | history | |
src/oberon-internals.h | patch | blob | history | |
src/oberon-type-compat.h | patch | blob | history | |
src/oberon.c | patch | blob | history |
diff --git a/Test.obn b/Test.obn
index 8371d40d26dc72bcfbac718753e7ba1e333de80b..babecff95eba9648125ff9e686de586d643d366e 100644 (file)
--- a/Test.obn
+++ b/Test.obn
MODULE Test;
-IMPORT Out;
-
-CONST
- im1 = -1;
- bol = ~FALSE;
- set = { 1, 2, 3..6 };
- fm1 = -1.0;
- dm1 = -1.0D0;
-
BEGIN
- Out.Open;
-
- Out.Int(im1, 0); Out.Ln;
- Out.Real(fm1, 0); Out.Ln;
- Out.LongReal(dm1, 0); Out.Ln;
-
- IF 5 IN set THEN
- Out.String("SET: Ok"); Out.Ln;
- ELSE
- Out.String("INVALID SET"); Out.Ln;
- HALT(1);
- END;
-
- IF bol THEN
- Out.String("BOOLEAN: Ok"); Out.Ln;
- ELSE
- Out.String("INVALID BOOLEAN"); Out.Ln;
- HALT(1);
- END;
+ ASSERT(ODD(5));
END Test.
diff --git a/Test10.obn b/Test10.obn
index 89dbcfd2f83a2e1d89937f8760d6dcab388e505c..08dd56c3aa1f2e8428324f8ac83322028a0397a5 100644 (file)
--- a/Test10.obn
+++ b/Test10.obn
MODULE Test10;
-IMPORT Out;
-
BEGIN
- IF "abc" = "abc" THEN
- Out.String("Equal abc = abc"); Out.Ln;
- ELSE
- Out.String("WAT: MUST BE abc = abc"); Out.Ln;
- HALT(1);
- END;
-
- IF "cba" > "abc" THEN
- Out.String("Great cba > abc"); Out.Ln;
- ELSE
- Out.String("WAT: MUST BE cba = abc"); Out.Ln;
- HALT(1);
- END;
-
- IF "abc" < "bc" THEN
- Out.String("Less abc < bc"); Out.Ln;
- ELSE
- Out.String("WAT: MUST BE abc < bc"); Out.Ln;
- HALT(1);
- END;
+ ASSERT("abc" = "abc");
+ ASSERT("abcz" # "abcd");
+ ASSERT("cba" > "abc");
+ ASSERT("abc" < "bc");
END Test10.
-Проверка строк.
+Ð\9fÑ\80овеÑ\80ка Ñ\81Ñ\80авнениÑ\8f Ñ\81Ñ\82Ñ\80ок.
diff --git a/Test11.obn b/Test11.obn
index 847fddfb9dcdf2b6a41579d0e2b995af2861f581..aba8cb4bae1d18d664dc202f963784ab443d51d2 100644 (file)
--- a/Test11.obn
+++ b/Test11.obn
Out.Real(pi, 0); Out.Ln;
- IF 5 IN set THEN
- Out.String("SET: Ok"); Out.Ln;
- ELSE
- Out.String("INVALID SET"); Out.Ln;
- HALT(1);
- END;
-
- IF bol THEN
- Out.String("BOOLEAN: Ok"); Out.Ln;
- ELSE
- Out.String("INVALID BOOLEAN"); Out.Ln;
- HALT(1);
- END;
+ ASSERT(5 IN set);
+ ASSERT(bol);
END Test11.
Проверка свёртки констант.
diff --git a/Test12.obn b/Test12.obn
--- /dev/null
+++ b/Test12.obn
@@ -0,0 +1,19 @@
+MODULE Test12;
+
+CONST
+ icon = 32;
+ ash1 = ASH(icon, -5);
+ ash2 = ASH(icon, 5);
+
+VAR
+ i : INTEGER;
+
+BEGIN
+ i := icon;
+ ASSERT(ash1 = 1);
+ ASSERT(ash2 = 1024);
+ ASSERT(ASH(i, -5) = 1);
+ ASSERT(ASH(i, 5) = 1024);
+END Test12.
+
+Проверка правильности вычисления ASH.
diff --git a/Test13.obn b/Test13.obn
--- /dev/null
+++ b/Test13.obn
@@ -0,0 +1,13 @@
+MODULE Test13;
+
+VAR
+ ch, cap, res : CHAR;
+
+BEGIN
+ ch := "a";
+ cap := "A";
+ res := CAP(ch);
+ ASSERT(res = cap);
+END Test13.
+
+Проверка функции CAP
diff --git a/Test7.obn b/Test7.obn
index 7579867ca572312f8f4945516f7d4dbed0d1d0d4..e3613e4e53d70fc7e9db3bbc058b3aada74dbb77 100644 (file)
--- a/Test7.obn
+++ b/Test7.obn
END;
Out.Ln;
- IF ok = FALSE THEN
- HALT(1);
- END;
+ ASSERT(ok);
END Test7.
Проверка корректности FOR.
index cf12913f25bfb136d5410fa6e51a6dc266fbb4d2..a6270d01e235a696b420c02896614ec5f4fb0548 100644 (file)
--- a/notes
+++ b/notes
- Сделать проверку повторов в CASE.
- Сделать нормальную проверку наличия RETURN.
-- Нет функций ASH CAP CHR ENTIER LEN LONG ODD ORD SHORT
+- Нет функций CHR ENTIER LEN LONG ORD SHORT
- Нет процедур DEC EXCL INC INCL
- Нет счёта строк / столбцов
- Нет процедур привязанных к типм
diff --git a/obn-run-tests.sh b/obn-run-tests.sh
index f483e01a2634ae6574da0e2a8ed8e7f4c00fc374..0c0e0922d08a99eb1658597b4a2b17c0bcf62093 100755 (executable)
--- a/obn-run-tests.sh
+++ b/obn-run-tests.sh
maketest Test9
maketest Test10
maketest Test11
+maketest Test12
+maketest Test13
index ee4bc67c17d31f33f25ba5047600658776953755..c2fd9abd4662bef894b32ae159650e7cdcb4baa2 100644 (file)
case OP_ABS:
jvm_generate_abs(p, prefix);
break;
+ case OP_CAP:
+ jvm_generate(p, cell_size, cell_size, "invokestatic java/lang/Character/toUpperCase(I)I");
+ break;
case OP_ADD:
jvm_generate(p, 2 * cell_size, cell_size, "%cadd", prefix);
jvm_generate_label(p, label_end);
}
+static void
+jvm_generate_ash(gen_proc_t * p, oberon_expr_t * a, oberon_expr_t * b)
+{
+ oberon_type_t * t = a -> result;
+ int cell_size = jvm_cell_size_for_type(t);
+ char prefix = jvm_get_prefix(t);
+ int label_else = jvm_new_label_id(p);
+ int label_end = jvm_new_label_id(p);
+
+ /* if b < 0 then a << b else a >> b end */
+
+ push_expr(p, a);
+ push_expr(p, b);
+ if(cell_size == 1)
+ {
+ jvm_generate(p, cell_size, 2 * cell_size, "dup");
+ }
+ else
+ {
+ jvm_generate(p, cell_size, 2 * cell_size, "dup2");
+ }
+ jvm_generate_push_int_size(p, 0, t -> size);
+ jvm_generate_compare_op(p, t, OP_LSS);
+
+ jvm_generate(p, cell_size, 0, "ifne L%i", label_else);
+ jvm_generate(p, 2 * cell_size, cell_size, "%cshl", prefix);
+ jvm_generate(p, 0, 0, "goto L%i", label_end);
+ jvm_generate_label(p, label_else);
+ jvm_generate_abs(p, prefix);
+ jvm_generate(p, 2 * cell_size, cell_size, "%cshr", prefix);
+ jvm_generate_label(p, label_end);
+}
+
static void
push_operator(gen_proc_t * p, oberon_oper_t * oper)
{
case OP_UNARY_MINUS:
case OP_LOGIC_NOT:
case OP_ABS:
+ case OP_CAP:
push_expr(p, oper -> left);
jvm_generate_operator(p, preq, op);
break;
case OP_IN:
jvm_generate_in(p, oper -> left, oper -> right);
break;
+
+ case OP_ASH:
+ jvm_generate_ash(p, oper -> left, oper -> right);
+ break;
default:
gen_error("push_oper: unk op %i", op);
break;
diff --git a/src/oberon-internals.h b/src/oberon-internals.h
index 3c6fb853f1a824330eb773fa55a95b7ac0ffd16d..7536540a6574ebc901d79e8870ad935ac6f2170b 100644 (file)
--- a/src/oberon-internals.h
+++ b/src/oberon-internals.h
OP_UNARY_MINUS,
OP_LOGIC_NOT,
OP_ABS,
+ OP_CAP,
OP_ADD,
OP_SUB,
OP_DIFFERENCE,
OP_SYM_DIFFERENCE,
OP_COMPLEMENTATION,
- OP_IN
+ OP_IN,
+
+ OP_ASH
};
struct oberon_item_t
index b09dccc7c2155e5827c7bec573548568efbb10bf..904a89c4577de0ee9b270281103e3391b0530e0d 100644 (file)
--- a/src/oberon-type-compat.h
+++ b/src/oberon-type-compat.h
bool
oberon_is_array_of_char_type(oberon_type_t * t);
+bool
+oberon_is_type_expr(oberon_expr_t * e);
+
bool
diff --git a/src/oberon.c b/src/oberon.c
index 30f10ec49af929465b3dfa31885ae7bb3b150fbb..08543355c92b9e421854e751081df3e6827c8d17 100644 (file)
--- a/src/oberon.c
+++ b/src/oberon.c
#include <assert.h>
#include <stdbool.h>
#include <math.h>
+#include <float.h>
#include "../include/oberon.h"
return expr;
}
+static oberon_expr_t *
+oberon_make_char(oberon_context_t * ctx, int64_t i)
+{
+ oberon_expr_t * expr;
+ expr = oberon_new_item(MODE_CHAR, ctx -> char_type, true);
+ expr -> item.integer = i;
+ expr -> item.real = i;
+ return expr;
+}
+
static oberon_expr_t *
oberon_make_real_typed(oberon_context_t * ctx, double r, oberon_type_t * result)
{
@@ -3073,7 +3084,8 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
oberon_check_dst(ctx, dst);
oberon_check_assignment_compatible(ctx, src, dst -> result);
- if(oberon_is_string_type(src -> result))
+ if(oberon_is_array_of_char_type(dst -> result)
+ && oberon_is_string_type(src -> result))
{
src -> next = dst;
oberon_make_copy_call(ctx, 2, src);
@@ -3669,7 +3681,7 @@ oberon_make_min_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
oberon_expr_t * arg;
arg = list_args;
- if(!arg -> is_item || arg -> item.mode != MODE_TYPE)
+ if(!oberon_is_type_expr(arg))
{
oberon_error(ctx, "MIN accept only type");
}
@@ -3681,6 +3693,15 @@ oberon_make_min_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
case OBERON_TYPE_INTEGER:
expr = oberon_make_integer(ctx, -powl(2, bits - 1));
break;
+ case OBERON_TYPE_BOOLEAN:
+ expr = oberon_make_boolean(ctx, false);
+ break;
+ case OBERON_TYPE_CHAR:
+ expr = oberon_make_char(ctx, 0);
+ break;
+ case OBERON_TYPE_REAL:
+ expr = oberon_make_real_typed(ctx, (bits <= 32) ? (-FLT_MAX) : (-DBL_MAX), arg -> result);
+ break;
case OBERON_TYPE_SET:
expr = oberon_make_integer(ctx, 0);
break;
@@ -3708,7 +3729,7 @@ oberon_make_max_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
oberon_expr_t * arg;
arg = list_args;
- if(!arg -> is_item || arg -> item.mode != MODE_TYPE)
+ if(!oberon_is_type_expr(arg))
{
oberon_error(ctx, "MAX accept only type");
}
@@ -3720,6 +3741,15 @@ oberon_make_max_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
case OBERON_TYPE_INTEGER:
expr = oberon_make_integer(ctx, powl(2, bits - 1) - 1);
break;
+ case OBERON_TYPE_BOOLEAN:
+ expr = oberon_make_boolean(ctx, true);
+ break;
+ case OBERON_TYPE_CHAR:
+ expr = oberon_make_char(ctx, powl(2, bits) - 1);
+ break;
+ case OBERON_TYPE_REAL:
+ expr = oberon_make_real_typed(ctx, (bits <= 32) ? (FLT_MAX) : (DBL_MAX), arg -> result);
+ break;
case OBERON_TYPE_SET:
expr = oberon_make_integer(ctx, bits);
break;
@@ -3746,8 +3776,7 @@ oberon_make_size_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list
oberon_expr_t * arg;
arg = list_args;
-
- if(!arg -> is_item || arg -> item.mode != MODE_TYPE)
+ if(!oberon_is_type_expr(arg))
{
oberon_error(ctx, "SIZE accept only type");
}
@@ -3790,16 +3819,29 @@ oberon_make_abs_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_
arg = list_args;
oberon_check_src(ctx, arg);
- oberon_type_t * result_type;
- result_type = arg -> result;
-
- if(result_type -> class != OBERON_TYPE_INTEGER)
+ if(oberon_is_number_type(arg -> result))
{
- oberon_error(ctx, "ABS accepts only integers");
+ oberon_error(ctx, "ABS accepts only numbers");
}
oberon_expr_t * expr;
- expr = oberon_new_operator(OP_ABS, result_type, arg, NULL);
+ if(oberon_is_const(arg))
+ {
+ if(oberon_is_real_type(arg -> result))
+ {
+ double x = arg -> item.real;
+ expr = oberon_make_real(ctx, fabsl(x), arg -> result);
+ }
+ else
+ {
+ int64_t x = arg -> item.integer;
+ expr = oberon_make_integer(ctx, llabs(x));
+ }
+ }
+ else
+ {
+ expr = oberon_new_operator(OP_ABS, arg -> result, arg, NULL);
+ }
return expr;
}
@@ -3937,7 +3979,7 @@ oberon_make_assert_call(oberon_context_t * ctx, int num_args, oberon_expr_t * li
cond = list_args;
oberon_check_src(ctx, cond);
- if(cond -> result -> class != OBERON_TYPE_BOOLEAN)
+ if(!oberon_is_boolean_type(cond -> result))
{
oberon_error(ctx, "expected boolean");
}
@@ -3952,7 +3994,7 @@ oberon_make_assert_call(oberon_context_t * ctx, int num_args, oberon_expr_t * li
num = list_args -> next;
oberon_check_src(ctx, num);
- if(num -> result -> class != OBERON_TYPE_INTEGER)
+ if(!oberon_is_integer_type(num -> result))
{
oberon_error(ctx, "expected integer");
}
@@ -3990,6 +4032,113 @@ oberon_make_halt_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list
oberon_generate_halt(ctx, num -> item.integer);
}
+static oberon_expr_t *
+oberon_make_ash_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args)
+{
+ if(num_args < 2)
+ {
+ oberon_error(ctx, "too few arguments");
+ }
+
+ if(num_args > 2)
+ {
+ oberon_error(ctx, "too mach arguments");
+ }
+
+ oberon_expr_t * arg1;
+ arg1 = list_args;
+ oberon_check_src(ctx, arg1);
+ if(arg1 -> result -> class != OBERON_TYPE_INTEGER)
+ {
+ oberon_error(ctx, "expected integer");
+ }
+
+ oberon_expr_t * arg2;
+ arg2 = list_args -> next;
+ oberon_check_src(ctx, arg2);
+ if(arg2 -> result -> class != OBERON_TYPE_INTEGER)
+ {
+ oberon_error(ctx, "expected integer");
+ }
+
+ oberon_expr_t * expr;
+ if(oberon_is_const(arg1) && oberon_is_const(arg2))
+ {
+ int64_t x = arg1 -> item.integer;
+ int64_t y = arg2 -> item.integer;
+ expr = oberon_make_integer(ctx, x * powl(2, y));
+ }
+ else
+ {
+ expr = oberon_new_operator(OP_ASH, arg1 -> result, arg1, arg2);
+ }
+
+ return expr;
+}
+
+static oberon_expr_t *
+oberon_make_cap_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args)
+{
+ if(num_args < 1)
+ {
+ oberon_error(ctx, "too few arguments");
+ }
+
+ if(num_args > 1)
+ {
+ oberon_error(ctx, "too mach arguments");
+ }
+
+ oberon_expr_t * arg;
+ arg = list_args;
+ oberon_check_src(ctx, arg);
+
+ if(!oberon_is_char_type(arg -> result))
+ {
+ oberon_error(ctx, "expected char");
+ }
+
+ oberon_expr_t * expr;
+ if(oberon_is_const(arg))
+ {
+ expr = oberon_make_char(ctx, toupper(arg -> item.integer));
+ }
+ else
+ {
+ expr = oberon_new_operator(OP_CAP, arg -> result, arg, NULL);
+ }
+
+ return expr;
+}
+
+static oberon_expr_t *
+oberon_make_odd_call(oberon_context_t * ctx, int num_args, oberon_expr_t * list_args)
+{
+ if(num_args < 1)
+ {
+ oberon_error(ctx, "too few arguments");
+ }
+
+ if(num_args > 1)
+ {
+ oberon_error(ctx, "too mach arguments");
+ }
+
+ oberon_expr_t * arg;
+ arg = list_args;
+ oberon_check_src(ctx, arg);
+
+ if(!oberon_is_integer_type(arg -> result))
+ {
+ oberon_error(ctx, "expected integer");
+ }
+
+ oberon_expr_t * expr;
+ expr = oberon_make_bin_op(ctx, MOD, arg, oberon_make_integer(ctx, 2));
+ expr = oberon_make_bin_op(ctx, EQUAL, expr, oberon_make_integer(ctx, 1));
+ return expr;
+}
+
static void
oberon_new_const(oberon_context_t * ctx, char * name, oberon_expr_t * expr)
{
/* Functions */
oberon_new_intrinsic(ctx, "ABS", oberon_make_abs_call, NULL);
+ oberon_new_intrinsic(ctx, "ASH", oberon_make_ash_call, NULL);
+ oberon_new_intrinsic(ctx, "CAP", oberon_make_cap_call, NULL);
oberon_new_intrinsic(ctx, "MIN", oberon_make_min_call, NULL);
oberon_new_intrinsic(ctx, "MAX", oberon_make_max_call, NULL);
+ oberon_new_intrinsic(ctx, "ODD", oberon_make_odd_call, NULL);
oberon_new_intrinsic(ctx, "SIZE", oberon_make_size_call, NULL);
/* Procedures */