DEADSOFTWARE

Добавлены выражения
[dsw-obn.git] / oberon.c
index 4dfc604a5f38159b0d1668b8376b0cc4fa8195e7..ec4cab05b3804d3c204407e28dcbb2eff1ccea22 100644 (file)
--- a/oberon.c
+++ b/oberon.c
@@ -22,7 +22,22 @@ enum {
        TRUE,
        FALSE,
        LPAREN,
-       RPAREN
+       RPAREN,
+       EQUAL,
+       NEQ,
+       LESS,
+       LEQ,
+       GREAT,
+       GEQ,
+       PLUS,
+       MINUS,
+       OR,
+       STAR,
+       SLASH,
+       DIV,
+       MOD,
+       AND,
+       NOT
 };
 
 // =======================================================================
@@ -44,6 +59,7 @@ oberon_error(oberon_context_t * ctx, const char * fmt, ...)
        exit(1);
 }
 
+/*
 static int
 oberon_item_to_type_class(oberon_context_t * ctx, oberon_item_t * item)
 {
@@ -67,7 +83,9 @@ oberon_item_to_type_class(oberon_context_t * ctx, oberon_item_t * item)
 
        return class;
 }
+*/
 
+/*
 static void
 oberon_autocast_to(oberon_context_t * ctx, oberon_item_t * from, oberon_item_t * to)
 {
@@ -79,6 +97,7 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_item_t * from, oberon_item_t *
                oberon_error(ctx, "oberon_autocast_to: types not matched %i -> %i", from_class, to_class);
        }
 }
+*/
 
 // =======================================================================
 //   TABLE
@@ -197,6 +216,18 @@ oberon_read_ident(oberon_context_t * ctx)
        {
                ctx -> token = FALSE;
        }
+       else if(strcmp(ident, "OR") == 0)
+       {
+               ctx -> token = OR;
+       }
+       else if(strcmp(ident, "DIV") == 0)
+       {
+               ctx -> token = DIV;
+       }
+       else if(strcmp(ident, "MOD") == 0)
+       {
+               ctx -> token = MOD;
+       }
 }
 
 static void
@@ -267,6 +298,56 @@ oberon_read_symbol(oberon_context_t * ctx)
                        ctx -> token = RPAREN;
                        oberon_get_char(ctx);
                        break;
+               case '=':
+                       ctx -> token = EQUAL;
+                       oberon_get_char(ctx);
+                       break;
+               case '#':
+                       ctx -> token = NEQ;
+                       oberon_get_char(ctx);
+                       break;
+               case '<':
+                       ctx -> token = LESS;
+                       oberon_get_char(ctx);
+                       if(ctx -> c == '=')
+                       {
+                               ctx -> token = LEQ;
+                               oberon_get_char(ctx);
+                       }
+                       break;
+               case '>':
+                       ctx -> token = GREAT;
+                       oberon_get_char(ctx);
+                       if(ctx -> c == '=')
+                       {
+                               ctx -> token = GEQ;
+                               oberon_get_char(ctx);
+                       }
+                       break;
+               case '+':
+                       ctx -> token = PLUS;
+                       oberon_get_char(ctx);
+                       break;
+               case '-':
+                       ctx -> token = MINUS;
+                       oberon_get_char(ctx);
+                       break;
+               case '*':
+                       ctx -> token = STAR;
+                       oberon_get_char(ctx);
+                       break;
+               case '/':
+                       ctx -> token = SLASH;
+                       oberon_get_char(ctx);
+                       break;
+               case '&':
+                       ctx -> token = AND;
+                       oberon_get_char(ctx);
+                       break;
+               case '~':
+                       ctx -> token = NOT;
+                       oberon_get_char(ctx);
+                       break;
                default:
                        oberon_error(ctx, "invalid char");
                        break;
@@ -294,22 +375,56 @@ oberon_read_token(oberon_context_t * ctx)
 }
 
 // =======================================================================
-//   EXPR
+//   EXPRESSION
 // =======================================================================
 
 static void oberon_expect_token(oberon_context_t * ctx, int token);
-static oberon_item_t * oberon_expr(oberon_context_t * ctx);
+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_item_t *
+static oberon_expr_t *
+oberon_new_operator(int op, oberon_type_t * result, oberon_expr_t * left, oberon_expr_t * right)
+{
+       oberon_oper_t * operator;
+       operator = malloc(sizeof *operator);
+       memset(operator, 0, sizeof *operator);
+
+       operator -> is_item = 0;
+       operator -> result = result;
+       operator -> op = op;
+       operator -> left = left;
+       operator -> right = right;
+
+       return (oberon_expr_t *) operator;
+}
+
+static oberon_expr_t *
+oberon_new_item(int mode, oberon_type_t * result)
+{
+       oberon_item_t * item;
+        item = malloc(sizeof *item);
+        memset(item, 0, sizeof *item);
+
+       item -> is_item = 1;
+       item -> result = result;
+       item -> mode = mode;
+
+       return (oberon_expr_t *)item;
+}
+
+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_item_t * item = malloc(sizeof *item);
-       memset(item, 0, sizeof *item);
+       oberon_expr_t * expr;
 
        switch(ctx -> token)
        {
@@ -320,40 +435,229 @@ oberon_factor(oberon_context_t * ctx)
                        {
                                oberon_error(ctx, "undefined variable %s", name);
                        }
-                       item -> mode = MODE_VAR;
-                       item -> var = var;
+                       expr = oberon_new_item(MODE_VAR, var -> type);
+                       expr -> item.var = var;
                        break;
                case INTEGER:
-                       item -> mode = MODE_INTEGER;
-                       item -> integer = ctx -> integer;
+                       expr = oberon_new_item(MODE_INTEGER, ctx -> int_type);
+                       expr -> item.integer = ctx -> integer;
                        oberon_assert_token(ctx, INTEGER);
                        break;
                case TRUE:
-                       item -> mode = MODE_BOOLEAN;
-                       item -> boolean = 1;
+                       expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type);
+                       expr -> item.boolean = 1;
                        oberon_assert_token(ctx, TRUE);
                        break;
                case FALSE:
