]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lexer.c
JS stuff
[xonotic/gmqcc.git] / lexer.c
diff --git a/lexer.c b/lexer.c
index eb215f49107283cbe434b7c906426fb532b2b842..64caad686c6ea35f43a729136c53ef9ae836a642 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -162,6 +162,34 @@ lex_file* lex_open(const char *file)
     return lex;
 }
 
+lex_file* lex_open_string(const char *str, size_t len, const char *name)
+{
+    lex_file *lex;
+
+    lex = (lex_file*)mem_a(sizeof(*lex));
+    if (!lex) {
+        lexerror(NULL, "out of memory\n");
+        return NULL;
+    }
+
+    memset(lex, 0, sizeof(*lex));
+
+    lex->file = NULL;
+    lex->open_string        = str;
+    lex->open_string_length = len;
+    lex->open_string_pos    = 0;
+
+    lex->name = util_strdup(name ? name : "<string-source>");
+    lex->line = 1; /* we start counting at 1 */
+
+    lex->peekpos = 0;
+    lex->eof = false;
+
+    lex_filenames_add(lex->name);
+
+    return lex;
+}
+
 void lex_cleanup(void)
 {
     size_t i;
@@ -192,6 +220,18 @@ void lex_close(lex_file *lex)
     mem_d(lex);
 }
 
+static int lex_fgetc(lex_file *lex)
+{
+    if (lex->file)
+        return fgetc(lex->file);
+    if (lex->open_string) {
+        if (lex->open_string_pos >= lex->open_string_length)
+            return EOF;
+        return lex->open_string[lex->open_string_pos++];
+    }
+    return EOF;
+}
+
 /* Get or put-back data
  * The following to functions do NOT understand what kind of data they
  * are working on.
@@ -201,13 +241,13 @@ static void lex_ungetch(lex_file *lex, int ch);
 static int lex_try_trigraph(lex_file *lex, int old)
 {
     int c2, c3;
-    c2 = fgetc(lex->file);
+    c2 = lex_fgetc(lex);
     if (c2 != '?') {
         lex_ungetch(lex, c2);
         return old;
     }
 
-    c3 = fgetc(lex->file);
+    c3 = lex_fgetc(lex);
     switch (c3) {
         case '=': return '#';
         case '/': return '\\';
@@ -228,7 +268,7 @@ static int lex_try_trigraph(lex_file *lex, int old)
 static int lex_try_digraph(lex_file *lex, int ch)
 {
     int c2;
-    c2 = fgetc(lex->file);
+    c2 = lex_fgetc(lex);
     if      (ch == '<' && c2 == ':')
         return '[';
     else if (ch == ':' && c2 == '>')
@@ -254,7 +294,7 @@ static int lex_getch(lex_file *lex)
         return lex->peek[lex->peekpos];
     }
 
-    ch = fgetc(lex->file);
+    ch = lex_fgetc(lex);
     if (ch == '\n')
         lex->line++;
     else if (ch == '?')
@@ -350,6 +390,7 @@ printf(   "line one\n"
 static int lex_skipwhite(lex_file *lex)
 {
     int ch = 0;
+    bool haswhite = false;
 
     do
     {
@@ -359,7 +400,7 @@ static int lex_skipwhite(lex_file *lex)
                 if (ch == '\n') {
                     /* end-of-line */
                     /* see if there was whitespace first */
-                    if (lex->tok.value_count) {
+                    if (haswhite) { /* (lex->tok.value_count) { */
                         lex_ungetch(lex, ch);
                         if (!lex_endtoken(lex))
                             return TOKEN_FATAL;
@@ -368,13 +409,12 @@ static int lex_skipwhite(lex_file *lex)
                     /* otherwise return EOL */
                     return TOKEN_EOL;
                 }
+                haswhite = true;
                 if (!lex_tokench(lex, ch))
                     return TOKEN_FATAL;
             }
             ch = lex_getch(lex);
         }
