#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lexer.h"
#include "misc.h"
#include "preprocessor.h"
stmt *lex_stmt(source *src, int dbg);
char *skip_seperators(source *src, whitespace *wspace, int preserve_src, int dbg) {
char *text = NULL;
char *tmp = src->text;
src->text = max(src->text, text);
src->text = skip_whitespace(src, wspace, 1, 1, dbg);
src->text = skip_comment(src, wspace, NULL, dbg);
text = src->text;
if (preserve_src) {
src->text = tmp;
}
return text;
}
cond_stmt *lex_cond_stmt(source *src, int dbg) {
const keyword *cond_keywords[] = {
&(const keyword) {"do", COND_DO, NULL},
&(const keyword) {"for", COND_FOR, NULL},
&(const keyword) {"if", COND_IF, NULL},
&(const keyword) {"while", COND_WHILE, NULL},
};
char *text = src->text;
char *key = NULL;
size_t key_len = 0;
cond_type type = COND_NONE;
whitespace wsp = {0};
text = skip_seperators(src, &wsp, 1, dbg);
key_len = strcspn(text, " \t\v\b");
key = calloc(key_len+1, sizeof(char));
memcpy(key, text, key_len);
type = find_keyword(key, (keyword **)cond_keywords, NULL, NULL, dbg);
free(key);
text += key_len+1;
if (type >= COND_NONE) {
cond_stmt *cond = calloc(1, sizeof(cond_stmt));
cond->type = type;
src->text = text;
src->cur.column += key_len+1;
if (type != COND_DO) {
cond->expr = lex_expr(src, dbg);
}
cond->stmt = lex_stmt(src, dbg);
if (type == COND_DO) {
text = skip_seperators(src, &wsp, 1, dbg);
key_len = strcspn(text, " \t\v\b");
key = calloc(key_len+1, sizeof(char));
memcpy(key, text, key_len);
if (!strcmp(key, "while")) {
text += key_len+1;
src->text = text;
src->cur.column += key_len+1;
cond->expr = lex_expr(src, dbg);
text = skip_seperators(src, &wsp, 1, dbg);
if (*text++ != ';') {
--text;
throw_error(src, 1, "Missing \';\' after do while statement.");
} else {
src->text = text;
++src->cur.column;
}
} else {
throw_error(src, 1, "Missing \'while\' after do while statement.");
}
free(key);
}
return cond;
}
}
stmt *lex_comp_stmt(source *src, int dbg) {
char *text = NULL;
whitespace wsp = {0};
text = skip_seperators(src, &wsp, 0, dbg);
if (*text++ == '{') {
stmt *s;
src->text = text;
++src->cur.column;
for (s = lex_stmt(src, dbg); *src->text != '}' && *src->text != '\0'; s = s->next) {
s->wsp = wsp;
s->next = lex_stmt(src, dbg);
text = skip_seperators(src, &wsp, 0, dbg);
}
text = src->text;
if (*text++ == '}') {
++src->cur.column;
} else {
--text;
throw_error(src, 1, "Missing terminating \'}\' in compound statement.");
}
src->text = text;
return s;
}
return NULL;
}
stmt *lex_stmt(source *src, int dbg) {
char *text = src->text;
const alt_stmt alts[] = {
{STMT_FUNC, offsetof(stmt, func), (lex_func *)lex_func},
{STMT_EXPR, offsetof(stmt, expr), (lex_func *)lex_exprs},
{STMT_COND, offsetof(stmt, cond_stmt), (lex_func *)lex_cond_stmt},
{STMT_COMP, offsetof(stmt, down), (lex_func *)lex_comp_stmt},
};
for (int i = 0; i < NUM_STMTS; ++i) {
src->text = text;
void *data = alts[i].lex(src, dbg);
if (data != NULL) {
stmt *s = calloc(1, sizeof(stmt));
char *stmt = (char *)s;
*(void **)(stmt+alts[i].offset) = data;
return s;
}
}
src->text = text;
return NULL;
}
void lex_library(source *src, int dbg) {
src->root = lex_stmt(src, dbg);
src->last = (src->last != NULL) ? src->last : src->root;
for (stmt *s = src->root; s != NULL; s = lex_stmt(src, dbg)) {
src->last->next = s;
src->last = s;
}
};
int lex(source *src, int dbg) {
char *text = src->text;
lex_library(src, dbg);
src->text = text;
return (src->root != NULL && src->last != NULL);
}