diff --git a/oberon.c b/oberon.c
index ec4cab05b3804d3c204407e28dcbb2eff1ccea22..2b4e09f5e8a3ca7e95e4923a6d4773fa9e5202bf 100644 (file)
--- a/oberon.c
+++ b/oberon.c
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
+#include <assert.h>
#include "oberon.h"
#include "generator.h"
DIV,
MOD,
AND,
- NOT
+ NOT,
+ PROCEDURE,
+ COMMA,
+ RETURN,
+ CONST,
+ TYPE,
+ ARRAY,
+ OF,
+ LBRACE,
+ RBRACE,
+ RECORD
};
// =======================================================================
exit(1);
}
-/*
-static int
-oberon_item_to_type_class(oberon_context_t * ctx, oberon_item_t * item)
+static oberon_type_t *
+oberon_new_type_ptr(int class)
{
- int class;
-
- switch(item -> mode)
- {
- case MODE_INTEGER:
- class = OBERON_TYPE_INTEGER;
- break;
- case MODE_BOOLEAN:
- class = OBERON_TYPE_BOOLEAN;
- break;
- case MODE_VAR:
- class = item -> var -> type -> class;
- break;
- default:
- oberon_error(ctx, "oberon_item_to_type_class: wat");
- break;
- }
-
- return class;
+ oberon_type_t * x = malloc(sizeof *x);
+ memset(x, 0, sizeof *x);
+ x -> class = class;
+ return x;
}
-*/
-/*
-static void
-oberon_autocast_to(oberon_context_t * ctx, oberon_item_t * from, oberon_item_t * to)
+static oberon_type_t *
+oberon_new_type_integer(int size)
{
- int from_class = oberon_item_to_type_class(ctx, from);
- int to_class = oberon_item_to_type_class(ctx, to);
+ oberon_type_t * x;
+ x = oberon_new_type_ptr(OBERON_TYPE_INTEGER);
+ x -> size = size;
+ return x;
+}
- if(from_class != to_class)
- {
- oberon_error(ctx, "oberon_autocast_to: types not matched %i -> %i", from_class, to_class);
- }
+static oberon_type_t *
+oberon_new_type_boolean(int size)
+{
+ oberon_type_t * x;
+ x = oberon_new_type_ptr(OBERON_TYPE_BOOLEAN);
+ x -> size = size;
+ return x;
}
-*/
// =======================================================================
// TABLE
// =======================================================================
-static oberon_type_t *
-oberon_find_type(oberon_context_t * ctx, char * name)
+static oberon_scope_t *
+oberon_open_scope(oberon_context_t * ctx)
+{
+ oberon_scope_t * scope = malloc(sizeof *scope);
+ memset(scope, 0, sizeof *scope);
+
+ oberon_object_t * list = malloc(sizeof *list);
+ memset(list, 0, sizeof *list);
+
+ scope -> ctx = ctx;
+ scope -> list = list;
+ scope -> up = ctx -> decl;
+
+ ctx -> decl = scope;
+ return scope;
+}
+
+static void
+oberon_close_scope(oberon_scope_t * scope)
+{
+ oberon_context_t * ctx = scope -> ctx;
+ ctx -> decl = scope -> up;
+}
+
+static oberon_object_t *
+oberon_define_object(oberon_scope_t * scope, char * name, int class)
{
- oberon_type_t * x = ctx -> types;
+ oberon_object_t * x = scope -> list;
while(x -> next && strcmp(x -> next -> name, name) != 0)
{
x = x -> next;
}
- return x -> next;
+ if(x -> next)
+ {
+ oberon_error(scope -> ctx, "already defined");
+ }
+
+ oberon_object_t * newvar = malloc(sizeof *newvar);
+ memset(newvar, 0, sizeof *newvar);
+ newvar -> name = name;
+ newvar -> class = class;
+
+ x -> next = newvar;
+
+ return newvar;
}
-static oberon_var_t *
-oberon_find_var(oberon_context_t * ctx, char * name)
+static void
+oberon_define_field(oberon_context_t * ctx, oberon_type_t * rec, char * name, oberon_type_t * type)
{
- oberon_var_t * x = ctx -> mod -> vars;
+ oberon_object_t * x = rec -> decl;
while(x -> next && strcmp(x -> next -> name, name) != 0)
{
x = x -> next;
}
- return x -> next;
+ if(x -> next)
+ {
+ oberon_error(ctx, "multiple definition");
+ }
+
+ oberon_object_t * field = malloc(sizeof *field);
+ memset(field, 0, sizeof *field);
+ field -> name = name;
+ field -> class = OBERON_CLASS_FIELD;
+ field -> type = type;
+
+ rec -> num_decl += 1;
+ oberon_generator_init_var(ctx, field);
+
+ x -> next = field;
}
-static void
-oberon_define_var(oberon_context_t * ctx, char * name, oberon_type_t * type)
+static oberon_object_t *
+oberon_find_object_in_list(oberon_object_t * list, char * name)
{
- oberon_var_t * x = ctx -> mod -> vars;
+ oberon_object_t * x = list;
while(x -> next && strcmp(x -> next -> name, name) != 0)
{
x = x -> next;
}
+ return x -> next;
+}
- if(x -> next)
+static oberon_object_t *
+oberon_find_object(oberon_scope_t * scope, char * name)
+{
+ oberon_object_t * result = NULL;
+
+ oberon_scope_t * s = scope;
+ while(result == NULL && s != NULL)
{
- oberon_error(ctx, "already defined");
+ result = oberon_find_object_in_list(s -> list, name);
+ s = s -> up;
}
- oberon_var_t * newvar = malloc(sizeof *newvar);
- memset(newvar, 0, sizeof *newvar);
- newvar -> name = name;
- newvar -> type = type;
- oberon_generator_init_var(ctx, newvar);
+ if(result == NULL)
+ {
+ oberon_error(scope -> ctx, "undefined ident %s", name);
+ }
- x -> next = newvar;
+ return result;
+}
+
+static oberon_object_t *
+oberon_find_field(oberon_context_t * ctx, oberon_type_t * rec, char * name)
+{
+ oberon_object_t * x = rec -> decl;
+ for(int i = 0; i < rec -> num_decl; i++)
+ {
+ if(strcmp(x -> name, name) == 0)
+ {
+ return x;
+ }
+ x = x -> next;
+ }
+
+ oberon_error(ctx, "field not defined");
+
+ return NULL;
+}
+
+static oberon_object_t *
+oberon_define_type(oberon_scope_t * scope, char * name, oberon_type_t * type)
+{
+ oberon_object_t * id;
+ id = oberon_define_object(scope, name, OBERON_CLASS_TYPE);
+ id -> type = type;
+ oberon_generator_init_type(scope -> ctx, type);
+ return id;
+}
+
+static oberon_type_t *
+oberon_find_type(oberon_scope_t * scope, char * name)
+{
+ oberon_object_t * x = oberon_find_object(scope, name);
+ if(x -> class != OBERON_CLASS_TYPE)
+ {
+ oberon_error(scope -> ctx, "%s not a type", name);
+ }
+
+ return x -> type;
+}
+
+static oberon_object_t *
+oberon_define_var(oberon_scope_t * scope, int class, char * name, oberon_type_t * type)
+{
+ oberon_object_t * var;
+ var = oberon_define_object(scope, name, class);
+ var -> type = type;
+ oberon_generator_init_var(scope -> ctx, var);
+ return var;
+}
+
+/*
+static oberon_object_t *
+oberon_find_var(oberon_scope_t * scope, char * name)
+{
+ oberon_object_t * x = oberon_find_object(scope, name);
+
+ if(x -> class != OBERON_CLASS_VAR)
+ {
+ oberon_error(scope -> ctx, "%s not a var", name);
+ }
+
+ return x;
+}
+*/
+
+static oberon_object_t *
+oberon_define_proc(oberon_scope_t * scope, char * name, oberon_type_t * signature)
+{
+ oberon_object_t * proc;
+ proc = oberon_define_object(scope, name, OBERON_CLASS_PROC);
+ proc -> type = signature;
+ oberon_generator_init_proc(scope -> ctx, proc);
+ return proc;
}
// =======================================================================
{
ctx -> token = MOD;
}
+ else if(strcmp(ident, "PROCEDURE") == 0)
+ {
+ ctx -> token = PROCEDURE;
+ }
+ else if(strcmp(ident, "RETURN") == 0)
+ {
+ ctx -> token = RETURN;
+ }
+ else if(strcmp(ident, "CONST") == 0)
+ {
+ ctx -> token = CONST;
+ }
+ else if(strcmp(ident, "TYPE") == 0)
+ {
+ ctx -> token = TYPE;
+ }
+ else if(strcmp(ident, "ARRAY") == 0)
+ {
+ ctx -> token = ARRAY;
+ }
+ else if(strcmp(ident, "OF") == 0)
+ {
+ ctx -> token = OF;
+ }
+ else if(strcmp(ident, "RECORD") == 0)
+ {
+ ctx -> token = RECORD;
+ }
}
static void
ctx -> token = NOT;
oberon_get_char(ctx);
break;
+ case ',':
+ ctx -> token = COMMA;
+ oberon_get_char(ctx);
+ break;
+ case '[':
+ ctx -> token = LBRACE;
+ oberon_get_char(ctx);
+ break;
+ case ']':
+ ctx -> token = RBRACE;
+ oberon_get_char(ctx);
+ break;
default:
oberon_error(ctx, "invalid char");
break;
static oberon_expr_t * oberon_expr(oberon_context_t * ctx);
static void oberon_assert_token(oberon_context_t * ctx, int token);
static char * oberon_assert_ident(oberon_context_t * ctx);
+static oberon_type_t * oberon_type(oberon_context_t * ctx);
static oberon_expr_t *
oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon_expr_t * right)
}
static oberon_expr_t *
-oberon_make_not(oberon_context_t * ctx, oberon_expr_t * expr)
-{
- return oberon_new_operator(OP_LOGIC_NOT, expr -> result, expr, NULL);
-}
-
-static oberon_expr_t *
-oberon_factor(oberon_context_t * ctx)
-{
- char * name;
- oberon_var_t * var;
- oberon_expr_t * expr;
-
- switch(ctx -> token)
- {
- case IDENT:
- name = oberon_assert_ident(ctx);
- var = oberon_find_var(ctx, name);
- if(var == NULL)
- {
- oberon_error(ctx, "undefined variable %s", name);
- }
- expr = oberon_new_item(MODE_VAR, var -> type);
- expr -> item.var = var;
- break;
- case INTEGER:
- expr = oberon_new_item(MODE_INTEGER, ctx -> int_type);
- expr -> item.integer = ctx -> integer;
- oberon_assert_token(ctx, INTEGER);
- break;
- case TRUE:
- expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
- expr -> item.boolean = 1;
- oberon_assert_token(ctx, TRUE);
- break;
- case FALSE:
- expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
- expr -> item.boolean = 0;
- oberon_assert_token(ctx, FALSE);
- break;
- case LPAREN:
- oberon_assert_token(ctx, LPAREN);
- expr = oberon_expr(ctx);
- oberon_assert_token(ctx, RPAREN);
- break;
- case NOT:
- oberon_assert_token(ctx, NOT);
- expr = oberon_factor(ctx);
- expr = oberon_make_not(ctx, expr);
- break;
- default:
- oberon_error(ctx, "invalid expression");
- }
-
- return expr;
-}
-
-static oberon_expr_t *
-oberon_make_mul_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+oberon_make_unary_op(oberon_context_t * ctx, int token, oberon_expr_t * a)
{
oberon_expr_t * expr;
oberon_type_t * result;
result = a -> result;
- if(token == STAR)
- {
- expr = oberon_new_operator(OP_MUL, result, a, b);
- }
- else if(token == SLASH)
- {
- expr = oberon_new_operator(OP_DIV, result, a, b);
- }
- else if(token == DIV)
+ if(token == MINUS)
{
- expr = oberon_new_operator(OP_DIV, result, a, b);
- }
- else if(token == MOD)
- {
- expr = oberon_new_operator(OP_MOD, result, a, b);
+ if(result -> class != OBERON_TYPE_INTEGER)
+ {
+ oberon_error(ctx, "incompatible operator type");
+ }
+
+ expr = oberon_new_operator(OP_UNARY_MINUS, result, a, NULL);
}
- else if(token == AND)
+ else if(token == NOT)
{
- expr = oberon_new_operator(OP_LOGIC_AND, result, a, b);
+ if(result -> class != OBERON_TYPE_BOOLEAN)
+ {
+ oberon_error(ctx, "incompatible operator type");
+ }
+
+ expr = oberon_new_operator(OP_LOGIC_NOT, result, a, NULL);
}
else
{
- oberon_error(ctx, "oberon_make_mul_op: wat");
+ oberon_error(ctx, "oberon_make_unary_op: wat");
}
return expr;
}
-#define ISMULOP(x) \
- ((x) >= STAR && (x) <= AND)
+static void
+oberon_expr_list(oberon_context_t * ctx, int * num_expr, oberon_expr_t ** first)
+{
+ oberon_expr_t * last;
+
+ *num_expr = 1;
+ *first = last = oberon_expr(ctx);
+ while(ctx -> token == COMMA)
+ {
+ oberon_assert_token(ctx, COMMA);
+ oberon_expr_t * current;
+ current = oberon_expr(ctx);
+ last -> next = current;
+ last = current;
+ *num_expr += 1;
+ }
+}
static oberon_expr_t *
-oberon_term_expr(oberon_context_t * ctx)
+oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
{
- oberon_expr_t * expr;
-
- expr = oberon_factor(ctx);
- while(ISMULOP(ctx -> token))
+ if(pref -> class != expr -> result -> class)
{
- int token = ctx -> token;
- oberon_read_token(ctx);
+ oberon_error(ctx, "incompatible types");
+ }
- oberon_expr_t * inter = oberon_factor(ctx);
- expr = oberon_make_mul_op(ctx, token, expr, inter);
+
+ if(pref -> class == OBERON_TYPE_INTEGER)
+ {
+ if(expr -> result -> class > pref -> class)
+ {
+ oberon_error(ctx, "incompatible size");
+ }
}
+ // TODO cast
+
return expr;
}
-static oberon_expr_t *
-oberon_make_add_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+static void
+oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
{
- oberon_expr_t * expr;
- oberon_type_t * result;
-
- result = a -> result;
+ if(desig -> is_item == 0)
+ {
+ oberon_error(ctx, "expected item");
+ }
- if(token == PLUS)
+ if(desig -> item.mode != MODE_CALL)
{
- expr = oberon_new_operator(OP_ADD, result, a, b);
+ oberon_error(ctx, "expected mode CALL");
}
- else if(token == MINUS)
+
+ if(desig -> item.var -> class != OBERON_CLASS_PROC)
{
- expr = oberon_new_operator(OP_SUB, result, a, b);
+ oberon_error(ctx, "only procedures can be called");
}
- else if(token == OR)
+
+ oberon_type_t * fn = desig -> item.var -> type;
+ int num_args = desig -> item.num_args;
+ int num_decl = fn -> num_decl;
+
+ if(num_args < num_decl)
{
- expr = oberon_new_operator(OP_LOGIC_OR, result, a, b);
+ oberon_error(ctx, "too few arguments");
}
- else
+ else if(num_args > num_decl)
{
- oberon_error(ctx, "oberon_make_add_op: wat");
+ oberon_error(ctx, "too many arguments");
}
- return expr;
+ oberon_expr_t * arg = desig -> item.args;
+ oberon_object_t * param = fn -> decl;
+ for(int i = 0; i < num_args; i++)
+ {
+ oberon_autocast_to(ctx, arg, param -> type);
+ arg = arg -> next;
+ param = param -> next;
+ }
}
-static oberon_expr_t *
-oberon_make_unary_minus(oberon_context_t * ctx, oberon_expr_t * expr)
-{
- return oberon_new_operator(OP_UNARY_MINUS, expr -> result, expr, NULL);
-}
+#define ISEXPR(x) \
+ (((x) == PLUS) \
+ || ((x) == MINUS) \
+ || ((x) == IDENT) \
+ || ((x) == INTEGER) \
+ || ((x) == LPAREN) \
+ || ((x) == NOT) \
+ || ((x) == TRUE) \
+ || ((x) == FALSE))
-#define ISADDOP(x) \
- ((x) >= PLUS && (x) <= OR)
+#define ISSELECTOR(x) \
+ (((x) == LBRACE) \
+ || ((x) == DOT))
static oberon_expr_t *
-oberon_simple_expr(oberon_context_t * ctx)
+oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, int num_indexes, oberon_expr_t * indexes)
{
- oberon_expr_t * expr;
+ assert(desig -> is_item == 1);
- int minus = 0;
- if(ctx -> token == PLUS)
+ if(desig -> item.mode != MODE_VAR)
{
- minus = 0;
- oberon_assert_token(ctx, PLUS);
+ oberon_error(ctx, "not MODE_VAR");
}
- else if(ctx -> token == MINUS)
+
+ int class = desig -> item.var -> class;
+ switch(class)
{
- minus = 1;
- oberon_assert_token(ctx, MINUS);
+ case OBERON_CLASS_VAR:
+ case OBERON_CLASS_VAR_PARAM:
+ case OBERON_CLASS_PARAM:
+ break;
+ default:
+ oberon_error(ctx, "not variable");
+ break;
}
- expr = oberon_term_expr(ctx);
- while(ISADDOP(ctx -> token))
+ oberon_type_t * type = desig -> item.var -> type;
+ if(type -> class != OBERON_TYPE_ARRAY)
{
- int token = ctx -> token;
- oberon_read_token(ctx);
+ oberon_error(ctx, "not array");
+ }
- oberon_expr_t * inter = oberon_term_expr(ctx);
- expr = oberon_make_add_op(ctx, token, expr, inter);
+ int dim = desig -> item.var -> type -> dim;
+ if(num_indexes != dim)
+ {
+ oberon_error(ctx, "dimesions not matched");
}
- if(minus)
+ oberon_type_t * base = desig -> item.var -> type -> base;
+
+ oberon_expr_t * selector;
+ selector = oberon_new_item(MODE_INDEX, base);
+ selector -> item.parent = (oberon_item_t *) desig;
+ selector -> item.num_args = num_indexes;
+ selector -> item.args = indexes;
+
+ return selector;
+}
+
+static oberon_expr_t *
+oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char * name)
+{
+ assert(expr -> is_item == 1);
+
+ int class = expr -> result -> class;
+ if(class != OBERON_TYPE_RECORD)
{
- expr = oberon_make_unary_minus(ctx, expr);
+ oberon_error(ctx, "not record");
}
- return expr;
+ oberon_type_t * rec = expr -> result;
+
+ oberon_object_t * field;
+ field = oberon_find_field(ctx, rec, name);
+
+ oberon_expr_t * selector;
+ selector = oberon_new_item(MODE_FIELD, field -> type);
+ selector -> item.var = field;
+ selector -> item.parent = (oberon_item_t *) expr;
+
+ return selector;
}
static oberon_expr_t *
-oberon_make_relation(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+oberon_designator(oberon_context_t * ctx)
{
+ char * name;
+ oberon_object_t * var;
oberon_expr_t * expr;
- oberon_type_t * result;
- result = a -> result;
+ name = oberon_assert_ident(ctx);
+ var = oberon_find_object(ctx -> decl, name);
- if(token == EQUAL)
- {
- expr = oberon_new_operator(OP_EQ, result, a, b);
- }
- else if(token == NEQ)
+ switch(var -> class)
{
- expr = oberon_new_operator(OP_NEQ, result, a, b);
- }
- else if(token == LESS)
+ case OBERON_CLASS_CONST:
+ // TODO copy value
+ expr = (oberon_expr_t *) var -> value;
+ break;
+ case OBERON_CLASS_VAR:
+ case OBERON_CLASS_VAR_PARAM:
+ case OBERON_CLASS_PARAM:
+ expr = oberon_new_item(MODE_VAR, var -> type);
+ break;
+ case OBERON_CLASS_PROC:
+ expr = oberon_new_item(MODE_CALL, var -> type);
+ break;
+ default:
+ oberon_error(ctx, "invalid designator");
+ break;
+ }
+ expr -> item.var = var;
+
+ while(ISSELECTOR(ctx -> token))
{
- expr = oberon_new_operator(OP_LSS, result, a, b);
+ switch(ctx -> token)
+ {
+ case DOT:
+ oberon_assert_token(ctx, DOT);
+ name = oberon_assert_ident(ctx);
+ expr = oberon_make_record_selector(ctx, expr, name);
+ break;
+ case LBRACE:
+ oberon_assert_token(ctx, LBRACE);
+ int num_indexes = 0;
+ oberon_expr_t * indexes = NULL;
+ oberon_expr_list(ctx, &num_indexes, &indexes);
+ oberon_assert_token(ctx, RBRACE);
+ expr = oberon_make_array_selector(ctx, expr, num_indexes, indexes);
+ break;
+ default:
+ oberon_error(ctx, "oberon_designator: wat");
+ break;
+ }
}
- else if(token == LEQ)
+ return expr;
+}
+
+static oberon_expr_t *
+oberon_opt_proc_parens(oberon_context_t * ctx, oberon_expr_t * expr)
+{
+ assert(expr -> is_item == 1);
+
+ if(ctx -> token == LPAREN)
{
- expr = oberon_new_operator(OP_LEQ, result, a, b);
+ if(expr -> result -> class != OBERON_TYPE_PROCEDURE)
+ {
+ oberon_error(ctx, "not a procedure");
+ }
+
+ oberon_assert_token(ctx, LPAREN);
+
+ int num_args = 0;
+ oberon_expr_t * arguments = NULL;
+
+ if(ISEXPR(ctx -> token))
+ {
+ oberon_expr_list(ctx, &num_args, &arguments);
+ }
+
+ expr -> result = expr -> item.var -> type -> base;
+ expr -> item.mode = MODE_CALL;
+ expr -> item.num_args = num_args;
+ expr -> item.args = arguments;
+ oberon_assert_token(ctx, RPAREN);
+
+ oberon_autocast_call(ctx, expr);
+ }
+
+ return expr;
+}
+
+static oberon_expr_t *
+oberon_factor(oberon_context_t * ctx)
+{
+ oberon_expr_t * expr;
+
+ switch(ctx -> token)
+ {
+ case IDENT:
+ expr = oberon_designator(ctx);
+ expr = oberon_opt_proc_parens(ctx, expr);
+ break;
+ case INTEGER:
+ expr = oberon_new_item(MODE_INTEGER, ctx -> int_type);
+ expr -> item.integer = ctx -> integer;
+ oberon_assert_token(ctx, INTEGER);
+ break;
+ case TRUE:
+ expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
+ expr -> item.boolean = 1;
+ oberon_assert_token(ctx, TRUE);
+ break;
+ case FALSE:
+ expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
+ expr -> item.boolean = 0;
+ oberon_assert_token(ctx, FALSE);
+ break;
+ case LPAREN:
+ oberon_assert_token(ctx, LPAREN);
+ expr = oberon_expr(ctx);
+ oberon_assert_token(ctx, RPAREN);
+ break;
+ case NOT:
+ oberon_assert_token(ctx, NOT);
+ expr = oberon_factor(ctx);
+ expr = oberon_make_unary_op(ctx, NOT, expr);
+ break;
+ default:
+ oberon_error(ctx, "invalid expression");
}
- else if(token == GREAT)
+
+ 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))
{
- expr = oberon_new_operator(OP_GRT, result, a, b);
+ oberon_error(ctx, "incompatible types");
}
- else if(token == GEQ)
+
+ if((a -> size) > (b -> size))
{
- expr = oberon_new_operator(OP_GEQ, result, a, b);
+ *result = a;
}
else
{
- oberon_error(ctx, "oberon_make_relation: wat");
- }
+ *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 ITUSEONLYINTEGER(x) \
+ ((x) >= LESS && (x) <= GEQ)
+
+#define ITUSEONLYBOOLEAN(x) \
+ (((x) == OR) || ((x) == AND))
+
+static oberon_expr_t *
+oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+{
+ oberon_expr_t * expr;
+ oberon_type_t * result;
+
+ if(ITMAKESBOOLEAN(token))
+ {
+ if(ITUSEONLYINTEGER(token))
+ {
+ if(a -> result -> class != OBERON_TYPE_INTEGER
+ || b -> result -> class != OBERON_TYPE_INTEGER)
+ {
+ oberon_error(ctx, "used only with integer types");
+ }
+ }
+ else if(ITUSEONLYBOOLEAN(token))
+ {
+ if(a -> result -> class != OBERON_TYPE_BOOLEAN
+ || b -> result -> class != OBERON_TYPE_BOOLEAN)
+ {
+ oberon_error(ctx, "used only with boolean type");
+ }
+ }
+
+ result = ctx -> bool_type;
+
+ if(token == EQUAL)
+ {
+ expr = oberon_new_operator(OP_EQ, result, a, b);
+ }
+ else if(token == NEQ)
+ {
+ expr = oberon_new_operator(OP_NEQ, result, a, b);
+ }
+ else if(token == LESS)
+ {
+ expr = oberon_new_operator(OP_LSS, result, a, b);
+ }
+ else if(token == LEQ)
+ {
+ expr = oberon_new_operator(OP_LEQ, result, a, b);
+ }
+ else if(token == GREAT)
+ {
+ expr = oberon_new_operator(OP_GRT, result, a, b);
+ }
+ else if(token == GEQ)
+ {
+ expr = oberon_new_operator(OP_GEQ, result, a, b);
+ }
+ else if(token == OR)
+ {
+ expr = oberon_new_operator(OP_LOGIC_OR, result, a, b);
+ }
+ else if(token == AND)
+ {
+ expr = oberon_new_operator(OP_LOGIC_AND, result, a, b);
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_make_bin_op: bool wat");
+ }
+ }
+ else
+ {
+ oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+
+ if(token == PLUS)
+ {
+ expr = oberon_new_operator(OP_ADD, result, a, b);
+ }
+ else if(token == MINUS)
+ {
+ expr = oberon_new_operator(OP_SUB, result, a, b);
+ }
+ else if(token == STAR)
+ {
+ expr = oberon_new_operator(OP_MUL, result, a, b);
+ }
+ else if(token == SLASH)
+ {
+ expr = oberon_new_operator(OP_DIV, result, a, b);
+ }
+ else if(token == DIV)
+ {
+ expr = oberon_new_operator(OP_DIV, result, a, b);
+ }
+ else if(token == MOD)
+ {
+ expr = oberon_new_operator(OP_MOD, result, a, b);
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_make_bin_op: bin wat");
+ }
+ }
+
+ return expr;
+}
+
+#define ISMULOP(x) \
+ ((x) >= STAR && (x) <= AND)
+
+static oberon_expr_t *
+oberon_term_expr(oberon_context_t * ctx)
+{
+ oberon_expr_t * expr;
+
+ expr = oberon_factor(ctx);
+ while(ISMULOP(ctx -> token))
+ {
+ int token = ctx -> token;
+ oberon_read_token(ctx);
+
+ oberon_expr_t * inter = oberon_factor(ctx);
+ expr = oberon_make_bin_op(ctx, token, expr, inter);
+ }
+
+ return expr;
+}
+
+#define ISADDOP(x) \
+ ((x) >= PLUS && (x) <= OR)
+
+static oberon_expr_t *
+oberon_simple_expr(oberon_context_t * ctx)
+{
+ oberon_expr_t * expr;
+
+ int minus = 0;
+ if(ctx -> token == PLUS)
+ {
+ minus = 0;
+ oberon_assert_token(ctx, PLUS);
+ }
+ else if(ctx -> token == MINUS)
+ {
+ minus = 1;
+ oberon_assert_token(ctx, MINUS);
+ }
+
+ expr = oberon_term_expr(ctx);
+ while(ISADDOP(ctx -> token))
+ {
+ int token = ctx -> token;
+ oberon_read_token(ctx);
+
+ oberon_expr_t * inter = oberon_term_expr(ctx);
+ expr = oberon_make_bin_op(ctx, token, expr, inter);
+ }
+
+ if(minus)
+ {
+ expr = oberon_make_unary_op(ctx, MINUS, expr);
+ }
return expr;
}
oberon_read_token(ctx);
oberon_expr_t * inter = oberon_simple_expr(ctx);
- expr = oberon_make_relation(ctx, token, expr, inter);
+ expr = oberon_make_bin_op(ctx, token, expr, inter);
}
return expr;
}
+static oberon_item_t *
+oberon_const_expr(oberon_context_t * ctx)
+{
+ oberon_expr_t * expr;
+ expr = oberon_expr(ctx);
+
+ if(expr -> is_item == 0)
+ {
+ oberon_error(ctx, "const expression are required");
+ }
+
+ return (oberon_item_t *) expr;
+}
+
// =======================================================================
// PARSER
// =======================================================================
+static void oberon_statement_seq(oberon_context_t * ctx);
+
static void
oberon_expect_token(oberon_context_t * ctx, int token)
{
return ident;
}
+static oberon_type_t *
+oberon_make_array_type(oberon_context_t * ctx, int dim, oberon_item_t * size, oberon_type_t * base)
+{
+ assert(dim == 1);
+ oberon_type_t * newtype;
+
+ if(size -> mode != MODE_INTEGER)
+ {
+ oberon_error(ctx, "requires integer constant");
+ }
+
+ newtype = oberon_new_type_ptr(OBERON_TYPE_ARRAY);
+ newtype -> dim = dim;
+ newtype -> size = size -> integer;
+ newtype -> base = base;
+ oberon_generator_init_type(ctx, newtype);
+
+ return newtype;
+}
+
+static void
+oberon_field_list(oberon_context_t * ctx, oberon_type_t * rec)
+{
+ if(ctx -> token == IDENT)
+ {
+ char * name;
+ oberon_type_t * type;
+ name = oberon_assert_ident(ctx);
+ oberon_assert_token(ctx, COLON);
+ type = oberon_type(ctx);
+ oberon_define_field(ctx, rec, name, type);
+ }
+}
+
+static oberon_type_t * oberon_opt_formal_pars(oberon_context_t * ctx, int class);
+
static oberon_type_t *
oberon_type(oberon_context_t * ctx)
{
- char * name = oberon_assert_ident(ctx);
- oberon_type_t * type = oberon_find_type(ctx, name);
+ oberon_type_t * type;
- if(type == NULL)
+ if(ctx -> token == IDENT)
+ {
+ char * name = oberon_assert_ident(ctx);
+ type = oberon_find_type(ctx -> decl, name);
+ }
+ else if(ctx -> token == ARRAY)
{
- oberon_error(ctx, "undefined type");
+ oberon_assert_token(ctx, ARRAY);
+ oberon_item_t * size = oberon_const_expr(ctx);
+ oberon_assert_token(ctx, OF);
+ oberon_type_t * base = oberon_type(ctx);
+ type = oberon_make_array_type(ctx, 1, size, base);
+ }
+ else if(ctx -> token == RECORD)
+ {
+ type = oberon_new_type_ptr(OBERON_TYPE_RECORD);
+ oberon_object_t * list = malloc(sizeof *list);
+ memset(list, 0, sizeof *list);
+ type -> num_decl = 0;
+ type -> base = NULL;
+ type -> decl = list;
+
+ oberon_assert_token(ctx, RECORD);
+ oberon_field_list(ctx, type);
+ while(ctx -> token == SEMICOLON)
+ {
+ oberon_assert_token(ctx, SEMICOLON);
+ oberon_field_list(ctx, type);
+ }
+ oberon_assert_token(ctx, END);
+
+ type -> decl = type -> decl -> next;
+ oberon_generator_init_type(ctx, type);
+ }
+ else if(ctx -> token == PROCEDURE)
+ {
+ oberon_assert_token(ctx, PROCEDURE);
+ type = oberon_opt_formal_pars(ctx, OBERON_TYPE_PROCEDURE);
+ }
+ else
+ {
+ oberon_error(ctx, "invalid type declaration");
}
return type;
char * name = oberon_assert_ident(ctx);
oberon_assert_token(ctx, COLON);
oberon_type_t * type = oberon_type(ctx);
- oberon_define_var(ctx, name, type);
+ oberon_define_var(ctx -> decl, OBERON_CLASS_VAR, name, type);
+}
+
+static oberon_object_t *
+oberon_make_param(oberon_context_t * ctx, int token, char * name, oberon_type_t * type)
+{
+ oberon_object_t * param;
+
+ if(token == VAR)
+ {
+ param = oberon_define_var(ctx -> decl, OBERON_CLASS_VAR_PARAM, name, type);
+ }
+ else if(token == IDENT)
+ {
+ param = oberon_define_var(ctx -> decl, OBERON_CLASS_PARAM, name, type);
+ }
+ else
+ {
+ oberon_error(ctx, "oberon_make_param: wat");
+ }
+
+ return param;
+}
+
+static oberon_object_t *
+oberon_fp_section(oberon_context_t * ctx, int * num_decl)
+{
+ int modifer_token = ctx -> token;
+ if(ctx -> token == VAR)
+ {
+ oberon_read_token(ctx);
+ }
+
+ char * name;
+ name = oberon_assert_ident(ctx);
+
+ oberon_assert_token(ctx, COLON);
+
+ oberon_type_t * type;
+ type = oberon_type(ctx);
+
+ oberon_object_t * first;
+ first = oberon_make_param(ctx, modifer_token, name, type);
+
+ *num_decl += 1;
+ return first;
+}
+
+#define ISFPSECTION \
+ ((ctx -> token == VAR) || (ctx -> token == IDENT))
+
+static oberon_type_t *
+oberon_formal_pars(oberon_context_t * ctx)
+{
+ oberon_type_t * tp;
+ tp = oberon_new_type_ptr(OBERON_TYPE_PROCEDURE);
+ tp -> num_decl = 0;
+ tp -> base = ctx -> void_type;
+ tp -> decl = NULL;
+
+ oberon_assert_token(ctx, LPAREN);
+
+ if(ISFPSECTION)
+ {
+ tp -> decl = oberon_fp_section(ctx, &tp -> num_decl);
+ while(ctx -> token == SEMICOLON)
+ {
+ oberon_assert_token(ctx, SEMICOLON);
+ oberon_fp_section(ctx, &tp -> num_decl);
+ }
+ }
+
+ oberon_assert_token(ctx, RPAREN);
+
+ if(ctx -> token == COLON)
+ {
+ oberon_assert_token(ctx, COLON);
+ tp -> base = oberon_type(ctx);
+ }
+
+ oberon_generator_init_type(ctx, tp);
+ return tp;
+}
+
+static oberon_type_t *
+oberon_opt_formal_pars(oberon_context_t * ctx, int class)
+{
+ oberon_type_t * signature;
+
+ if(ctx -> token == LPAREN)
+ {
+ signature = oberon_formal_pars(ctx);
+ }
+ else
+ {
+ signature = oberon_new_type_ptr(class);
+ signature -> num_decl = 0;
+ signature -> base = ctx -> void_type;
+ signature -> decl = NULL;
+ oberon_generator_init_type(ctx, signature);
+ }
+
+ return signature;
+}
+
+static void
+oberon_make_return(oberon_context_t * ctx, oberon_expr_t * expr)
+{
+ if(ctx -> result_type -> class == OBERON_TYPE_VOID)
+ {
+ if(expr != NULL)
+ {
+ oberon_error(ctx, "procedure has no result type");
+ }
+ }
+ else
+ {
+ if(expr == NULL)
+ {
+ oberon_error(ctx, "procedure requires expression on result");
+ }
+
+ oberon_autocast_to(ctx, expr, ctx -> result_type);
+ }
+
+ ctx -> has_return = 1;
+
+ oberon_generate_return(ctx, expr);
+}
+
+static void
+oberon_proc_decl(oberon_context_t * ctx)
+{
+ oberon_assert_token(ctx, PROCEDURE);
+
+ char * name;
+ name = oberon_assert_ident(ctx);
+
+ oberon_scope_t * this_proc_def_scope = ctx -> decl;
+ oberon_open_scope(ctx);
+
+ oberon_type_t * signature;
+ signature = oberon_opt_formal_pars(ctx, OBERON_TYPE_PROCEDURE);
+
+ oberon_object_t * proc;
+ proc = oberon_define_proc(this_proc_def_scope, name, signature);
+
+ ctx -> result_type = signature -> base;
+ ctx -> has_return = 0;
+
+ oberon_assert_token(ctx, SEMICOLON);
+
+ oberon_generate_begin_proc(ctx, proc);
+
+ // TODO declarations
+
+ if(ctx -> token == BEGIN)
+ {
+ oberon_assert_token(ctx, BEGIN);
+ oberon_statement_seq(ctx);
+ }
+
+ oberon_assert_token(ctx, END);
+ char * name2 = oberon_assert_ident(ctx);
+ if(strcmp(name2, name) != 0)
+ {
+ oberon_error(ctx, "procedure name not matched");
+ }
+
+ if(signature -> base -> class == OBERON_TYPE_VOID)
+ {
+ oberon_make_return(ctx, NULL);
+ }
+
+ if(ctx -> has_return == 0)
+ {
+ oberon_error(ctx, "procedure requires return");
+ }
+ ctx -> result_type = NULL;
+
+ oberon_generate_end_proc(ctx);
+ oberon_close_scope(ctx -> decl);
+}
+
+static void
+oberon_const_decl(oberon_context_t * ctx)
+{
+ char * name;
+ oberon_item_t * value;
+ oberon_object_t * constant;
+
+ name = oberon_assert_ident(ctx);
+ oberon_assert_token(ctx, EQUAL);
+ value = oberon_const_expr(ctx);
+
+ constant = oberon_define_object(ctx -> decl, name, OBERON_CLASS_CONST);
+ constant -> value = value;
+}
+
+static void
+oberon_type_decl(oberon_context_t * ctx)
+{
+ char * name;
+ oberon_object_t * newtype;
+ oberon_type_t * type;
+
+ name = oberon_assert_ident(ctx);
+ oberon_assert_token(ctx, EQUAL);
+ type = oberon_type(ctx);
+
+ newtype = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE);
+ newtype -> type = type;
}
static void
oberon_decl_seq(oberon_context_t * ctx)
{
+ if(ctx -> token == CONST)
+ {
+ oberon_assert_token(ctx, CONST);
+ while(ctx -> token == IDENT)
+ {
+ oberon_const_decl(ctx);
+ oberon_assert_token(ctx, SEMICOLON);
+ }
+ }
+
+ if(ctx -> token == TYPE)
+ {
+ oberon_assert_token(ctx, TYPE);
+ while(ctx -> token == IDENT)
+ {
+ oberon_type_decl(ctx);
+ oberon_assert_token(ctx, SEMICOLON);
+ }
+ }
+
if(ctx -> token == VAR)
{
oberon_assert_token(ctx, VAR);
oberon_assert_token(ctx, SEMICOLON);
}
}
+
+ while(ctx -> token == PROCEDURE)
+ {
+ oberon_proc_decl(ctx);
+ oberon_assert_token(ctx, SEMICOLON);
+ }
}
static void
oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
{
-// if(dst -> mode == MODE_INTEGER)
-// {
-// oberon_error(ctx, "invalid assignment");
-// }
-//
-// oberon_autocast_to(ctx, src, dst);
-
+ oberon_autocast_to(ctx, src, dst -> result);
oberon_generate_assign(ctx, src, dst);
}
+static void
+oberon_make_call(oberon_context_t * ctx, oberon_expr_t * desig)
+{
+ oberon_autocast_call(ctx, desig);
+ oberon_generate_call_proc(ctx, desig);
+}
+
static void
oberon_statement(oberon_context_t * ctx)
{
if(ctx -> token == IDENT)
{
- item1 = oberon_expr(ctx);
- oberon_assert_token(ctx, ASSIGN);
- item2 = oberon_expr(ctx);
- oberon_assign(ctx, item2, item1);
+ item1 = oberon_designator(ctx);
+ if(ctx -> token == ASSIGN)
+ {
+ oberon_assert_token(ctx, ASSIGN);
+ item2 = oberon_expr(ctx);
+ oberon_assign(ctx, item2, item1);
+ }
+ else
+ {
+ item1 = oberon_opt_proc_parens(ctx, item1);
+ oberon_make_call(ctx, item1);
+ }
+ }
+ else if(ctx -> token == RETURN)
+ {
+ oberon_assert_token(ctx, RETURN);
+ if(ISEXPR(ctx -> token))
+ {
+ oberon_expr_t * expr;
+ expr = oberon_expr(ctx);
+ oberon_make_return(ctx, expr);
+ }
+ else
+ {
+ oberon_make_return(ctx, NULL);
+ }
}
}
// LIBRARY
// =======================================================================
-static oberon_type_t *
-oberon_register_global_type_ret(oberon_context_t * ctx, oberon_type_t * type)
-{
- oberon_type_t * x = ctx -> types;
- while(x -> next && strcmp(x -> next -> name, type -> name) != 0)
- {
- x = x -> next;
- }
-
- if(x -> next)
- {
- oberon_error(ctx, "already defined");
- }
-
- // TODO: copy type name (not a pointer)
- oberon_type_t * newtype = malloc(sizeof *newtype);
- memcpy(newtype, type, sizeof *newtype);
- newtype -> next = NULL;
- oberon_generator_init_type(ctx, newtype);
-
- x -> next = newtype;
- return newtype;
-}
-
static void
register_default_types(oberon_context_t * ctx)
{
- static oberon_type_t integer = { "INTEGER", OBERON_TYPE_INTEGER, sizeof(int) };
- static oberon_type_t boolean = { "BOOLEAN", OBERON_TYPE_BOOLEAN, sizeof(int) };
+ ctx -> void_type = oberon_new_type_ptr(OBERON_TYPE_VOID);
+ oberon_generator_init_type(ctx, ctx -> void_type);
- ctx -> int_type = oberon_register_global_type_ret(ctx, &integer);
- ctx -> bool_type = oberon_register_global_type_ret(ctx, &boolean);
-}
+ ctx -> int_type = oberon_new_type_integer(sizeof(int));
+ oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type);
-void
-oberon_register_global_type(oberon_context_t * ctx, oberon_type_t * type)
-{
- oberon_register_global_type_ret(ctx, type);
+ ctx -> bool_type = oberon_new_type_boolean(sizeof(int));
+ oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type);
}
oberon_context_t *
oberon_context_t * ctx = malloc(sizeof *ctx);
memset(ctx, 0, sizeof *ctx);
- oberon_type_t * types = malloc(sizeof *types);
- memset(types, 0, sizeof *types);
- ctx -> types = types;
+ oberon_scope_t * world_scope;
+ world_scope = oberon_open_scope(ctx);
+ ctx -> world_scope = world_scope;
oberon_generator_init_context(ctx);
{
oberon_module_t * mod = malloc(sizeof *mod);
memset(mod, 0, sizeof *mod);
- oberon_var_t * vars = malloc(sizeof *vars);
- memset(vars, 0, sizeof *vars);
ctx -> mod = mod;
- ctx -> mod -> vars = vars;
+
+ oberon_scope_t * module_scope;
+ module_scope = oberon_open_scope(ctx);
+ mod -> decl = module_scope;
oberon_init_scaner(ctx, code);
oberon_parse_module(ctx);
oberon_generate_code(ctx);
+
+ ctx -> mod = NULL;
return mod;
}
-