char *includename;
} ftepp_t;
+typedef struct {
+ const char *name;
+ char *(*func)(lex_file *);
+} predef_t;
+
+/*
+ * Implement the predef subsystem now. We can do this safely with the
+ * help of lexer contexts.
+ */
+static uint32_t ftepp_predef_countval = 0;
+static uint32_t ftepp_predef_randval = 0;
+
+/* __LINE__ */
+char *ftepp_predef_line(lex_file *context) {
+ char *value;
+ util_asprintf(&value, "%d", (int)context->line);
+ return value;
+}
+/* __FILE__ */
+char *ftepp_predef_file(lex_file *context) {
+ size_t length = strlen(context->name) + 3; /* two quotes and a terminator */
+ char *value = (char*)mem_a(length);
+ memset (value, 0, length);
+ sprintf(value, "\"%s\"", context->name);
+
+ return value;
+}
+/* __COUNTER_LAST__ */
+char *ftepp_predef_counterlast(lex_file *context) {
+ char *value;
+ util_asprintf(&value, "%u", ftepp_predef_countval);
+
+ (void)context;
+ return value;
+}
+/* __COUNTER__ */
+char *ftepp_predef_counter(lex_file *context) {
+ char *value;
+ ftepp_predef_countval ++;
+ util_asprintf(&value, "%u", ftepp_predef_countval);
+ (void)context;
+
+ return value;
+}
+/* __RANDOM__ */
+char *ftepp_predef_random(lex_file *context) {
+ char *value;
+ ftepp_predef_randval = (util_rand() % 0xFF) + 1;
+ util_asprintf(&value, "%u", ftepp_predef_randval);
+
+ (void)context;
+ return value;
+}
+/* __RANDOM_LAST__ */
+char *ftepp_predef_randomlast(lex_file *context) {
+ char *value;
+ util_asprintf(&value, "%u", ftepp_predef_randval);
+
+ (void)context;
+ return value;
+}
+
+static const predef_t ftepp_predefs[] = {
+ { "__LINE__", &ftepp_predef_line },
+ { "__FILE__", &ftepp_predef_file },
+ { "__COUNTER__", &ftepp_predef_counter },
+ { "__COUNTER_LAST__", &ftepp_predef_counterlast },
+ { "__RANDOM__", &ftepp_predef_random },
+ { "__RANDOM_LAST__", &ftepp_predef_randomlast },
+};
+
#define ftepp_tokval(f) ((f)->lex->tok.value)
#define ftepp_ctx(f) ((f)->lex->tok.ctx)
static bool GMQCC_WARN ftepp_warn(ftepp_t *ftepp, int warntype, const char *fmt, ...)
{
+ bool r;
va_list ap;
- int lvl = LVL_WARNING;
-
- if (!OPTS_WARN(warntype))
- return false;
-
- if (opts.werror) {
- lvl = LVL_ERROR;
- ftepp->errors++;
- }
va_start(ap, fmt);
- con_cvprintmsg((void*)&ftepp->lex->tok.ctx, lvl, "error", fmt, ap);
+ r = vcompile_warning(ftepp->lex->tok.ctx, warntype, fmt, ap);
va_end(ap);
- return opts.werror;
+ return r;
}
static pptoken *pptoken_make(ftepp_t *ftepp)
static void ftepp_delete(ftepp_t *self)
{
size_t i;
+ ftepp_flush(self);
if (self->itemname)
mem_d(self->itemname);
if (self->includename)
}
}
-static inline int ftepp_next(ftepp_t *ftepp)
+static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
{
return (ftepp->token = lex_do(ftepp->lex));
}
memcpy(vec_add(filename, len+1), file, len);
vec_last(filename) = 0;
- fp = util_fopen(filename, "rb");
+ fp = file_open(filename, "rb");
if (fp) {
- fclose(fp);
+ file_close(fp);
return filename;
}
vec_free(filename);
return filename;
}
+static bool ftepp_directive_warning(ftepp_t *ftepp) {
+ char *message = NULL;
+
+ if (!ftepp_skipspace(ftepp))
+ return false;
+
+ /* handle the odd non string constant case so it works like C */
+ if (ftepp->token != TOKEN_STRINGCONST) {
+ bool store = false;
+ vec_upload(message, "#warning", 8);
+ ftepp_next(ftepp);
+ while (ftepp->token != TOKEN_EOL) {
+ vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp)));
+ ftepp_next(ftepp);
+ }
+ vec_push(message, '\0');
+ store = ftepp_warn(ftepp, WARN_CPP, message);
+ vec_free(message);
+ return store;
+ }
+
+ unescape (ftepp_tokval(ftepp), ftepp_tokval(ftepp));
+ return ftepp_warn(ftepp, WARN_CPP, "#warning %s", ftepp_tokval(ftepp));
+}
+
+static void ftepp_directive_error(ftepp_t *ftepp) {
+ char *message = NULL;
+
+ if (!ftepp_skipspace(ftepp))
+ return;
+
+ /* handle the odd non string constant case so it works like C */
+ if (ftepp->token != TOKEN_STRINGCONST) {
+ vec_upload(message, "#error", 6);
+ ftepp_next(ftepp);
+ while (ftepp->token != TOKEN_EOL) {
+ vec_upload(message, ftepp_tokval(ftepp), strlen(ftepp_tokval(ftepp)));
+ ftepp_next(ftepp);
+ }
+ vec_push(message, '\0');
+ ftepp_error(ftepp, message);
+ vec_free(message);
+ return;
+ }
+
+ unescape (ftepp_tokval(ftepp), ftepp_tokval(ftepp));
+ ftepp_error(ftepp, "#error %s", ftepp_tokval(ftepp));
+}
+
/**
* Include a file.
* FIXME: do we need/want a -I option?
ftepp_out(ftepp, "#", false);
break;
}
+ else if (!strcmp(ftepp_tokval(ftepp), "warning")) {
+ ftepp_directive_warning(ftepp);
+ break;
+ }
+ else if (!strcmp(ftepp_tokval(ftepp), "error")) {
+ ftepp_directive_error(ftepp);
+ break;
+ }
else {
if (ftepp->output_on) {
ftepp_error(ftepp, "unrecognized preprocessor directive: `%s`", ftepp_tokval(ftepp));
ppmacro *macro;
bool newline = true;
+ /* predef stuff */
+ char *expand = NULL;
+ size_t i;
+
ftepp->lex->flags.preprocessing = true;
ftepp->lex->flags.mergelines = false;
ftepp->lex->flags.noops = true;
case TOKEN_KEYWORD:
case TOKEN_IDENT:
case TOKEN_TYPENAME:
+ /* is it a predef? */
+ if (OPTS_FLAG(FTEPP_PREDEFS)) {
+ for (i = 0; i < sizeof(ftepp_predefs) / sizeof (*ftepp_predefs); i++) {
+ if (!strcmp(ftepp_predefs[i].name, ftepp_tokval(ftepp))) {
+ expand = ftepp_predefs[i].func(ftepp->lex);
+ ftepp_out(ftepp, expand, false);
+ ftepp_next(ftepp); /* skip */
+
+ mem_d(expand); /* free memory */
+ break;
+ }
+ }
+ }
+
if (ftepp->output_on)
macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
else
macro = NULL;
+
if (!macro) {
ftepp_out(ftepp, ftepp_tokval(ftepp), false);
ftepp_next(ftepp);
return ftepp_preprocess_done();
}
+
+void ftepp_add_macro(const char *name, const char *value) {
+ char *create = NULL;
+
+ /* use saner path for empty macros */
+ if (!value) {
+ ftepp_add_define("__builtin__", name);
+ return;
+ }
+
+ vec_upload(create, "#define ", 8);
+ vec_upload(create, name, strlen(name));
+ vec_push (create, ' ');
+ vec_upload(create, value, strlen(value));
+ vec_push (create, 0);
+
+ ftepp_preprocess_string("__builtin__", create);
+ vec_free (create);
+}
+
bool ftepp_init()
{
char minor[32];
char major[32];
- char *verminor = NULL;
- char *vermajor = NULL;
ftepp = ftepp_new();
if (!ftepp)
if (opts.standard == COMPILER_FTEQCC) {
ftepp_add_define(NULL, "__STD_FTEQCC__");
/* 1.00 */
- major[0] = '1';
- minor[0] = '0';
+ major[0] = '"';
+ major[1] = '1';
+ major[2] = '"';
+
+ minor[0] = '"';
+ minor[1] = '0';
+ minor[2] = '"';
} else if (opts.standard == COMPILER_GMQCC) {
ftepp_add_define(NULL, "__STD_GMQCC__");
- sprintf(major, "%d", GMQCC_VERSION_MAJOR);
- sprintf(minor, "%d", GMQCC_VERSION_MINOR);
+ sprintf(major, "\"%d\"", GMQCC_VERSION_MAJOR);
+ sprintf(minor, "\"%d\"", GMQCC_VERSION_MINOR);
} else if (opts.standard == COMPILER_QCC) {
ftepp_add_define(NULL, "__STD_QCC__");
/* 1.0 */
- major[0] = '1';
- minor[0] = '0';
- }
+ major[0] = '"';
+ major[1] = '1';
+ major[2] = '"';
- vec_upload(verminor, "#define __STD_VERSION_MINOR__ \"", 31);
- vec_upload(vermajor, "#define __STD_VERSION_MAJOR__ \"", 31);
- vec_upload(verminor, minor, strlen(minor));
- vec_upload(vermajor, major, strlen(major));
- vec_push (verminor, '"');
- vec_push (vermajor, '"');
- vec_push (verminor, 0);
- vec_push (vermajor, 0);
+ minor[0] = '"';
+ minor[1] = '0';
+ minor[2] = '"';
+ }
- ftepp_preprocess_string("__builtin__", verminor);
- ftepp_preprocess_string("__builtin__", vermajor);
+ ftepp_add_macro("__STD_VERSION_MINOR__", minor);
+ ftepp_add_macro("__STD_VERSION_MAJOR__", major);
- vec_free(verminor);
- vec_free(vermajor);
return true;
}