From: DeaDDooMER Date: Mon, 24 Jul 2017 19:03:31 +0000 (+0300) Subject: Добавлены типы INTEGER и BOOLEAN X-Git-Url: https://deadsoftware.ru/gitweb?p=dsw-obn.git;a=commitdiff_plain;h=c3449e207b5e1e85ecea55975163a4dc6b986962 Добавлены типы INTEGER и BOOLEAN --- diff --git a/generator.c b/generator.c new file mode 100644 index 0000000..c633e54 --- /dev/null +++ b/generator.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include + +#include "oberon.h" +#include "generator.h" + +#include + +/* + * oberon_var_t -> gvar == gcc_jit_lvalue; + * oberon_type_t -> gtype == gcc_jit_type; + * oberon_context_t -> gctx == gen_context_t; + */ + +typedef struct +{ + gcc_jit_context * gcc_context; + gcc_jit_block * gcc_block; + gcc_jit_result * gcc_result; +} gen_context_t; + +static void printcontext(oberon_context_t * ctx, char * s) +{ +/* + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + gcc_jit_block * gcc_block = gen_context -> gcc_block; + + printf("%s:\n", s); + printf(" ctx = %p:\n", ctx); + printf(" gctx = %p:\n", gctx); + printf(" context = %p:\n", context); + printf(" block = %p:\n", block); +*/ +} + +// ======================================================================= +// ALLOC +// ======================================================================= + +void +oberon_generator_init_context(oberon_context_t * ctx) +{ + gen_context_t * gen_context = malloc(sizeof *gen_context); + memset(gen_context, 0, sizeof *gen_context); + + gcc_jit_context * gcc_context; + gcc_context = gcc_jit_context_acquire(); + + ctx -> gen_context = gen_context; + gen_context -> gcc_context = gcc_context; + + printcontext(ctx, "oberon_generator_init_context"); +} + +void +oberon_generator_destroy_context(oberon_context_t * ctx) +{ + printcontext(ctx, "oberon_generator_destroy_context"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + + gcc_jit_context_release(gcc_context); +} + +void +oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type) +{ + printcontext(ctx, "oberon_generator_init_type"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + + gcc_jit_type * gen_type; + if(type -> class == OBERON_TYPE_INTEGER) + { + gen_type = gcc_jit_context_get_int_type(gcc_context, type -> size, 1); + } + else if(type -> class == OBERON_TYPE_BOOLEAN) + { + gen_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL); + } + else + { + oberon_error(ctx, "oberon_generator_init_type: invalid type class %i", type -> class); + } + + type -> gen_type = gen_type; +} + +void +oberon_generator_init_var(oberon_context_t * ctx, oberon_var_t * var) +{ + printcontext(ctx, "oberon_generator_init_var"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + gcc_jit_type * gen_type = var -> type -> gen_type; + const char * name = var -> name; + + gcc_jit_lvalue * gen_var; + gen_var = gcc_jit_context_new_global(gcc_context, NULL, GCC_JIT_GLOBAL_INTERNAL, gen_type, name); + + var -> gen_var = gen_var; +} + +// ======================================================================= +// GENERATOR +// ======================================================================= + +static gcc_jit_rvalue * +oberon_generate_rvalue_from_item(oberon_context_t * ctx, oberon_item_t * item) +{ + printcontext(ctx, "oberon_generate_rvalue_from_item"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + + gcc_jit_rvalue * right; + if(item -> mode == MODE_VAR) + { + gcc_jit_lvalue * gen_var = item -> var -> gen_var; + right = gcc_jit_lvalue_as_rvalue(gen_var); + printf("PUSH (var) %s\n", item -> var -> name); + } + else if(item -> mode == MODE_INTEGER) + { + gcc_jit_type * int_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_INT); + right = gcc_jit_context_new_rvalue_from_int(gcc_context, int_type, item -> integer); + printf("PUSH (int) %i\n", item -> integer); + } + else if(item -> mode == MODE_BOOLEAN) + { + gcc_jit_type * bool_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_BOOL); + if(item -> boolean) + { + right = gcc_jit_context_one(gcc_context, bool_type); + } + else + { + right = gcc_jit_context_zero(gcc_context, bool_type); + } + printf("PUSH (bool) %i\n", item -> boolean); + } + else + { + oberon_error(ctx, "oberon_generate_push: invalid mode %i", item -> mode); + } + + return right; +} + +void +oberon_generate_begin_module(oberon_context_t * ctx) +{ + printcontext(ctx, "oberon_generate_begin_module"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + + gcc_jit_type * void_type = gcc_jit_context_get_type(gcc_context, GCC_JIT_TYPE_VOID); + gcc_jit_function * func = gcc_jit_context_new_function( + gcc_context, NULL, GCC_JIT_FUNCTION_EXPORTED, void_type, "BEGIN", 0, NULL, 0 + ); + gcc_jit_block * gcc_block = gcc_jit_function_new_block(func, NULL); + + gen_context -> gcc_block = gcc_block; +} + +void +oberon_generate_end_module(oberon_context_t * ctx) +{ + printcontext(ctx, "oberon_generate_end_module"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_block * gcc_block = gen_context -> gcc_block; + + gcc_jit_block_end_with_void_return(gcc_block, NULL); + + gen_context -> gcc_block = NULL; +} + +void +oberon_generate_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst) +{ + printcontext(ctx, "oberon_generate_assign"); + + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_block * gcc_block = gen_context -> gcc_block; + + gcc_jit_lvalue * left; + gcc_jit_rvalue * right; + + right = oberon_generate_rvalue_from_item(ctx, src); + + if(dst -> mode == MODE_VAR) + { + printf("STORE %s\n", dst -> var -> name); + left = dst -> var -> gen_var; + } + else + { + oberon_error(ctx, "oberon_generate_assign: invalid assignment"); + } + + gcc_jit_block_add_assignment(gcc_block, NULL, left, right); +} + +void +oberon_generate_code(oberon_context_t * ctx) +{ + gen_context_t * gen_context = ctx -> gen_context; + gcc_jit_context * gcc_context = gen_context -> gcc_context; + + gcc_jit_result * gcc_result; + gcc_result = gcc_jit_context_compile(gcc_context); + + gen_context -> gcc_result = gcc_result; + ctx -> mod -> begin = gcc_jit_result_get_code(gcc_result, "BEGIN"); +} diff --git a/generator.h b/generator.h new file mode 100644 index 0000000..e9dbd53 --- /dev/null +++ b/generator.h @@ -0,0 +1,11 @@ +void oberon_generator_init_context(oberon_context_t * ctx); +void oberon_generator_destroy_context(oberon_context_t * ctx); +void oberon_generator_init_type(oberon_context_t * ctx, oberon_type_t * type); +void oberon_generator_init_var(oberon_context_t * ctx, oberon_var_t * var); + +void oberon_generate_begin_module(oberon_context_t * ctx); +void oberon_generate_end_module(oberon_context_t * ctx); + +void oberon_generate_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst); + +void oberon_generate_code(oberon_context_t * ctx); diff --git a/make.sh b/make.sh index fe43cd6..286e5ff 100755 --- a/make.sh +++ b/make.sh @@ -2,4 +2,4 @@ set -e -cc -g -Wall -Werror -std=c11 *.c +cc -g -Wall -Werror -std=c11 -lgccjit *.c diff --git a/oberon.c b/oberon.c index e411c6c..4dfc604 100644 --- a/oberon.c +++ b/oberon.c @@ -3,7 +3,9 @@ #include #include #include + #include "oberon.h" +#include "generator.h" enum { EOF_ = 0, @@ -16,26 +18,18 @@ enum { COLON, BEGIN, ASSIGN, - INTEGER -}; - -enum { - MODE_VAR, - MODE_INTEGER, + INTEGER, + TRUE, + FALSE, + LPAREN, + RPAREN }; -typedef struct -{ - int mode; - int integer; - oberon_var_t * var; -} oberon_item_t; - // ======================================================================= // UTILS // ======================================================================= -static void +void oberon_error(oberon_context_t * ctx, const char * fmt, ...) { va_list ptr; @@ -55,22 +49,37 @@ oberon_item_to_type_class(oberon_context_t * ctx, oberon_item_t * item) { int class; - if(item -> mode == MODE_INTEGER) + switch(item -> mode) { - 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"); + 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; } +static void +oberon_autocast_to(oberon_context_t * ctx, oberon_item_t * from, oberon_item_t * to) +{ + int from_class = oberon_item_to_type_class(ctx, from); + int to_class = oberon_item_to_type_class(ctx, to); + + if(from_class != to_class) + { + oberon_error(ctx, "oberon_autocast_to: types not matched %i -> %i", from_class, to_class); + } +} + // ======================================================================= // TABLE // ======================================================================= @@ -117,20 +126,11 @@ oberon_define_var(oberon_context_t * ctx, char * name, oberon_type_t * type) memset(newvar, 0, sizeof *newvar); newvar -> name = name; newvar -> type = type; + oberon_generator_init_var(ctx, newvar); 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 // ======================================================================= @@ -164,9 +164,9 @@ oberon_read_ident(oberon_context_t * ctx) c = ctx -> code[i]; } - char * ident = malloc(len + 2); + char * ident = malloc(len + 1); memcpy(ident, &ctx->code[ctx->code_index], len); - ident[len + 1] = 0; + ident[len] = 0; ctx -> code_index = i; ctx -> c = ctx -> code[i]; @@ -189,6 +189,14 @@ oberon_read_ident(oberon_context_t * ctx) { ctx -> token = BEGIN; } + else if(strcmp(ident, "TRUE") == 0) + { + ctx -> token = TRUE; + } + else if(strcmp(ident, "FALSE") == 0) + { + ctx -> token = FALSE; + } } static void @@ -225,6 +233,46 @@ oberon_skip_space(oberon_context_t * ctx) } } +static void +oberon_read_symbol(oberon_context_t * ctx) +{ + int c = ctx -> c; + 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; + case '(': + ctx -> token = LPAREN; + oberon_get_char(ctx); + break; + case ')': + ctx -> token = RPAREN; + oberon_get_char(ctx); + break; + default: + oberon_error(ctx, "invalid char"); + break; + } +} + static void oberon_read_token(oberon_context_t * ctx) { @@ -241,26 +289,73 @@ oberon_read_token(oberon_context_t * 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"); - } + oberon_read_symbol(ctx); } } +// ======================================================================= +// EXPR +// ======================================================================= + +static void oberon_expect_token(oberon_context_t * ctx, int token); +static oberon_item_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 * +oberon_factor(oberon_context_t * ctx) +{ + char * name; + oberon_var_t * var; + + oberon_item_t * item = malloc(sizeof *item); + memset(item, 0, sizeof *item); + + 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); + } + item -> mode = MODE_VAR; + item -> var = var; + break; + case INTEGER: + item -> mode = MODE_INTEGER; + item -> integer = ctx -> integer; + oberon_assert_token(ctx, INTEGER); + break; + case TRUE: + item -> mode = MODE_BOOLEAN; + item -> boolean = 1; + oberon_assert_token(ctx, TRUE); + break; + case FALSE: + item -> mode = MODE_BOOLEAN; + item -> boolean = 0; + oberon_assert_token(ctx, FALSE); + break; + case LPAREN: + oberon_assert_token(ctx, LPAREN); + item = oberon_expr(ctx); + oberon_assert_token(ctx, RPAREN); + break; + default: + oberon_error(ctx, "invalid expression"); + } + + return item; +} + +static oberon_item_t * +oberon_expr(oberon_context_t * ctx) +{ + return oberon_factor(ctx); +} + // ======================================================================= // PARSER // ======================================================================= @@ -284,9 +379,8 @@ oberon_assert_token(oberon_context_t * ctx, int token) static char * oberon_assert_ident(oberon_context_t * ctx) { - char * ident; oberon_expect_token(ctx, IDENT); - ident = ctx -> string; + char * ident = ctx -> string; oberon_read_token(ctx); return ident; } @@ -328,37 +422,6 @@ oberon_decl_seq(oberon_context_t * ctx) } } -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) { @@ -367,16 +430,9 @@ oberon_assign(oberon_context_t * ctx, oberon_item_t * src, oberon_item_t * dst) 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"); - } + oberon_autocast_to(ctx, src, dst); - // TODO: code generation - oberon_generate_assign(ctx, 0, 0, 4); + oberon_generate_assign(ctx, src, dst); } static void @@ -406,7 +462,7 @@ oberon_statement_seq(oberon_context_t * ctx) } static void -oberon_parse_it(oberon_context_t * ctx) +oberon_parse_module(oberon_context_t * ctx) { char *name1, *name2; oberon_read_token(ctx); @@ -421,7 +477,9 @@ oberon_parse_it(oberon_context_t * ctx) if(ctx -> token == BEGIN) { oberon_assert_token(ctx, BEGIN); + oberon_generate_begin_module(ctx); oberon_statement_seq(ctx); + oberon_generate_end_module(ctx); } oberon_assert_token(ctx, END); @@ -447,10 +505,18 @@ oberon_create_context() oberon_type_t * types = malloc(sizeof *types); memset(types, 0, sizeof *types); + oberon_generator_init_context(ctx); ctx -> types = types; return ctx; } +void +oberon_destroy_context(oberon_context_t * ctx) +{ + oberon_generator_destroy_context(ctx); + free(ctx); +} + oberon_module_t * oberon_compile_module(oberon_context_t * ctx, const char * code) { @@ -462,7 +528,9 @@ oberon_compile_module(oberon_context_t * ctx, const char * code) ctx -> mod -> vars = vars; oberon_init_scaner(ctx, code); - oberon_parse_it(ctx); + oberon_parse_module(ctx); + + oberon_generate_code(ctx); return mod; } @@ -484,6 +552,7 @@ oberon_register_global_type(oberon_context_t * ctx, oberon_type_t * type) oberon_type_t * newtype = malloc(sizeof *newtype); memcpy(newtype, type, sizeof *newtype); newtype -> next = NULL; + oberon_generator_init_type(ctx, newtype); x -> next = newtype; } diff --git a/oberon.h b/oberon.h index 7fee329..ec742c6 100644 --- a/oberon.h +++ b/oberon.h @@ -1,22 +1,24 @@ #ifndef EMBEDED_OBERON_SCRIPT_H #define EMBEDED_OBERON_SCRIPT_H -enum { - OBERON_TYPE_INTEGER, - OBERON_TYPE_BOOLEAN, -}; - typedef struct oberon_var_s oberon_var_t; typedef struct oberon_type_s oberon_type_t; typedef struct oberon_module_s oberon_module_t; typedef struct oberon_context_s oberon_context_t; +enum { + OBERON_TYPE_INTEGER, + OBERON_TYPE_BOOLEAN, +}; + struct oberon_type_s { char * name; int class; int size; oberon_type_t * next; + + void * gen_type; }; struct oberon_var_s @@ -24,12 +26,16 @@ struct oberon_var_s char * name; oberon_type_t * type; oberon_var_t * next; + + void * gen_var; }; struct oberon_module_s { char * name; oberon_var_t * vars; + + void (* begin)(); }; struct oberon_context_s @@ -43,12 +49,29 @@ struct oberon_context_s int integer; oberon_module_t * mod; - oberon_type_t * types; + + void * gen_context; +}; + +enum { + MODE_VAR, + MODE_INTEGER, + MODE_BOOLEAN }; +typedef struct +{ + int mode; + int integer; + int boolean; + oberon_var_t * var; +} oberon_item_t; + oberon_context_t * oberon_create_context(); +void oberon_destroy_context(oberon_context_t * ctx); void oberon_register_global_type(oberon_context_t * ctx, oberon_type_t * type); oberon_module_t * oberon_compile_module(oberon_context_t * ctx, const char * code); +void oberon_error(oberon_context_t * ctx, const char * fmt, ...); #endif // EMBEDED_OBERON_SCRIPT_H diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..58023d2 --- /dev/null +++ b/run.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +export PATH="/usr/lib/gcc/x86_64-pc-linux-gnu/7.1.1:${PATH}" +export LIBRARY_PATH="/usr/lib/gcc/x86_64-pc-linux-gnu/7.1.1:${LIBRARY_PATH}" + +exec ./a.out diff --git a/test.c b/test.c index 2247eac..7149026 100644 --- a/test.c +++ b/test.c @@ -7,10 +7,13 @@ static oberon_type_t boolean = { "BOOLEAN", OBERON_TYPE_BOOLEAN, sizeof(int) }; static const char source[] = "MODULE Test;" "VAR" + " k : INTEGER;" " i : INTEGER;" " b : BOOLEAN;" "BEGIN" - " i := 10;" + " k := 10;" + " i := k;" + " b := TRUE;" "END Test." ; @@ -24,5 +27,6 @@ main(int argc, char ** argv) oberon_register_global_type(ctx, &integer); oberon_register_global_type(ctx, &boolean); mod = oberon_compile_module(ctx, source); + oberon_destroy_context(ctx); return 0; } diff --git a/test_gcc_jit/make.sh b/test_gcc_jit/make.sh deleted file mode 100755 index 03ddd5b..0000000 --- a/test_gcc_jit/make.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -set -e - -gcc -g -Wall -Werror -std=c11 -lgccjit s1.c -o s1 diff --git a/test_gcc_jit/s1 b/test_gcc_jit/s1 deleted file mode 100755 index 143c368..0000000 Binary files a/test_gcc_jit/s1 and /dev/null differ diff --git a/test_gcc_jit/s1.c b/test_gcc_jit/s1.c deleted file mode 100644 index f83910e..0000000 --- a/test_gcc_jit/s1.c +++ /dev/null @@ -1,22 +0,0 @@ -#include - -gcc_jit_context * ctxt; - -int -main(int argc, char **argv) -{ - ctxt = gcc_jit_context_acquire(); - - cc_jit_type * void_type = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_VOID); - - gcc_jit_function * func = gcc_jit_context_new_function( - ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, void_type, "BEGIN", 0, NULL, 0 - ); - - gcc_jit_block * block = gcc_jit_function_new_block (func, NULL); - - - - gcc_jit_context_release(ctxt); - return 0; -}