#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");
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 = 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;
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) {
}