author | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Mon, 24 Jul 2017 19:01:38 +0000 (22:01 +0300) | ||
committer | DeaDDooMER <deaddoomer@deadsoftware.ru> | |
Mon, 24 Jul 2017 19:01:38 +0000 (22:01 +0300) |
.gitignore | [new file with mode: 0644] | patch | blob |
make.sh | [new file with mode: 0755] | patch | blob |
oberon.c | [new file with mode: 0644] | patch | blob |
oberon.h | [new file with mode: 0644] | patch | blob |
test.c | [new file with mode: 0644] | patch | blob |
test_gcc_jit/make.sh | [new file with mode: 0755] | patch | blob |
test_gcc_jit/s1 | [new file with mode: 0755] | patch | blob |
test_gcc_jit/s1.c | [new file with mode: 0644] | patch | blob |
diff --git a/make.sh b/make.sh
--- /dev/null
+++ b/make.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+cc -g -Wall -Werror -std=c11 *.c
diff --git a/oberon.c b/oberon.c
--- /dev/null
+++ b/oberon.c
@@ -0,0 +1,489 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#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;
+}
diff --git a/oberon.h b/oberon.h
--- /dev/null
+++ b/oberon.h
@@ -0,0 +1,54 @@
+#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;
+
+struct oberon_type_s
+{
+ char * name;
+ int class;
+ int size;
+ oberon_type_t * next;
+};
+
+struct oberon_var_s
+{
+ char * name;
+ oberon_type_t * type;
+ oberon_var_t * next;
+};
+
+struct oberon_module_s
+{
+ char * name;
+ oberon_var_t * vars;
+};
+
+struct oberon_context_s
+{
+ const char * code;
+ int code_index;
+
+ char c;
+ int token;
+ char * string;
+ int integer;
+
+ oberon_module_t * mod;
+
+ oberon_type_t * types;
+};
+
+oberon_context_t * oberon_create_context();
+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);
+
+#endif // EMBEDED_OBERON_SCRIPT_H
diff --git a/test.c b/test.c
--- /dev/null
+++ b/test.c
@@ -0,0 +1,28 @@
+#include "oberon.h"
+#include <assert.h>
+
+static oberon_type_t integer = { "INTEGER", OBERON_TYPE_INTEGER, sizeof(int) };
+static oberon_type_t boolean = { "BOOLEAN", OBERON_TYPE_BOOLEAN, sizeof(int) };
+
+static const char source[] =
+ "MODULE Test;"
+ "VAR"
+ " i : INTEGER;"
+ " b : BOOLEAN;"
+ "BEGIN"
+ " i := 10;"
+ "END Test."
+;
+
+static oberon_context_t * ctx;
+static oberon_module_t * mod;
+
+int
+main(int argc, char ** argv)
+{
+ ctx = oberon_create_context();
+ oberon_register_global_type(ctx, &integer);
+ oberon_register_global_type(ctx, &boolean);
+ mod = oberon_compile_module(ctx, source);
+ return 0;
+}
diff --git a/test_gcc_jit/make.sh b/test_gcc_jit/make.sh
--- /dev/null
+++ b/test_gcc_jit/make.sh
@@ -0,0 +1,5 @@
+#!/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
new file mode 100755 (executable)
index 0000000..143c368
Binary files /dev/null and b/test_gcc_jit/s1 differ
index 0000000..143c368
Binary files /dev/null and b/test_gcc_jit/s1 differ
diff --git a/test_gcc_jit/s1.c b/test_gcc_jit/s1.c
--- /dev/null
+++ b/test_gcc_jit/s1.c
@@ -0,0 +1,22 @@
+#include <libgccjit.h>
+
+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;
+}