]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lex.c
Updated README
[xonotic/gmqcc.git] / lex.c
diff --git a/lex.c b/lex.c
index ae73dc1f97ac26b527b8de9bed40455f7a5620f3..5673701157a7aaf1b47fd043d821054dcaa0e488 100644 (file)
--- a/lex.c
+++ b/lex.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <stdio.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
 #include "gmqcc.h"
 
 /*
@@ -48,6 +43,7 @@ struct lex_file *lex_open(FILE *fp) {
        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;
@@ -57,7 +53,7 @@ void lex_close(struct lex_file *file) {
        if (!file) return;
        
        fclose(file->file); /* may already be closed */
-       mem_d(file);
+       mem_d (file);
 }
 
 static void lex_addch(int ch, struct lex_file *file) {
@@ -138,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;
 }
@@ -150,7 +157,7 @@ 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);
@@ -237,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", "");
+                               return error(file, ERROR_LEX, "malformatted comment");
                        else
                                lex_addch(ch, file);
                }
@@ -258,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;
        }
 }
 
@@ -269,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,7 +308,7 @@ int lex_token(struct lex_file *file) {
                        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);
@@ -302,6 +317,7 @@ int lex_token(struct lex_file *file) {
                if (typedef_find(file->lastok))
                        TEST_TYPE(typedef_find(file->lastok)->name);
                        
+               #undef TEST_TYPE
                return LEX_IDENT;
        }
        return ch;
@@ -316,3 +332,24 @@ void lex_reset(struct lex_file *file) {
        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) {
+       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);
+}