summaryrefslogtreecommitdiff
path: root/igen/preprocessor.c
diff options
context:
space:
mode:
Diffstat (limited to 'igen/preprocessor.c')
-rw-r--r--igen/preprocessor.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/igen/preprocessor.c b/igen/preprocessor.c
new file mode 100644
index 0000000..e83bd20
--- /dev/null
+++ b/igen/preprocessor.c
@@ -0,0 +1,192 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "preprocessor.h"
+
+static const keyword *preproc_keywords[] = {
+ &(const keyword *) {"include", DIR_INCLUDE, pp_include},
+ NULL
+};
+
+char *skip_line(const char *str, int dbg) {
+ size_t span = strcspn(str, "\r\n\f");
+ /*span += strspn(&str[span], "\r\n\f");*/
+ return &str[span+strspn(&str[span], "\r\n\f")];
+}
+
+size_t line_span(const char *str, int dbg) {
+ return skip_line(str, dbg)-str;
+}
+
+size_t get_comment_span(source *src, const char *str, int dbg) {
+ if (str[0] == '/') {
+ if (str[1] == '*') {
+ char *tmp = strstr(str, "*/")+strlen("*/");
+ if (tmp == NULL) {
+ throw_error(src, 0, "Unterminated comment (missing \"*/\").");
+ }
+ return tmp-str;
+ } else if (str[1] == '/') {
+ return line_span(str, dbg);
+ }
+ }
+ return 0;
+}
+
+size_t get_whitespace_span(const char *str, int count_lines, int count_columns, int dbg) {
+ size_t span = 0;
+ if (count_columns) {
+ span = strspn(str, " \t\v\b");
+ }
+ if (count_lines) {
+ span += strspn(&str[span], "\r\n\f");
+ }
+ return span;
+}
+
+void count_whitespace(whitespace *wsp, const char *str, size_t span, int count_lines, int count_columns, int dbg) {
+ for (size_t i = 0; i < span && str[i] != '\0'; ++i) {
+ char c = str[i];
+ if (str[i+1] != '\b') {
+ if (count_columns) {
+ wsp->spaces += (c == ' ');
+ wsp->vtabs += (c == '\v');
+ wsp->tabs += (c == '\t');
+ }
+ if (count_lines) {
+ i += (c == '\r' && str[i+1] == '\n');
+ wsp->lines += (c == '\r' || c == '\n' || c == '\f');
+ }
+ } else {
+ c = str[++i+1];
+ if (c != '\0') {
+ i += (count_lines && (c == '\r' && str[i+2] == '\n'));
+ }
+ ++wsp->bspaces;
+ }
+ }
+}
+
+char *skip_whitespace(source *src, whitespace *wspace, int count_lines, int count_columns, int dbg) {
+ char *text = src->text;
+ size_t span = get_whitespace_span(text, count_lines, count_columns, dbg);
+ whitespace wsp = {0};
+
+ count_whitespace(&wsp, str, span, count_lines, count_columns, dbg);
+
+ if (wsp.tabs) {
+ const int tab_stop = src->tab_width;
+ const int extra_tabs = wsp.spaces/tab_stop;
+ src->cur.x += ((wsp.tabs+extra_tabs)*tab_stop);
+ } else {
+ src->cur.x += wsp.spaces;
+ }
+ src->cur.y += wsp.lines;
+ if (wspace != NULL) {
+ *wspace = wsp;
+ }
+ return &text[span];
+}
+
+char *skip_comment(source *src, whitespace *wspace, enum comment_type *type, int dbg) {
+ /*char *text = skip_whitespace(src wspace, 1, 1, dbg);*/
+ char *text = src->text;
+ size_t span = get_comment_span(src, text++, dbg);
+ enum comment_type dummy = COMM_NONE;
+ whitespace wsp = {0};
+
+ type = (type != NULL) ? type : &dummy;
+
+ if (span) {
+ if (*text++ == '*') {
+ *type = COMM_MULTI;
+ /*for (size_t i = 0; text[i] != '\0' && i < span; i = line_span(&text[i], dbg), ++wsp.lines);*/
+ count_whitespace(&wsp, text, span, 1, 0, dbg);
+ count_whitespace(&wsp, &text[span], strspn(&text[span], "\r\n\f"), 0, 1, dbg);
+ } else {
+ *type = COMM_SINGLE;
+ ++wsp.lines
+ text -= 2;
+ }
+
+ if (wspace != NULL) {
+ *wspace = wsp;
+ }
+
+ if (wsp.tabs) {
+ const int tab_stop = src->tab_width;
+ const int extra_tabs = wsp.spaces/tab_stop;
+ src->cur.x += ((wsp.tabs+extra_tabs)*tab_stop);
+ } else {
+ src->cur.x += wsp.spaces;
+ }
+ src->cur.y += wsp.lines;
+ } else {
+ --text;
+ *type = COMM_NONE;
+ }
+ return &text[span];
+}
+
+comment *get_comment(source *src, int dbg) {
+ char *text = src->text;
+ char *after_comment;
+ size_t comment_len = 0;
+ comment *com = calloc(1, sizeof(comment));
+
+ text = skip_whitespace(src, &com->wsp, 1, 1, dbg);
+ com->start_pos = src->cur;
+
+ after_comment = skip_comment(src, NULL, &com->type, dbg);
+ com->end_pos = src->cur;
+
+ switch (com->type) {
+ case COMM_MULTI : comment_len = strstr(text, "*/")-text; break;
+ case COMM_SINGLE: comment_len = strcspn(text, "\r\n\f"); break;
+ }
+
+ com->text = calloc(comment_len+1, sizeof(char));
+ memcpy(com->text, &text[strlen("/*")], comment_len);
+ return com;
+}
+
+source *pp_include(source *src, int dbg) {
+ char *text = skip_whitespace(src, NULL, 0, 1, dbg);
+ if (*text == '\r' || *text == '\n' || *text == '\f') {
+ throw_error(src, 1, "Found line separator \'%s\' before the operand of an include directive.", esc_char_to_string(*text));
+ src->text = text;
+ return NULL;
+ } else if (*text == '\"' || *text == '\'') {
+ char c = *text++;
+ char *tmp = strchr(text, c);
+ if (tmp == NULL) {
+ throw_error(src, 1, "Missing terminating %c character.", c);
+ src->text = text;
+ return NULL;
+ } else {
+ long dummy = 0;
+ source *inc_src = calloc(1, sizeof(source));
+ inc_src->tab_width = src->tab_width;
+ inc_src->filename = calloc((tmp--)-text, sizeof(char));
+ inc_src->text = read_file(inc_src->filename, &dummy);
+ if (inc_src->text == NULL) {
+ throw_error(src, 1, "File \"%s\" couldn't be read.", inc_src->filename);
+ free(inc_src->filename);
+ free(inc_src);
+ src->text = skip_line(text, dbg);
+ return NULL;
+ }
+ }
+ } else {
+ throw_error(src, 1, "Missing quote mark at the start of the operand of an include directive.");
+ src->text = text;
+ return NULL;
+ }
+ if
+ size_t span = strspn(text, " \t\v\r\n");
+ if (text[span]+1 == '/' && text[])
+}
+
+source *preprocess(const char *str, int dbg) {
+}