-                       item -> mode = MODE_BOOLEAN;
-                       item -> boolean = 0;
+                       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);
-                       item = oberon_expr(ctx);
+                       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 item;    
+       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_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)
+       {
+               expr = oberon_new_operator(OP_DIV, result, a, b);
+       }
+       else if(token == MOD)
+       {
+               expr = oberon_new_operator(OP_MOD, result, a, b);
+       }
+       else if(token == AND)
+       {
+               expr = oberon_new_operator(OP_LOGIC_AND, result, a, b);
+       }
+       else
+       {
+               oberon_error(ctx, "oberon_make_mul_op: 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_mul_op(ctx, token, expr, inter);
+       }
+
+       return expr;
 }
 
-static oberon_item_t *
+static oberon_expr_t *
+oberon_make_add_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+{
+       oberon_expr_t * expr;
+       oberon_type_t * result;
+
+       result = a -> 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 == OR)
+       {
+               expr = oberon_new_operator(OP_LOGIC_OR, result, a, b);
+       }
+       else
+       {
+               oberon_error(ctx, "oberon_make_add_op: wat");
+       }
+
+       return expr;
+}
+
+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 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_add_op(ctx, token, expr, inter);
+       }
+
+       if(minus)
+       {
+               expr = oberon_make_unary_minus(ctx, expr);
+       }
+
+       return expr;
+}
+
+static oberon_expr_t *
+oberon_make_relation(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
+{
+       oberon_expr_t * expr;
+       oberon_type_t * result;
+
+       result = a -> result;
+
+       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
+       {
+               oberon_error(ctx, "oberon_make_relation: wat");
+       }       
+
+       return expr;
+}
+
+#define ISRELATION(x) \
+       ((x) >= EQUAL && (x) <= GEQ)
+
+static oberon_expr_t *
 oberon_expr(oberon_context_t * ctx)
 {
-       return oberon_factor(ctx);
+       oberon_expr_t * expr;
+
+       expr = oberon_simple_expr(ctx);
+       while(ISRELATION(ctx -> token))
+       {
+               int token = ctx -> token;
+               oberon_read_token(ctx);
+
+               oberon_expr_t * inter = oberon_simple_expr(ctx);
+               expr = oberon_make_relation(ctx, token, expr, inter);
+       }
+
+       return expr;
 }
 
 // =======================================================================
@@ -423,14 +727,14 @@ oberon_decl_seq(oberon_context_t * ctx)
 }
 
 static void
-oberon_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst)
+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);
+//     if(dst -> mode == MODE_INTEGER)
+//     {
+//             oberon_error(ctx, "invalid assignment");
+//     }
+//
+//     oberon_autocast_to(ctx, src, dst);
 
        oberon_generate_assign(ctx, src, dst);
 }
@@ -438,8 +742,8 @@ oberon_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst)
 static void
 oberon_statement(oberon_context_t * ctx)
 {
-       oberon_item_t * item1;
-       oberon_item_t * item2;
+       oberon_expr_t * item1;
+       oberon_expr_t * item2;
 
        if(ctx -> token == IDENT)
        {
@@ -496,6 +800,46 @@ oberon_parse_module(oberon_context_t * ctx)
 //   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 -> int_type = oberon_register_global_type_ret(ctx, &integer);
+       ctx -> bool_type = oberon_register_global_type_ret(ctx, &boolean);
+}
+
+void
+oberon_register_global_type(oberon_context_t * ctx, oberon_type_t * type)
+{
+       oberon_register_global_type_ret(ctx, type);
+}
+
 oberon_context_t *
 oberon_create_context()
 {
@@ -504,9 +848,12 @@ oberon_create_context()
 
        oberon_type_t * types = malloc(sizeof *types);
        memset(types, 0, sizeof *types);
+       ctx -> types = types;
 
        oberon_generator_init_context(ctx);
-       ctx -> types = types;
+
+       register_default_types(ctx);    
+
        return ctx;
 }
 
@@ -534,25 +881,3 @@ oberon_compile_module(oberon_context_t * ctx, const char * code)
        return mod;
 }
 
-void
-oberon_register_global_type(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;
-}