#include #include #include #include #include #include "oberon.h" enum { EOF_ = 0, IDENT, MODULE, SEMICOLON, END, DOT, VAR, COLON, BEGIN, ASSIGN, INTEGER }; enum { MODE_VAR, MODE_INTEGER, }; typedef struct { int mode; int integer; oberon_var_t * var; } oberon_item_t; // ======================================================================= // UTILS // ======================================================================= static void oberon_error(oberon_context_t * ctx, const char * fmt, ...) { va_list ptr; va_start(ptr, fmt); fprintf(stderr, "error: "); vfprintf(stderr, fmt, ptr); fprintf(stderr, "\n"); fprintf(stderr, " code_index = %i\n", ctx -> code_index); fprintf(stderr, " c = %c\n", ctx -> c); fprintf(stderr, " token = %i\n", ctx -> token); va_end(ptr); exit(1); } static int oberon_item_to_type_class(oberon_context_t * ctx, oberon_item_t * item) { int class; if(item -> mode == MODE_INTEGER) { class = OBERON_TYPE_INTEGER; } else if(item -> mode == MODE_VAR) { class = item -> var -> type -> class; } else { oberon_error(ctx, "oberon_item_to_type_class: wat"); } return class; } // ======================================================================= // TABLE // ======================================================================= static oberon_type_t * oberon_find_type(oberon_context_t * ctx, char * name) { oberon_type_t * x = ctx -> types; while(x -> next && strcmp(x -> next -> name, name) != 0) { x = x -> next; } return x -> next; } static oberon_var_t * oberon_find_var(oberon_context_t * ctx, char * name) { oberon_var_t * x = ctx -> mod -> vars; while(x -> next && strcmp(x -> next -> name, name) != 0) { x = x -> next; } return x -> next; } static void oberon_define_var(oberon_context_t * ctx, char * name, oberon_type_t * type) { oberon_var_t * x = ctx -> mod -> vars; while(x -> next && strcmp(x -> next -> name, name) != 0) { x = x -> next; } if(x -> next) { oberon_error(ctx, "already defined"); } oberon_var_t * newvar = malloc(sizeof *newvar); memset(newvar, 0, sizeof *newvar); newvar -> name = name; newvar -> type = type; x -> next = newvar; } // ======================================================================= // GENERATOR // ======================================================================= static void oberon_generate_assign(oberon_context_t * ctx, void * src, void * dst, int size) { printf("G: %p := %p (%i);\n", dst, src, size); } // ======================================================================= // SCANER // ======================================================================= static void oberon_get_char(oberon_context_t * ctx) { ctx -> code_index += 1; ctx -> c = ctx -> code[ctx -> code_index]; } static void oberon_init_scaner(oberon_context_t * ctx, const char * code) { ctx -> code = code; ctx -> code_index = 0; ctx -> c = ctx -> code[ctx -> code_index]; } static void oberon_read_ident(oberon_context_t * ctx) { int len = 0; int i = ctx -> code_index; int c = ctx -> code[i]; while(isalnum(c)) { i += 1; len += 1; c = ctx -> code[i]; } char * ident = malloc(len + 2); memcpy(ident, &ctx->code[ctx->code_index], len); ident[len + 1] = 0; ctx -> code_index = i; ctx -> c = ctx -> code[i]; ctx -> string = ident; ctx -> token = IDENT; if(strcmp(ident, "MODULE") == 0) { ctx -> token = MODULE; } else if(strcmp(ident, "END") == 0) { ctx -> token = END; } else if(strcmp(ident, "VAR") == 0) { ctx -> token = VAR; } else if(strcmp(ident, "BEGIN") == 0) { ctx -> token = BEGIN; } } static void oberon_read_integer(oberon_context_t * ctx) { int len = 0; int i = ctx -> code_index; int c = ctx -> code[i]; while(isdigit(c)) { i += 1; len += 1; c = ctx -> code[i]; } char * ident = malloc(len + 2); memcpy(ident, &ctx->code[ctx->code_index], len); ident[len + 1] = 0; ctx -> code_index = i; ctx -> c = ctx -> code[i]; ctx -> string = ident; ctx -> integer = atoi(ident); ctx -> token = INTEGER; } static void oberon_skip_space(oberon_context_t * ctx) { while(isspace(ctx -> c)) { oberon_get_char(ctx); } } static void oberon_read_token(oberon_context_t * ctx) { oberon_skip_space(ctx); int c = ctx -> c; if(isalpha(c)) { oberon_read_ident(ctx); } else if(isdigit(c)) { oberon_read_integer(ctx); } else { switch(c) { case 0: ctx -> token = EOF_; break; case ';': ctx -> token = SEMICOLON; oberon_get_char(ctx); break; case ':': /****************************************************/ ctx -> token = COLON; oberon_get_char(ctx); if(ctx -> c == '=') { ctx -> token = ASSIGN; oberon_get_char(ctx); } break; /****************************************************/ case '.': ctx -> token = DOT; oberon_get_char(ctx); break; default: oberon_error(ctx, "invalid char"); } } } // ======================================================================= // PARSER // ======================================================================= static void oberon_expect_token(oberon_context_t * ctx, int token) { if(ctx -> token != token) { oberon_error(ctx, "unexpected token %i (%i)", ctx -> token, token); } } static void oberon_assert_token(oberon_context_t * ctx, int token) { oberon_expect_token(ctx, token); oberon_read_token(ctx); } static char * oberon_assert_ident(oberon_context_t * ctx) { char * ident; oberon_expect_token(ctx, IDENT); ident = ctx -> string; oberon_read_token(ctx); return ident; } 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); if(type == NULL) { oberon_error(ctx, "undefined type"); } return type; } static void oberon_var_decl(oberon_context_t * ctx) { char * name = oberon_assert_ident(ctx); oberon_assert_token(ctx, COLON); oberon_type_t * type = oberon_type(ctx); oberon_define_var(ctx, name, type); } static void oberon_decl_seq(oberon_context_t * ctx) { if(ctx -> token == VAR) { oberon_assert_token(ctx, VAR); while(ctx -> token == IDENT) { oberon_var_decl(ctx); oberon_assert_token(ctx, SEMICOLON); } } } static oberon_item_t * oberon_expr(oberon_context_t * ctx) { oberon_item_t * item = malloc(sizeof *item); memset(item, 0, sizeof *item); if(ctx -> token == IDENT) { char * name = oberon_assert_ident(ctx); oberon_var_t * var = oberon_find_var(ctx, name); if(var == NULL) { oberon_error(ctx, "undefined variable"); } item -> mode = MODE_VAR; item -> var = var; } else if(ctx -> token == INTEGER) { item -> mode = MODE_INTEGER; item -> integer = ctx -> integer; oberon_assert_token(ctx, INTEGER); } else { oberon_error(ctx, "invalid expression"); } return item; } static void oberon_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst) { if(dst -> mode == MODE_INTEGER) { oberon_error(ctx, "invalid assignment"); } int src_class = oberon_item_to_type_class(ctx, src); int dst_class = oberon_item_to_type_class(ctx, dst); if(src_class != dst_class) { oberon_error(ctx, "types not matched"); } // TODO: code generation oberon_generate_assign(ctx, 0, 0, 4); } static void oberon_statement(oberon_context_t * ctx) { oberon_item_t * item1; oberon_item_t * item2; if(ctx -> token == IDENT) { item1 = oberon_expr(ctx); oberon_assert_token(ctx, ASSIGN); item2 = oberon_expr(ctx); oberon_assign(ctx, item2, item1); } } static void oberon_statement_seq(oberon_context_t * ctx) { oberon_statement(ctx); while(ctx -> token == SEMICOLON) { oberon_assert_token(ctx, SEMICOLON); oberon_statement(ctx); } } static void oberon_parse_it(oberon_context_t * ctx) { char *name1, *name2; oberon_read_token(ctx); oberon_assert_token(ctx, MODULE); name1 = oberon_assert_ident(ctx); oberon_assert_token(ctx, SEMICOLON); ctx -> mod -> name = name1; oberon_decl_seq(ctx); if(ctx -> token == BEGIN) { oberon_assert_token(ctx, BEGIN); oberon_statement_seq(ctx); } oberon_assert_token(ctx, END); name2 = oberon_assert_ident(ctx); oberon_assert_token(ctx, DOT); if(strcmp(name1, name2) != 0) { oberon_error(ctx, "module name not matched"); } } // ======================================================================= // LIBRARY // ======================================================================= oberon_context_t * oberon_create_context() { 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; return ctx; } oberon_module_t * oberon_compile_module(oberon_context_t * ctx, const char * code) { 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_init_scaner(ctx, code); oberon_parse_it(ctx); 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; x -> next = newtype; }