Basic structure of ftepp

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-16 17:46:16 +01:00
parent 07ca2e6407
commit 4bee1bdb6e

217
ftepp.c
View file

@ -24,10 +24,44 @@
#include "lexer.h"
typedef struct {
lex_file *lex;
bool on;
bool was_on;
bool had_else;
} ppcondition;
typedef struct {
lex_file *lex;
int token;
bool newline;
unsigned int errors;
ppcondition *conditions;
} ftepp_t;
#define ftepp_tokval(f) ((f)->lex->tok.value)
#define ftepp_ctx(f) ((f)->lex->tok.ctx)
static void ftepp_errorat(ftepp_t *ftepp, lex_ctx ctx, const char *fmt, ...)
{
va_list ap;
ftepp->errors++;
va_start(ap, fmt);
con_vprintmsg(LVL_ERROR, ctx.file, ctx.line, "error", fmt, ap);
va_end(ap);
}
static void ftepp_error(ftepp_t *ftepp, const char *fmt, ...)
{
va_list ap;
ftepp->errors++;
va_start(ap, fmt);
con_vprintmsg(LVL_ERROR, ftepp->lex->tok.ctx.file, ftepp->lex->tok.ctx.line, "error", fmt, ap);
va_end(ap);
}
ftepp_t* ftepp_init()
{
@ -39,23 +73,192 @@ ftepp_t* ftepp_init()
return ftepp;
}
static inline int ftepp_next(ftepp_t *ftepp)
{
return (ftepp->token = lex_do(ftepp->lex));
}
/* Important: this does not skip newlines! */
static bool ftepp_skipspace(ftepp_t *ftepp)
{
while (ftepp_next(ftepp) == TOKEN_WHITE) {}
return (ftepp->token < TOKEN_EOF);
}
static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond)
{
ftepp_error(ftepp, "TODO: #if");
return false;
}
static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond)
{
ftepp_error(ftepp, "TODO: #ifdef");
return false;
}
static bool ftepp_define(ftepp_t *ftepp)
{
ftepp_error(ftepp, "TODO: #define");
return false;
}
static bool ftepp_else_allowed(ftepp_t *ftepp)
{
if (!vec_size(ftepp->conditions)) {
ftepp_error(ftepp, "#else without #if");
return false;
}
if (vec_last(ftepp->conditions).had_else) {
ftepp_error(ftepp, "multiple #else for a single #if");
return false;
}
return true;
}
static bool ftepp_hash(ftepp_t *ftepp)
{
ppcondition cond;
ppcondition *pc;
lex_ctx ctx = ftepp_ctx(ftepp);
if (!ftepp_skipspace(ftepp))
return false;
switch (ftepp->token) {
case TOKEN_IDENT:
if (!strcmp(ftepp_tokval(ftepp), "define")) {
return ftepp_define(ftepp);
}
else if (!strcmp(ftepp_tokval(ftepp), "ifdef")) {
if (!ftepp_ifdef(ftepp, &cond))
return false;
vec_push(ftepp->conditions, cond);
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "ifndef")) {
if (!ftepp_ifdef(ftepp, &cond))
return false;
cond.on = !cond.on;
vec_push(ftepp->conditions, cond);
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "elifdef")) {
if (!ftepp_else_allowed(ftepp))
return false;
if (!ftepp_ifdef(ftepp, &cond))
return false;
pc = &vec_last(ftepp->conditions);
pc->on = !pc->was_on && cond.on;
pc->was_on = pc->was_on || pc->on;
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "elifndef")) {
if (!ftepp_else_allowed(ftepp))
return false;
if (!ftepp_ifdef(ftepp, &cond))
return false;
cond.on = !cond.on;
pc = &vec_last(ftepp->conditions);
pc->on = !pc->was_on && cond.on;
pc->was_on = pc->was_on || pc->on;
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "elif")) {
if (!ftepp_else_allowed(ftepp))
return false;
if (!ftepp_if(ftepp, &cond))
return false;
pc = &vec_last(ftepp->conditions);
pc->on = !pc->was_on && cond.on;
pc->was_on = pc->was_on || pc->on;
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "if")) {
if (!ftepp_if(ftepp, &cond))
return false;
vec_push(ftepp->conditions, cond);
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "else")) {
if (!ftepp_else_allowed(ftepp))
return false;
pc = &vec_last(ftepp->conditions);
pc->on = !pc->was_on;
pc->had_else = true;
return true;
}
else if (!strcmp(ftepp_tokval(ftepp), "endif")) {
if (!vec_size(ftepp->conditions)) {
ftepp_error(ftepp, "#endif without #if");
return false;
}
vec_pop(ftepp->conditions);
break;
}
else {
ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(ftepp));
return false;
}
break;
case TOKEN_KEYWORD:
if (!strcmp(ftepp_tokval(ftepp), "if")) {
if (!ftepp_if(ftepp, &cond))
return false;
vec_push(ftepp->conditions, cond);
return true;
}
/* fall through */
default:
ftepp_error(ftepp, "unexpected preprocessor token: `%s`", ftepp_tokval(ftepp));
return false;
case TOKEN_EOL:
ftepp_errorat(ftepp, ctx, "empty preprocessor directive");
return false;
case TOKEN_EOF:
ftepp_error(ftepp, "missing newline at end of file", ftepp_tokval(ftepp));
return false;
}
return true;
}
static bool ftepp_preprocess(ftepp_t *ftepp)
{
int token;
bool newline = true;
ftepp->lex->flags.preprocessing = true;
for (token = lex_do(ftepp->lex); token < TOKEN_EOF; token = lex_do(ftepp->lex))
do
{
switch (token) {
case TOKEN_EOL: printf("\n"); break;
ftepp_next(ftepp);
if (ftepp->token >= TOKEN_EOF)
break;
ftepp->newline = newline;
newline = false;
switch (ftepp->token) {
case '#':
if (!ftepp->newline) {
printf("%s", ftepp_tokval(ftepp));
break;
}
if (!ftepp_hash(ftepp))
return false;
break;
case TOKEN_EOL:
newline = true;
printf("\n");
break;
default:
printf("%s", ftepp_tokval(ftepp));
break;
}
}
} while (!ftepp->errors && ftepp->token < TOKEN_EOF);
return (token == TOKEN_EOF);
return (ftepp->token == TOKEN_EOF);
}
bool ftepp_preprocess_file(const char *filename)