struct lex_file *lex_open(FILE *fp) {
struct lex_file *lex = mem_a(sizeof(struct lex_file));
- if (lex) {
- lex->file = fp;
- fseek(lex->file, 0, SEEK_END);
- lex->length = ftell(lex->file);
- lex->size = lex->length; /* copy, this is never changed */
- fseek(lex->file, 0, SEEK_SET);
- lex->last = 0;
+ if (!lex || !fp)
+ return NULL;
- memset(lex->peek, 0, sizeof(lex->peek));
- }
+ lex->file = fp;
+ fseek(lex->file, 0, SEEK_END);
+ lex->length = ftell(lex->file);
+ lex->size = lex->length; /* copy, this is never changed */
+ fseek(lex->file, 0, SEEK_SET);
+ lex->last = 0;
+ lex->line = 0;
+
+ memset(lex->peek, 0, sizeof(lex->peek));
return lex;
}
-int lex_close(struct lex_file *file) {
- int ret = -1;
- if (file) {
- ret = fclose(file->file);
- mem_d(file);
- }
- return ret;
+void lex_close(struct lex_file *file) {
+ if (!file) return;
+
+ fclose(file->file); /* may already be closed */
+ mem_d (file);
}
static void lex_addch(int ch, struct lex_file *file) {
static int lex_getch(struct lex_file *file) {
int ch = lex_inget(file);
- if (ch == '?')
- return lex_trigraph(file);
- if (ch == '<' || ch == ':' || ch == '%')
- return lex_digraph (file, ch);
+
+ static int str = 0;
+ switch (ch) {
+ case '?' :
+ return lex_trigraph(file);
+ case '<' :
+ case ':' :
+ case '%' :
+ case '"' : str = !str; if (str) { file->line ++; }
+ return lex_digraph(file, ch);
+
+ case '\n':
+ if (!str)
+ file->line++;
+ }
return ch;
}
int ch;
if (!isspace(ch = lex_getch(file)))
return ch;
-
+
/* skip over all spaces */
while (isspace(ch) && ch != '\n')
ch = lex_getch(file);
lex_addch(ch, file);
while ((ch = lex_getch(file)) != '*') {
if (ch == EOF)
- return error(ERROR_LEX, "malformatted comment at line %d", file->line);
+ return error(ERROR_LEX, "malformatted comment at line", "");
else
lex_addch(ch, file);
}
case '\'': return lex_skipchr(file);
case '"': return lex_skipstr(file);
case '/': return lex_skipcmt(file);
- default: return ch;
+ default:
+ return ch;
}
}
/* valid identifier */
if (ch > 0 && (ch == '_' || isalpha(ch))) {
lex_clear(file);
- while (ch > 0 && (isalpha(ch) || ch == '_')) {
+
+ /*
+ * Yes this is dirty, but there is no other _sane_ easy
+ * way to do it, this is what I call defensive programming
+ * if something breaks, add more defense :-)
+ */
+ while (ch > 0 && ch != ' ' && ch != '(' &&
+ ch != '\n' && ch != ';' && ch != ')') {
lex_addch(ch, file);
ch = lex_getsource(file);
}
#define TEST_TYPE(X) \
do { \
if (!strncmp(X, "float", sizeof("float"))) \
- return TOKEN_FLOAT; \
+ return TOKEN_FLOAT; \
if (!strncmp(X, "vector", sizeof("vector"))) \
- return TOKEN_VECTOR; \
+ return TOKEN_VECTOR; \
if (!strncmp(X, "string", sizeof("string"))) \
return TOKEN_STRING; \
if (!strncmp(X, "entity", sizeof("entity"))) \
return TOKEN_ENTITY; \
if (!strncmp(X, "void" , sizeof("void"))) \
- return TOKEN_VOID; \
+ return TOKEN_VOID; \
} while(0)
TEST_TYPE(file->lastok);
if (typedef_find(file->lastok))
TEST_TYPE(typedef_find(file->lastok)->name);
+ #undef TEST_TYPE
return LEX_IDENT;
}
return ch;
memset(file->peek, 0, sizeof(file->peek ));
memset(file->lastok, 0, sizeof(file->lastok));
}
+
+/*
+ * Include a file into the lexer / parsing process: This really
+ * should check if names are the same to prevent endless include
+ * recrusion.
+ */
+struct lex_file *lex_include(struct lex_file *lex, char *file) {
+ char *find = (char*)file;
+ /*
+ * strip for "" (quotes) .. they might be part of the current
+ * thing. Or possibly not.
+ */
+ if (*find == '"') {
+ find++;
+ file++;
+ while (*find != '"' && *find != '\0')
+ find++;
+
+ /* strip end "" (quotes) .. if they're actually there */
+ if (*find != '\0')
+ *find = '\0';
+ }
+
+ /*
+ * Dissallow recrusive include: this could easily cause some breakage
+ * and instant OOM.
+ */
+ if (strncmp(lex->name, file, strlen(lex->name)) == 0) {
+ error(ERROR_LEX, "%s:%d Source file cannot include itself\n", lex->name, lex->line-1);
+ exit (-1);
+ }
+
+ FILE *fp = fopen(file, "r");
+ if (!fp) {
+ error(ERROR_LEX, "%s:%d Include file `%s` doesn't exist\n", lex->name, lex->line, file);
+ exit (-1);
+ }
+
+ /* must free strdup */
+ file --;
+ mem_d (file);
+
+ return lex_open(fp);
+}