X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=lex.c;h=5673701157a7aaf1b47fd043d821054dcaa0e488;hp=9296158fd196cd5390e47fb60d7e1d096a936e7f;hb=f76c1d2078400c8cef4f493b35099d80dc7c3c8f;hpb=a440c1410bad2a06b6a9385094a3dae0142f9395 diff --git a/lex.c b/lex.c index 9296158..5673701 100644 --- a/lex.c +++ b/lex.c @@ -20,11 +20,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include -#include -#include -#include #include "gmqcc.h" /* @@ -34,39 +29,31 @@ static const char *const lex_keywords[] = { "do", "else", "if", "while", "break", "continue", "return", "goto", - "for", "typedef", - - /* types */ - "int", - "void", - "string", - "float", - "vector", - "entity", + "for", "typedef" }; 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) { @@ -147,10 +134,21 @@ static int lex_digraph(struct lex_file *file, int first) { 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; } @@ -159,16 +157,13 @@ static int lex_get(struct lex_file *file) { int ch; if (!isspace(ch = lex_getch(file))) return ch; - + /* skip over all spaces */ while (isspace(ch) && ch != '\n') ch = lex_getch(file); - if (ch == '\n') { - file->line ++; + if (ch == '\n') return ch; - } - lex_unget(ch, file); return ' '; } @@ -249,7 +244,7 @@ static int lex_skipcmt(struct lex_file *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(file, ERROR_LEX, "malformatted comment"); else lex_addch(ch, file); } @@ -270,7 +265,8 @@ static int lex_getsource(struct lex_file *file) { case '\'': return lex_skipchr(file); case '"': return lex_skipstr(file); case '/': return lex_skipcmt(file); - default: return ch; + default: + return ch; } } @@ -281,7 +277,14 @@ int lex_token(struct lex_file *file) { /* 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); } @@ -293,12 +296,28 @@ int lex_token(struct lex_file *file) { if (!strncmp(file->lastok, lex_keywords[it], sizeof(lex_keywords[it]))) return it; + /* try a type? */ + #define TEST_TYPE(X) \ + do { \ + if (!strncmp(X, "float", sizeof("float"))) \ + return TOKEN_FLOAT; \ + if (!strncmp(X, "vector", sizeof("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; \ + } while(0) + + TEST_TYPE(file->lastok); + /* try the hashtable for typedefs? */ if (typedef_find(file->lastok)) - for (it = 0; it < sizeof(lex_keywords)/sizeof(*lex_keywords); it++) - if (!strncmp(typedef_find(file->lastok)->name, lex_keywords[it], sizeof(lex_keywords[it]))) - return it; - + TEST_TYPE(typedef_find(file->lastok)->name); + + #undef TEST_TYPE return LEX_IDENT; } return ch; @@ -314,53 +333,23 @@ void lex_reset(struct lex_file *file) { memset(file->lastok, 0, sizeof(file->lastok)); } -int lex_debug(struct lex_file *file) { - int list_do = 0; - int list_else = 0; - int list_if = 0; - int list_while = 0; - int list_break = 0; - int list_continue = 0; - int list_return = 0; - int list_goto = 0; - int list_for = 0; - int token = 0; - printf("===========================\nTOKENS: \n===========================\n"); - while ((token = lex_token(file)) != ERROR_LEX && file->length >= 0) { - if (token != -1) { - switch (token) { - case 0: list_do ++; break; - case 1: list_else ++; break; - case 2: list_if ++; break; - case 3: list_while ++; break; - case 4: list_break ++; break; - case 5: list_continue++; break; - case 6: list_return ++; break; - case 7: list_goto ++; break; - case 8: list_for ++; break; - } - } - if (token >= 33 && token <= 126) - putchar(token); +/* + * 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) { + util_strrq(file); + if (strncmp(lex->name, file, strlen(lex->name)) == 0) { + error(lex, ERROR_LEX, "Source file cannot include itself\n"); + exit (-1); } - printf("\n===========================\nBRANCHES \n===========================\n"); - printf("\t if % 8d\n", list_if); - printf("\t else % 8d\n", list_else); - printf("===========================\nLOOPS \n===========================\n"); - printf("\t for % 8d\n", list_for); - printf("\t while % 8d\n", list_while); - printf("\t do % 8d\n", list_do); - printf("===========================\nSTATEMENTS \n===========================\n"); - printf("\t break % 8d\n", list_break); - printf("\t continue % 8d\n", list_continue); - printf("\t return % 8d\n", list_return); - printf("\t goto % 8d\n", list_goto); - printf("===========================\nIDENTIFIERS\n===========================\n"); - lex_reset(file); - while ((token = lex_token(file)) != ERROR_LEX && file->length >= 0) - if (token == LEX_IDENT) - printf("%s ", file->lastok); - fputc('\n', stdout); - lex_reset(file); - return 1; + + FILE *fp = fopen(file, "r"); + if (!fp) { + error(lex, ERROR_LEX, "Include file `%s` doesn't exist\n", file); + exit (-1); + } + + return lex_open(fp); }