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;
#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)
{
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);
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");
}
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;
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");
}
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;
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");
}
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;
}
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");
}
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");
}
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 */