X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=lex.c;h=54875a35a1314d1459157236a9cb5d416e481410;hb=c81eb57480ccb652bf990abc7cd2cd8671187e32;hp=f30073fc9fdcc48aa8e9e16987c0c42559ada90e;hpb=32b804864ebfce0ed4f8ae891683d11c71ae389a;p=xonotic%2Fgmqcc.git diff --git a/lex.c b/lex.c index f30073f..54875a3 100644 --- a/lex.c +++ b/lex.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 + * Copyright (C) 2012 * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -32,37 +32,42 @@ static const char *const lex_keywords[] = { "for", "typedef" }; -struct lex_file *lex_open(FILE *fp) { - struct lex_file *lex = mem_a(sizeof(struct lex_file)); - if (!lex || !fp) - return NULL; - - lex->file = fp; +void lex_init(const char *file, lex_file **set) { + lex_file *lex = mem_a(sizeof(lex_file)); + if (!lex) + return; + + lex->file = fopen(file, "r"); + if (!lex->file) { + mem_d(lex); + return; + } + 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; - + lex->line = 1; + memset(lex->peek, 0, sizeof(lex->peek)); - return lex; + *set = lex; } -void lex_close(struct lex_file *file) { +void lex_close(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 void lex_addch(int ch, lex_file *file) { if (file->current < sizeof(file->lastok)-1) file->lastok[file->current++] = (char)ch; if (file->current == sizeof(file->lastok)-1) file->lastok[file->current] = (char)'\0'; } -static inline void lex_clear(struct lex_file *file) { +static GMQCC_INLINE void lex_clear(lex_file *file) { file->current = 0; } @@ -71,15 +76,26 @@ static inline void lex_clear(struct lex_file *file) { * This doesn't play with file streams, the lexer has * it's own internal state for this. */ -static int lex_inget(struct lex_file *file) { +static int lex_inget(lex_file *file) { + char get; file->length --; - if (file->last > 0) - return file->peek[--file->last]; - return fgetc(file->file); + + if (file->last > 0) { + if ((get = file->peek[--file->last]) == '\n') + file->line ++; + return get; + } + if ((get = fgetc(file->file)) == '\n') + file->line++; + + return get; } -static void lex_unget(int ch, struct lex_file *file) { - if (file->last < sizeof(file->peek)) +static void lex_unget(int ch, lex_file *file) { + if (file->last < sizeof(file->peek)) { + if (ch == '\n') + file->line --; file->peek[file->last++] = ch; + } file->length ++; } @@ -87,13 +103,13 @@ static void lex_unget(int ch, struct lex_file *file) { * This is trigraph and digraph support, a feature not qc compiler * supports. Moving up in this world! */ -static int lex_trigraph(struct lex_file *file) { +static int lex_trigraph(lex_file *file) { int ch; if ((ch = lex_inget(file)) != '?') { lex_unget(ch, file); return '?'; } - + ch = lex_inget(file); switch (ch) { case '(' : return '[' ; @@ -108,11 +124,10 @@ static int lex_trigraph(struct lex_file *file) { default: lex_unget('?', file); lex_unget(ch , file); - return '?'; } return '?'; } -static int lex_digraph(struct lex_file *file, int first) { +static int lex_digraph(lex_file *file, int first) { int ch = lex_inget(file); switch (first) { case '<': @@ -127,57 +142,45 @@ static int lex_digraph(struct lex_file *file, int first) { if (ch == '>') return ']'; break; } - + lex_unget(ch, file); return first; } -static int lex_getch(struct lex_file *file) { +static int lex_getch(lex_file *file) { int ch = lex_inget(file); - - 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++; - } - + if (ch == '?') + return lex_trigraph(file); + if (ch == '<' || ch == ':' || ch == '%') + return lex_digraph(file, ch); return ch; } -static int lex_get(struct lex_file *file) { +static int lex_get(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 ' '; } -static int lex_skipchr(struct lex_file *file) { +static int lex_skipchr(lex_file *file) { int ch; int it; - + lex_clear(file); lex_addch('\'', file); - + for (it = 0; it < 2 && ((ch = lex_inget(file)) != '\''); it++) { lex_addch(ch, file); - + if (ch == '\n') return ERROR_LEX; if (ch == '\\') @@ -185,41 +188,41 @@ static int lex_skipchr(struct lex_file *file) { } lex_addch('\'', file); lex_addch('\0', file); - + if (it > 2) return ERROR_LEX; - + return LEX_CHRLIT; } -static int lex_skipstr(struct lex_file *file) { +static int lex_skipstr(lex_file *file) { int ch; lex_clear(file); lex_addch('"', file); - + while ((ch = lex_getch(file)) != '"') { if (ch == '\n' || ch == EOF) return ERROR_LEX; - + lex_addch(ch, file); if (ch == '\\') lex_addch(lex_inget(file), file); } - + lex_addch('"', file); lex_addch('\0', file); - + return LEX_STRLIT; } -static int lex_skipcmt(struct lex_file *file) { +static int lex_skipcmt(lex_file *file) { int ch; lex_clear(file); ch = lex_getch(file); - + if (ch == '/') { lex_addch('/', file); lex_addch('/', file); - + while ((ch = lex_getch(file)) != '\n') { if (ch == '\\') { lex_addch(ch, file); @@ -231,14 +234,14 @@ static int lex_skipcmt(struct lex_file *file) { lex_addch('\0', file); return LEX_COMMENT; } - + if (ch != '*') { lex_unget(ch, file); return '/'; } - + lex_addch('/', file); - + /* hate this */ do { lex_addch(ch, file); @@ -250,16 +253,16 @@ static int lex_skipcmt(struct lex_file *file) { } lex_addch(ch, file); } while ((ch = lex_getch(file)) != '/'); - + lex_addch('/', file); lex_addch('\0', file); - + return LEX_COMMENT; } -static int lex_getsource(struct lex_file *file) { +static int lex_getsource(lex_file *file) { int ch = lex_get(file); - + /* skip char/string/comment */ switch (ch) { case '\'': return lex_skipchr(file); @@ -270,32 +273,26 @@ static int lex_getsource(struct lex_file *file) { } } -int lex_token(struct lex_file *file) { +int lex_token(lex_file *file) { int ch = lex_getsource(file); int it; - + /* valid identifier */ if (ch > 0 && (ch == '_' || isalpha(ch))) { lex_clear(file); - - /* - * 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 != ')') { + + while (ch > 0 && (ch == '_' || isalpha(ch))) { lex_addch(ch, file); ch = lex_getsource(file); } lex_unget(ch, file); lex_addch('\0', file); - + /* look inside the table for a keyword .. */ for (it = 0; it < sizeof(lex_keywords)/sizeof(*lex_keywords); it++) if (!strncmp(file->lastok, lex_keywords[it], strlen(lex_keywords[it]))) return it; - + /* try a type? */ #define TEST_TYPE(X) \ do { \ @@ -310,46 +307,48 @@ int lex_token(struct lex_file *file) { 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; + return (ch != ' ') ? ch : lex_token(file); } -void lex_reset(struct lex_file *file) { +void lex_reset(lex_file *file) { file->current = 0; file->last = 0; file->length = file->size; fseek(file->file, 0, SEEK_SET); - + memset(file->peek, 0, sizeof(file->peek )); memset(file->lastok, 0, sizeof(file->lastok)); } +void lex_parse(lex_file *file) { + if (!file) return; + parse_gen(file); /* run parser */ +} + /* * 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) { +lex_file *lex_include(lex_file *lex, const char *file) { + lex_file *set = NULL; + util_strrq(file); if (strncmp(lex->name, file, strlen(lex->name)) == 0) { error(lex, ERROR_LEX, "Source file cannot include itself\n"); exit (-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); + lex_init(file, &set); + + return set; }