-        if (lex->flags.preprocessing && !lex_tokench(lex, ch))
-            return TOKEN_FATAL;
 
         if (ch == '/') {
             ch = lex_getch(lex);
@@ -384,17 +424,18 @@ static int lex_skipwhite(lex_file *lex)
                 ch = lex_getch(lex);
 
                 if (lex->flags.preprocessing) {
-                    if (!lex_tokench(lex, ' ') ||
-                        !lex_tokench(lex, ' '))
+                    haswhite = true;
+                    if (!lex_tokench(lex, '/') ||
+                        !lex_tokench(lex, '/'))
                     {
                         return TOKEN_FATAL;
                     }
                 }
 
                 while (ch != EOF && ch != '\n') {
-                    ch = lex_getch(lex);
-                    if (lex->flags.preprocessing && !lex_tokench(lex, ' '))
+                    if (lex->flags.preprocessing && !lex_tokench(lex, ch))
                         return TOKEN_FATAL;
+                    ch = lex_getch(lex);
                 }
                 if (lex->flags.preprocessing) {
                     lex_ungetch(lex, '\n');
@@ -408,8 +449,9 @@ static int lex_skipwhite(lex_file *lex)
             {
                 /* multiline comment */
                 if (lex->flags.preprocessing) {
-                    if (!lex_tokench(lex, ' ') ||
-                        !lex_tokench(lex, ' '))
+                    haswhite = true;
+                    if (!lex_tokench(lex, '/') ||
+                        !lex_tokench(lex, '*'))
                     {
                         return TOKEN_FATAL;
                     }
@@ -422,8 +464,8 @@ static int lex_skipwhite(lex_file *lex)
                         ch = lex_getch(lex);
                         if (ch == '/') {
                             if (lex->flags.preprocessing) {
-                                if (!lex_tokench(lex, ' ') ||
-                                    !lex_tokench(lex, ' '))
+                                if (!lex_tokench(lex, '*') ||
+                                    !lex_tokench(lex, '/'))
                                 {
                                     return TOKEN_FATAL;
                                 }
@@ -432,8 +474,6 @@ static int lex_skipwhite(lex_file *lex)
                         }
                     }
                     if (lex->flags.preprocessing) {
-                        if (ch != '\n')
-                            ch = ' ';
                         if (!lex_tokench(lex, ch))
                             return TOKEN_FATAL;
                     }
@@ -448,6 +488,12 @@ static int lex_skipwhite(lex_file *lex)
         }
     } while (ch != EOF && isspace(ch));
 
+    if (haswhite) {
+        if (!lex_endtoken(lex))
+            return TOKEN_FATAL;
+        lex_ungetch(lex, ch);
+        return TOKEN_WHITE;
+    }
     return ch;
 }
 
@@ -544,7 +590,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
         if (ch == quote)
             return TOKEN_STRINGCONST;
 
-        if (ch == '\\') {
+        if (!lex->flags.preprocessing && ch == '\\') {
             ch = lex_getch(lex);
             if (ch == EOF) {
                 lexerror(lex, "unexpected end of file");
@@ -675,7 +721,7 @@ int lex_do(lex_file *lex)
     lex->tok.ctx.line = lex->sline;
     lex->tok.ctx.file = lex->name;
 
-    if (lex->flags.preprocessing && (ch == TOKEN_WHITE || ch == TOKEN_EOL || TOKEN_FATAL)) {
+    if (lex->flags.preprocessing && (ch == TOKEN_WHITE || ch == TOKEN_EOL || ch == TOKEN_FATAL)) {
         return (lex->tok.ttype = ch);
     }
 
@@ -1060,8 +1106,12 @@ int lex_do(lex_file *lex)
     if (ch == '"')
     {
         lex->flags.nodigraphs = true;
+        if (lex->flags.preprocessing && !lex_tokench(lex, ch))
+            return TOKEN_FATAL;
         lex->tok.ttype = lex_finish_string(lex, '"');
-        while (lex->tok.ttype == TOKEN_STRINGCONST)
+        if (lex->flags.preprocessing && !lex_tokench(lex, ch))
+            return TOKEN_FATAL;
+        while (!lex->flags.preprocessing && lex->tok.ttype == TOKEN_STRINGCONST)
         {
             /* Allow c style "string" "continuation" */
             ch = lex_skipwhite(lex);
@@ -1085,23 +1135,28 @@ int lex_do(lex_file *lex)
          * Likewise actual unescaping has to be done by the parser.
          * The difference is we don't allow 'char' 'continuation'.
          */
-         lex->tok.ttype = lex_finish_string(lex, '\'');
-         if (!lex_endtoken(lex))
-              return (lex->tok.ttype = TOKEN_FATAL);
+        if (lex->flags.preprocessing && !lex_tokench(lex, ch))
+            return TOKEN_FATAL;
+        lex->tok.ttype = lex_finish_string(lex, '\'');
+        if (lex->flags.preprocessing && !lex_tokench(lex, ch))
+            return TOKEN_FATAL;
+        if (!lex_endtoken(lex))
+            return (lex->tok.ttype = TOKEN_FATAL);
 
          /* It's a vector if we can successfully scan 3 floats */
 #ifdef WIN32
-         if (sscanf_s(lex->tok.value, " %f %f %f ",
-                    &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
+        if (sscanf_s(lex->tok.value, " %f %f %f ",
+                   &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
 #else
-         if (sscanf(lex->tok.value, " %f %f %f ",
-                    &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
+        if (sscanf(lex->tok.value, " %f %f %f ",
+                   &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
 #endif
-         {
-              lex->tok.ttype = TOKEN_VECTORCONST;
-         }
 
-         return lex->tok.ttype;
+        {
+             lex->tok.ttype = TOKEN_VECTORCONST;
+        }
+
+        return lex->tok.ttype;
     }
 
     if (isdigit(ch))