X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=lex.c;h=5673701157a7aaf1b47fd043d821054dcaa0e488;hp=5333171ef2e28a63d57cf6bc1ccdd8720bda1d9c;hb=f67b6ea240ed62fd40d7383968940b8f90f0c6c9;hpb=e6a270a7e00abd3bcc1b587594e21ed75e341f43 diff --git a/lex.c b/lex.c index 5333171..5673701 100644 --- a/lex.c +++ b/lex.c @@ -20,50 +20,40 @@ * 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" +/* + * Keywords are multichar, punctuation lexing is a bit more complicated + * than keyword lexing. + */ static const char *const lex_keywords[] = { "do", "else", "if", "while", "break", "continue", "return", "goto", - "for", - - /* types */ - "int", - "bool", - "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) { @@ -144,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; } @@ -156,14 +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') return ch; - lex_unget(ch, file); return ' '; } @@ -244,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", " "); + return error(file, ERROR_LEX, "malformatted comment"); else lex_addch(ch, file); } @@ -265,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; } } @@ -276,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); } @@ -288,6 +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)) + TEST_TYPE(typedef_find(file->lastok)->name); + + #undef TEST_TYPE return LEX_IDENT; } return ch; @@ -303,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); }