diff --git a/src/oberon.c b/src/oberon.c
index e755b6cf625c2984edd3ef2dd8655810426fd44e..8a84e1359dcd48f368f41cd945a76bb92a11b599 100644 (file)
--- a/src/oberon.c
+++ b/src/oberon.c
UPARROW,
NIL,
IMPORT,
UPARROW,
NIL,
IMPORT,
- REAL
+ REAL,
+ CHAR,
+ STRING,
+ IF,
+ THEN,
+ ELSE,
+ ELSIF,
+ WHILE,
+ DO
};
// =======================================================================
};
// =======================================================================
return x;
}
return x;
}
+static oberon_type_t *
+oberon_new_type_char(int size)
+{
+ oberon_type_t * x;
+ x = oberon_new_type_ptr(OBERON_TYPE_CHAR);
+ x -> size = size;
+ return x;
+}
+
+static oberon_type_t *
+oberon_new_type_string(int size)
+{
+ oberon_type_t * x;
+ x = oberon_new_type_ptr(OBERON_TYPE_STRING);
+ x -> size = size;
+ return x;
+}
+
// =======================================================================
// TABLE
// =======================================================================
// =======================================================================
// TABLE
// =======================================================================
{
ctx -> token = IS;
}
{
ctx -> token = IS;
}
+ else if(strcmp(ident, "IF") == 0)
+ {
+ ctx -> token = IF;
+ }
+ else if(strcmp(ident, "THEN") == 0)
+ {
+ ctx -> token = THEN;
+ }
+ else if(strcmp(ident, "ELSE") == 0)
+ {
+ ctx -> token = ELSE;
+ }
+ else if(strcmp(ident, "ELSIF") == 0)
+ {
+ ctx -> token = ELSIF;
+ }
+ else if(strcmp(ident, "WHILE") == 0)
+ {
+ ctx -> token = WHILE;
+ }
+ else if(strcmp(ident, "DO") == 0)
+ {
+ ctx -> token = DO;
+ }
}
static void
}
static void
* mode = 1 == HEX
* mode = 2 == REAL
* mode = 3 == LONGREAL
* mode = 1 == HEX
* mode = 2 == REAL
* mode = 3 == LONGREAL
+ * mode = 4 == CHAR
*/
int mode = 0;
start_i = ctx -> code_index;
*/
int mode = 0;
start_i = ctx -> code_index;
end_i = ctx -> code_index;
end_i = ctx -> code_index;
- if(ctx -> c != 'H')
+ if(ctx -> c == 'H')
+ {
+ mode = 1;
+ oberon_get_char(ctx);
+ }
+ else if(ctx -> c == 'X')
+ {
+ mode = 4;
+ oberon_get_char(ctx);
+ }
+ else
{
oberon_error(ctx, "invalid hex number");
}
{
oberon_error(ctx, "invalid hex number");
}
- oberon_get_char(ctx);
}
else if(ctx -> c == '.')
{
}
else if(ctx -> c == '.')
{
end_i = ctx -> code_index;
}
end_i = ctx -> code_index;
}
+ if(mode == 0)
+ {
+ if(ctx -> c == 'H')
+ {
+ mode = 1;
+ oberon_get_char(ctx);
+ }
+ else if(ctx -> c == 'X')
+ {
+ mode = 4;
+ oberon_get_char(ctx);
+ }
+ }
+
int len = end_i - start_i;
ident = malloc(len + 1);
memcpy(ident, &ctx -> code[start_i], len);
int len = end_i - start_i;
ident = malloc(len + 1);
memcpy(ident, &ctx -> code[start_i], len);
sscanf(ident, "%lf", &real);
ctx -> token = REAL;
break;
sscanf(ident, "%lf", &real);
ctx -> token = REAL;
break;
+ case 4:
+ sscanf(ident, "%lx", &integer);
+ real = integer;
+ ctx -> token = CHAR;
+ break;
default:
oberon_error(ctx, "oberon_read_number: wat");
break;
default:
oberon_error(ctx, "oberon_read_number: wat");
break;
}
}
}
}
+static void oberon_read_string(oberon_context_t * ctx)
+{
+ int c = ctx -> c;
+ oberon_get_char(ctx);
+
+ int start = ctx -> code_index;
+
+ while(ctx -> c != 0 && ctx -> c != c)
+ {
+ oberon_get_char(ctx);
+ }
+
+ if(ctx -> c == 0)
+ {
+ oberon_error(ctx, "unterminated string");
+ }
+
+ int end = ctx -> code_index;
+
+ oberon_get_char(ctx);
+
+ char * string = calloc(1, end - start + 1);
+ strncpy(string, &ctx -> code[start], end - start);
+
+ ctx -> token = STRING;
+ ctx -> string = string;
+
+ printf("oberon_read_string: string ((%s))\n", string);
+}
+
static void oberon_read_token(oberon_context_t * ctx);
static void
static void oberon_read_token(oberon_context_t * ctx);
static void
ctx -> token = UPARROW;
oberon_get_char(ctx);
break;
ctx -> token = UPARROW;
oberon_get_char(ctx);
break;
+ case '"':
+ oberon_read_string(ctx);
+ break;
+ case '\'':
+ oberon_read_string(ctx);
+ break;
default:
oberon_error(ctx, "invalid char %c", ctx -> c);
break;
default:
oberon_error(ctx, "invalid char %c", ctx -> c);
break;
@@ -747,7 +862,14 @@ oberon_expr_list(oberon_context_t * ctx, int * num_expr, oberon_expr_t ** first,
oberon_expr_t * last;
*num_expr = 1;
oberon_expr_t * last;
*num_expr = 1;
- *first = last = oberon_expr(ctx);
+ if(const_expr)
+ {
+ *first = last = (oberon_expr_t *) oberon_const_expr(ctx);
+ }
+ else
+ {
+ *first = last = oberon_expr(ctx);
+ }
while(ctx -> token == COMMA)
{
oberon_assert_token(ctx, COMMA);
while(ctx -> token == COMMA)
{
oberon_assert_token(ctx, COMMA);
@@ -857,11 +979,29 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
// Допускается:
// Если классы типов равны
// Если INTEGER переводится в REAL
// Допускается:
// Если классы типов равны
// Если INTEGER переводится в REAL
+ // Есди STRING переводится в ARRAY OF CHAR
bool error = false;
if(pref -> class != expr -> result -> class)
{
bool error = false;
if(pref -> class != expr -> result -> class)
{
- if(expr -> result -> class == OBERON_TYPE_INTEGER)
+ printf("expr class %i\n", expr -> result -> class);
+ printf("pref class %i\n", pref -> class);
+
+ if(expr -> result -> class == OBERON_TYPE_STRING)
+ {
+ if(pref -> class == OBERON_TYPE_ARRAY)
+ {
+ if(pref -> base -> class != OBERON_TYPE_CHAR)
+ {
+ error = true;
+ }
+ }
+ else
+ {
+ error = true;
+ }
+ }
+ else if(expr -> result -> class == OBERON_TYPE_INTEGER)
{
if(pref -> class != OBERON_TYPE_REAL)
{
{
if(pref -> class != OBERON_TYPE_REAL)
{
@@ -876,7 +1016,7 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
if(error)
{
if(error)
{
- oberon_error(ctx, "incompatible types");
+ oberon_error(ctx, "oberon_autocast_to: incompatible types");
}
if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL)
}
if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL)
@@ -893,6 +1033,7 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
else if(pref -> class == OBERON_TYPE_RECORD)
{
oberon_check_record_compatibility(ctx, expr -> result, pref);
else if(pref -> class == OBERON_TYPE_RECORD)
{
oberon_check_record_compatibility(ctx, expr -> result, pref);
+ expr = oberno_make_record_cast(ctx, expr, pref);
}
else if(pref -> class == OBERON_TYPE_POINTER)
{
}
else if(pref -> class == OBERON_TYPE_POINTER)
{
@@ -1106,10 +1247,14 @@ oberon_make_call_proc(oberon_context_t * ctx, oberon_object_t * proc, int num_ar
|| ((x) == MINUS) \
|| ((x) == IDENT) \
|| ((x) == INTEGER) \
|| ((x) == MINUS) \
|| ((x) == IDENT) \
|| ((x) == INTEGER) \
+ || ((x) == REAL) \
+ || ((x) == CHAR) \
+ || ((x) == STRING) \
+ || ((x) == NIL) \
|| ((x) == LPAREN) \
|| ((x) == NOT) \
|| ((x) == TRUE) \
|| ((x) == LPAREN) \
|| ((x) == NOT) \
|| ((x) == TRUE) \
- || ((x) == FALSE))
+ || ((x) == FALSE))
static oberon_expr_t *
oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr)
static oberon_expr_t *
oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr)
static void
oberon_opt_proc_parens(oberon_context_t * ctx, oberon_expr_t * expr)
{
static void
oberon_opt_proc_parens(oberon_context_t * ctx, oberon_expr_t * expr)
{
- assert(expr -> is_item == 1);
+ assert(expr -> is_item);
int num_args = 0;
oberon_expr_t * arguments = NULL;
int num_args = 0;
oberon_expr_t * arguments = NULL;
break;
case INTEGER:
result = oberon_get_type_of_int_value(ctx, ctx -> integer);
break;
case INTEGER:
result = oberon_get_type_of_int_value(ctx, ctx -> integer);
- expr = oberon_new_item(MODE_INTEGER, result, 1);
+ expr = oberon_new_item(MODE_INTEGER, result, true);
expr -> item.integer = ctx -> integer;
oberon_assert_token(ctx, INTEGER);
break;
expr -> item.integer = ctx -> integer;
oberon_assert_token(ctx, INTEGER);
break;
+ case CHAR:
+ result = ctx -> char_type;
+ expr = oberon_new_item(MODE_CHAR, result, true);
+ expr -> item.integer = ctx -> integer;
+ oberon_assert_token(ctx, CHAR);
+ break;
+ case STRING:
+ result = ctx -> string_type;
+ expr = oberon_new_item(MODE_STRING, result, true);
+ expr -> item.string = ctx -> string;
+ oberon_assert_token(ctx, STRING);
+ break;
case REAL:
result = (ctx -> longmode) ? (ctx -> longreal_type) : (ctx -> real_type);
expr = oberon_new_item(MODE_REAL, result, 1);
case REAL:
result = (ctx -> longmode) ? (ctx -> longreal_type) : (ctx -> real_type);
expr = oberon_new_item(MODE_REAL, result, 1);
oberon_assert_token(ctx, REAL);
break;
case TRUE:
oberon_assert_token(ctx, REAL);
break;
case TRUE:
- expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
+ expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, true);
expr -> item.boolean = true;
oberon_assert_token(ctx, TRUE);
break;
case FALSE:
expr -> item.boolean = true;
oberon_assert_token(ctx, TRUE);
break;
case FALSE:
- expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
+ expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, true);
expr -> item.boolean = false;
oberon_assert_token(ctx, FALSE);
break;
expr -> item.boolean = false;
oberon_assert_token(ctx, FALSE);
break;
break;
case NIL:
oberon_assert_token(ctx, NIL);
break;
case NIL:
oberon_assert_token(ctx, NIL);
- expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type, 1);
+ expr = oberon_new_item(MODE_NIL, ctx -> void_ptr_type, true);
break;
default:
oberon_error(ctx, "invalid expression");
break;
default:
oberon_error(ctx, "invalid expression");
@@ -1514,6 +1671,10 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
|| b -> result -> class == OBERON_TYPE_INTEGER
|| a -> result -> class == OBERON_TYPE_REAL
|| b -> result -> class == OBERON_TYPE_REAL)
|| b -> result -> class == OBERON_TYPE_INTEGER
|| a -> result -> class == OBERON_TYPE_REAL
|| b -> result -> class == OBERON_TYPE_REAL)
+ {
+ // accept
+ }
+ else
{
oberon_error(ctx, "used only with numeric types");
}
{
oberon_error(ctx, "used only with numeric types");
}
oberon_prevent_undeclarated_procedures(ctx);
}
oberon_prevent_undeclarated_procedures(ctx);
}
+static void
+oberon_statement_seq(oberon_context_t * ctx);
+
static void
oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
{
static void
oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
{
oberon_opt_proc_parens(ctx, item1);
}
}
oberon_opt_proc_parens(ctx, item1);
}
}
+ else if(ctx -> token == IF)
+ {
+ gen_label_t * end;
+ gen_label_t * els;
+ oberon_expr_t * cond;
+
+ els = oberon_generator_reserve_label(ctx);
+ end = oberon_generator_reserve_label(ctx);
+
+ oberon_assert_token(ctx, IF);
+ cond = oberon_expr(ctx);
+ if(cond -> result -> class != OBERON_TYPE_BOOLEAN)
+ {
+ oberon_error(ctx, "condition must be boolean");
+ }
+ oberon_assert_token(ctx, THEN);
+ oberon_generate_branch(ctx, cond, false, els);
+ oberon_statement_seq(ctx);
+ oberon_generate_goto(ctx, end);
+ oberon_generate_label(ctx, els);
+
+ while(ctx -> token == ELSIF)
+ {
+ els = oberon_generator_reserve_label(ctx);
+
+ oberon_assert_token(ctx, ELSIF);
+ cond = oberon_expr(ctx);
+ if(cond -> result -> class != OBERON_TYPE_BOOLEAN)
+ {
+ oberon_error(ctx, "condition must be boolean");
+ }
+ oberon_assert_token(ctx, THEN);
+ oberon_generate_branch(ctx, cond, false, els);
+ oberon_statement_seq(ctx);
+ oberon_generate_goto(ctx, end);
+ oberon_generate_label(ctx, els);
+ }
+
+ if(ctx -> token == ELSE)
+ {
+ oberon_assert_token(ctx, ELSE);
+ oberon_statement_seq(ctx);
+ }
+
+ oberon_generate_label(ctx, end);
+ oberon_assert_token(ctx, END);
+ }
+ else if(ctx -> token == WHILE)
+ {
+ gen_label_t * begin;
+ gen_label_t * end;
+ oberon_expr_t * cond;
+
+ begin = oberon_generator_reserve_label(ctx);
+ end = oberon_generator_reserve_label(ctx);
+
+ oberon_assert_token(ctx, WHILE);
+ oberon_generate_label(ctx, begin);
+ cond = oberon_expr(ctx);
+ if(cond -> result -> class != OBERON_TYPE_BOOLEAN)
+ {
+ oberon_error(ctx, "condition must be boolean");
+ }
+ oberon_generate_branch(ctx, cond, false, end);
+
+ oberon_assert_token(ctx, DO);
+ oberon_statement_seq(ctx);
+ oberon_generate_goto(ctx, begin);
+
+ oberon_assert_token(ctx, END);
+ oberon_generate_label(ctx, end);
+ }
else if(ctx -> token == RETURN)
{
oberon_assert_token(ctx, RETURN);
else if(ctx -> token == RETURN)
{
oberon_assert_token(ctx, RETURN);
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 -> string_type = oberon_new_type_string(1);
+ oberon_generator_init_type(ctx, ctx -> string_type);
+
ctx -> bool_type = oberon_new_type_boolean();
oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
ctx -> bool_type = oberon_new_type_boolean();
oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
ctx -> longreal_type = oberon_new_type_real(8);
oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1);
ctx -> longreal_type = oberon_new_type_real(8);
oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1);
+
+ ctx -> char_type = oberon_new_type_char(1);
+ oberon_define_type(ctx -> world_scope, "CHAR", ctx -> char_type, 1);
}
static void
}
static void