aboutsummaryrefslogtreecommitdiff
path: root/src/compiler.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-03-23 16:14:51 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2023-03-23 16:14:51 +0200
commit5b038666c3e911ffeb78a4d656044e5bd076705b (patch)
tree9b09b4f27c39ef6a0139a5eb9bfa5e98a250086c /src/compiler.c
parent70615379062cdd2e016f5095dfafd23a6dca148c (diff)
downloadek-5b038666c3e911ffeb78a4d656044e5bd076705b.tar.gz
ek-5b038666c3e911ffeb78a4d656044e5bd076705b.zip
integrate parser work
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c328
1 files changed, 76 insertions, 252 deletions
diff --git a/src/compiler.c b/src/compiler.c
index b222c2e..782001f 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -3,284 +3,116 @@
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
-#include <regex.h>
+#include <limits.h>
#include <errno.h>
-#include <ct/compiler.h>
-#include <ct/string.h>
-#include <ct/debug.h>
-#include <ct/path.h>
-#include <ct/res.h>
+#include <cu/actualize.h>
+#include <cu/compiler.h>
+#include <cu/string.h>
+#include <cu/parser.h>
+#include <cu/debug.h>
+#include <cu/scope.h>
+#include <cu/path.h>
+#include <cu/res.h>
-const char *import_regex =
-"^[[:space:]]*(pub[[:space:]]+)?"
-"import[[:space:]]+"
-"([[:alnum:]/.]+)"
-"[[:space:]]*;"
-"[[:space:]]*$";
-
-const char *define_regex =
-"^[[:space:]]*(pub[[:space:]]+)?"
-"define[[:space:]]+"
-"([[:alnum:]]+)[[:space:]]*"
-"\\((.*)\\)"
-"[[:space:]]*"
-"\\{(.*)\\}"
-"[[:space:]]*$";
-
-regex_t import_re;
-regex_t define_re;
-
-/* this could maybe be moved to a utility file or something */
-static char *get_regerror(int errcode, regex_t *compiled)
-{
- size_t len = regerror(errcode, compiled, NULL, 0);
- char *buf = malloc(len);
- regerror(errcode, compiled, buf, len);
- return buf;
-}
-
-static int read_element(FILE *f, struct string *element)
+static char *read_file(const char *file, FILE *f)
{
- if (feof(f))
- return -1;
-
- str_clear(element);
-
- char c = fgetc(f);
- str_append(element, c);
- if (!isalnum(c))
- return 0;
-
- while ((c = fgetc(f))) {
- if (isalnum(c)) {
- str_append(element, c);
- } else {
- ungetc(c, f);
- break;
- }
- }
-
- return 0;
-}
-
-static struct string *read_block(FILE *f, size_t *lines)
-{
- size_t depth = 0;
- bool maybe_statement = true;
- struct string *block = new_string(NULL);
- if (!block)
- return NULL;
-
- struct string *elem = new_string(NULL);
- if (!elem) {
- destroy_string(block);
+ fseek(f, 0, SEEK_END);
+ /* TODO: check how well standardized this actually is */
+ long s = ftell(f);
+ if (s == LONG_MAX) {
+ error("%s might be a directory", file);
return NULL;
}
- size_t newlines = 0;
- while (1) {
- if (read_element(f, elem)) {
- destroy_string(elem);
- destroy_string(block);
- return NULL;
- }
-
- if (maybe_statement && str_compare(elem, ";")) {
- str_add(block, elem);
- break;
- }
-
- if (str_compare(elem, "{")) {
- maybe_statement = false;
- depth += 1;
- }
-
- if (str_compare(elem, "}"))
- depth -= 1;
-
- str_add(block, elem);
-
- if (str_compare(elem, "\n"))
- newlines++;
-
- if (!maybe_statement && depth == 0)
- break;
- }
-
- if (lines)
- *lines += newlines;
-
- destroy_string(elem);
- return block;
-}
-
-static bool detect_pub(struct string *block, regmatch_t rm)
-{
- const char *start = block->buf + rm.rm_so;
- const size_t len = rm.rm_eo - rm.rm_so;
- const size_t min = len < 3 ? len : 3;
- return strncmp(start, "pub", min);
-}
+ fseek(f, 0, SEEK_SET);
-static char *extract_match(struct string *block, regmatch_t rm)
-{
- const char *start = block->buf + rm.rm_so;
- const size_t len = rm.rm_eo - rm.rm_so;
- char *match = strndup(start, len);
- if (!match)
- error("couldn't extract match: %s\n", strerror(errno));
+ char *buf = malloc(s + 1);
+ if (!buf)
+ return NULL;
- return match;
+ fread(buf, s + 1, 1, f);
+ /* remember terminating null */
+ buf[s] = 0;
+ return buf;
}
-static bool detect_import(struct string *block, bool *pub, char **file)
+static int process(struct scope **parent, int public, const char *file)
{
- int ret = 0;
- const size_t captures = 3;
- regmatch_t rm[captures];
- ret = regexec(&import_re, block->buf, captures, rm, 0);
-
- switch (ret) {
- case REG_ESPACE: error("import regex ran out of memory: %s\n",
- strerror(errno));
- /* fallthrough */
- case REG_NOMATCH: return false;
+ FILE *f = fopen(file, "rb");
+ if (!f) {
+ error("failed opening %s: %s\n", file, strerror(errno));
+ return -1;
}
- *pub = detect_pub(block, rm[1]);
- *file = extract_match(block, rm[2]);
- return true;
-}
-
-static bool detect_define(struct string *block, bool *pub,
- char **name, char **args, char **content)
-{
- int ret = 0;
- const size_t captures = 5;
- regmatch_t rm[captures];
- ret = regexec(&define_re, block->buf, captures, rm, 0);
-
- switch (ret) {
- case REG_ESPACE: error("define regex ran out of memory: %s\n",
- strerror(errno));
- /* fallthrough */
- case REG_NOMATCH: return false;
- }
+ const char *buf = read_file(file, f);
+ fclose(f);
- *pub = detect_pub(block, rm[1]);
- *name = extract_match(block, rm[2]);
- *args = extract_match(block, rm[3]);
- *content = extract_match(block, rm[4]);
- return true;
-}
+ if (!buf)
+ return -1;
-static void process_file(const char *file);
+ struct parser *p = create_parser();
+ if (!p)
+ return -1;
+ parse(p, file, buf);
-static int process(const char *file)
-{
- FILE *f = fopen(file, "r");
- if (!f) {
- error("failed opening %s: %s\n", file, strerror(errno));
+ struct scope *scope = create_scope();
+ if (!scope)
return -1;
- }
- size_t lines = 1, prev_lines = 1;
- struct string *block;
- while ((block = read_block(f, &lines))) {
- debug("block: (%zu - %zu, %zu)\n%s\n", prev_lines, lines,
- lines - prev_lines, block->buf);
- prev_lines = lines + 1;
+ if (public)
+ scope_set_flags(scope, SCOPE_PUBLIC);
- bool pub = false;
- char *file = NULL;
- if (detect_import(block, &pub, &file)) {
- debug("detected %s import block for file (%s)\n",
- pub ? "public" : "private",
- file);
- process_file(file);
- free(file);
- goto next;
- }
+ scope->fctx.fbuf = buf;
+ scope->fctx.fname = strdup(file);
+ scope->actuals = create_actuals();
+ scope_set_flags(scope, SCOPE_FILE);
- char *name = NULL, *args = NULL, *content = NULL;
- if (detect_define(block, &pub, &name, &args, &content)) {
- debug("detected %s define block %s (%s) {%s}\n",
- pub ? "public" : "private",
- name, args, content);
- free(name);
- free(args);
- free(content);
- goto next;
- }
+ if (*parent)
+ scope_add_scope(*parent, scope);
+ else
+ *parent = scope;
- /* with each block,
- * A) Detect if it is an import block and what kind,
- * in which case process the file that it refers to.
- *
- * B) Detect if it is a macro block and what kind, in which case
- * parse it and add it to the macro subsystem.
- *
- * C) Run the preprocessor on the block.
- *
- * D) Actually lex/parse/generate AST for the block.
- *
- * E) Run semantic checks on the block.
- *
- * With all of these parts checked, I'm pretty sure we can
- * directly generate code for each block. Possibly something
- * like one C file per CT file, will have to look into what
- * might be easiest. Also, some internal duplicate checking, so
- * that we don't accidentally generate the same generic function
- * in two different files or something like that.
- *
- * Same duplicate checking could be useful for the interpreted
- * approach.
- *
- * Step D) could potentially be done on request, maybe fitting
- * for the interpreted approach, I guess it depends on how fast the
- * lexing/parsing/AST generation for each block is. Semantic
- * checking is what I suspect will be the slowest part.
- *
- * Oh yeah, need some way to push result of some lower file
- * processing upwards. And probably detecting a main block as
- * well?
- */
-next:
- destroy_string(block);
- }
+ if (analyze_root(scope, p->tree))
+ return -1;
+
+ destroy_parser(p);
- fclose(f);
return 0;
}
-void process_file(const char *file)
+int process_file(struct scope **scope, int public, const char *file)
{
+ int res = -1;
+ /* TODO: report failure allocating stuff maybe? */
struct res *r = res_create();
+ if (!r)
+ return -1;
- const char *base = ct_basename(file);
+ const char *base = cu_basename(file);
res_add(r, (void *)base);
if (!base)
goto out;
- const char *dir = ct_dirname(file);
+ const char *dir = cu_dirname(file);
res_add(r, (void *)dir);
if (!dir)
goto out;
- const char *cwd = ct_cwdname();
+ /* TODO: iterate through include paths */
+ const char *cwd = cu_cwdname();
res_add(r, (void *)cwd);
if (!cwd)
goto out;
- debug("(cwd:%s)(dir:%s)(base:%s)\n", cwd, dir, base);
+ debug("(cwd:%s)(dir:%s)(base:%s)", cwd, dir, base);
if (*dir != 0 && chdir(dir)) {
- error("couldn't change to directory %s: %s\n", dir, strerror(errno));
+ error("couldn't change to directory %s: %s", dir, strerror(errno));
goto out;
}
- if (process(base))
+ if (process(scope, public, base))
goto out;
if (chdir(cwd)) {
@@ -288,30 +120,22 @@ void process_file(const char *file)
goto out;
}
+ res = 0;
out:
res_destroy(r);
+ return res;
}
-void compile(const char *file) {
- int err = 0;
- if ((err = regcomp(&import_re, import_regex, REG_EXTENDED)) != 0) {
- char *err_str = get_regerror(err, &import_re);
- error("failed compiling import regex: %s\n", err_str);
- free(err_str);
- goto out;
+int compile(const char *file) {
+ int ret = -1;
+ struct scope *root = NULL;
+ if (process_file(&root, 0, file)) {
+ error("compilation of %s stopped due to errors", file);
+ return ret;
}
- if ((err = regcomp(&define_re, define_regex, REG_EXTENDED)) != 0) {
- char *err_str = get_regerror(err, &define_re);
- error("failed compiling define regex: %s\n", err_str);
- free(err_str);
- goto define_out;
- }
-
- process_file(file);
-
- regfree(&define_re);
-define_out:
- regfree(&import_re);
-out:
+ ret = actualize_main(root);
+ /* TODO: backend */
+ destroy_scope(root);
+ return ret;
}