DEADSOFTWARE

Начало проекта, где-то первая неделя июля.
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 19:01:38 +0000 (22:01 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 24 Jul 2017 19:01:38 +0000 (22:01 +0300)
.gitignore [new file with mode: 0644]
make.sh [new file with mode: 0755]
oberon.c [new file with mode: 0644]
oberon.h [new file with mode: 0644]
test.c [new file with mode: 0644]
test_gcc_jit/make.sh [new file with mode: 0755]
test_gcc_jit/s1 [new file with mode: 0755]
test_gcc_jit/s1.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f47cb20
--- /dev/null
@@ -0,0 +1 @@
+*.out
diff --git a/make.sh b/make.sh
new file mode 100755 (executable)
index 0000000..fe43cd6
--- /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
new file mode 100644 (file)
index 0000000..e411c6c
--- /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
new file mode 100644 (file)
index 0000000..7fee329
--- /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
new file mode 100644 (file)
index 0000000..2247eac
--- /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
new file mode 100755 (executable)
index 0000000..03ddd5b
--- /dev/null
@@ -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
diff --git a/test_gcc_jit/s1.c b/test_gcc_jit/s1.c
new file mode 100644 (file)
index 0000000..f83910e
--- /dev/null
@@ -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;
+}