]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parse.c
AUTHORS
[xonotic/gmqcc.git] / parse.c
diff --git a/parse.c b/parse.c
index 792495b83e7c7717346496f6fba290585865a119..2d52efdec35e8b14e6c4f4854b6ef669d33e3d9e 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 
- *     Dale Weiler
+ *     Dale Weiler
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  * this software and associated documentation files (the "Software"), to deal in
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
 #include "gmqcc.h"
 
-/*
- * These are not lexical tokens:  These are parse tree types.  Most people
- * perform tokenizing on language punctuation which is wrong.  That stuff
- * is technically already tokenized, it just needs to be parsed into a tree
- */
-#define PARSE_TYPE_DO       0
-#define PARSE_TYPE_ELSE     1
-#define PARSE_TYPE_IF       2
-#define PARSE_TYPE_WHILE    3
-#define PARSE_TYPE_BREAK    4
-#define PARSE_TYPE_CONTINUE 5
-#define PARSE_TYPE_RETURN   6
-#define PARSE_TYPE_GOTO     7
-#define PARSE_TYPE_FOR      8
-#define PARSE_TYPE_VOID     9
-#define PARSE_TYPE_STRING   10
-#define PARSE_TYPE_FLOAT    11
-#define PARSE_TYPE_VECTOR   12
-#define PARSE_TYPE_ENTITY   13
-#define PARSE_TYPE_LAND     14
-#define PARSE_TYPE_LOR      15
-#define PARSE_TYPE_LTEQ     16
-#define PARSE_TYPE_GTEQ     17
-#define PARSE_TYPE_EQEQ     18
-#define PARSE_TYPE_LNEQ     19
-#define PARSE_TYPE_COMMA    20
-#define PARSE_TYPE_LNOT     21
-#define PARSE_TYPE_STAR     22
-#define PARSE_TYPE_DIVIDE   23
-#define PARSE_TYPE_LPARTH   24
-#define PARSE_TYPE_RPARTH   25
-#define PARSE_TYPE_MINUS    26
-#define PARSE_TYPE_ADD      27
-#define PARSE_TYPE_EQUAL    28
-#define PARSE_TYPE_LBS      29
-#define PARSE_TYPE_RBS      30
-#define PARSE_TYPE_ELIP     31
-#define PARSE_TYPE_DOT      32
-#define PARSE_TYPE_LT       33
-#define PARSE_TYPE_GT       34
-#define PARSE_TYPE_BAND     35
-#define PARSE_TYPE_BOR      36
-#define PARSE_TYPE_DONE     37
-#define PARSE_TYPE_IDENT    38
+/* compile-time constant for type constants */
+typedef struct {
+    char *name;
+    int   type;
+    float value[3];
+    char *string; /* string value if constant is string literal */
+} constant;
+VECTOR_MAKE(constant, compile_constants);
 
-/*
- * Adds a parse type to the parse tree, this is where all the hard
- * work actually begins.
- */
-#define PARSE_TREE_ADD(X)                                        \
-       do {                                                         \
-               parsetree->next       = mem_a(sizeof(struct parsenode)); \
-               parsetree->next->next = NULL;                            \
-               parsetree->next->type = (X);                             \
-               parsetree             = parsetree->next;                 \
-       } while (0)
-
-/*
- * This is all the punctuation handled in the parser, these don't
- * need tokens, they're already tokens.
- */
-#if 0
-       "&&", "||", "<=", ">=", "==", "!=", ";", ",", "!", "*",
-       "/" , "(" , ")" , "-" , "+" , "=" , "[" , "]", "{", "}", "...",
-       "." , "<" , ">" , "&" , "|" , 
-#endif
-
-#define STORE(X,C) {  \
-    long f = fill;    \
-    while(f--) {      \
-      putchar(' ');   \
-    }                 \
-    fill C;           \
-       printf(X);        \
-       break;            \
-}
-
-void parse_debug(struct parsenode *tree) {
-       long fill = 0;
-       while (tree) {  
-               switch (tree->type) {
-                       case PARSE_TYPE_ADD:       STORE("OPERATOR:  ADD    \n", -=0);
-                       case PARSE_TYPE_BAND:      STORE("OPERATOR:  BITAND \n",-=0);
-                       case PARSE_TYPE_BOR:       STORE("OPERATOR:  BITOR  \n",-=0);
-                       case PARSE_TYPE_COMMA:     STORE("OPERATOR:  SEPERATOR\n",-=0);
-                       case PARSE_TYPE_DOT:       STORE("OPERATOR:  DOT\n",-=0);
-                       case PARSE_TYPE_DIVIDE:    STORE("OPERATOR:  DIVIDE\n",-=0);
-                       case PARSE_TYPE_EQUAL:     STORE("OPERATOR:  ASSIGNMENT\n",-=0);
-                       
-                       case PARSE_TYPE_BREAK:     STORE("STATEMENT: BREAK  \n",-=0);
-                       case PARSE_TYPE_CONTINUE:  STORE("STATEMENT: CONTINUE\n",-=0);
-                       case PARSE_TYPE_GOTO:      STORE("STATEMENT: GOTO\n",-=0);
-                       case PARSE_TYPE_RETURN:    STORE("STATEMENT: RETURN\n",-=0);
-                       case PARSE_TYPE_DONE:      STORE("STATEMENT: DONE\n",-=0);
-
-                       case PARSE_TYPE_VOID:      STORE("DECLTYPE:  VOID\n",-=0);
-                       case PARSE_TYPE_STRING:    STORE("DECLTYPE:  STRING\n",-=0);
-                       case PARSE_TYPE_ELIP:      STORE("DECLTYPE:  VALIST\n",-=0);
-                       case PARSE_TYPE_ENTITY:    STORE("DECLTYPE:  ENTITY\n",-=0);
-                       case PARSE_TYPE_FLOAT:     STORE("DECLTYPE:  FLOAT\n",-=0);
-                       case PARSE_TYPE_VECTOR:    STORE("DECLTYPE:  VECTOR\n",-=0);
-                       
-                       case PARSE_TYPE_GT:        STORE("TEST:      GREATER THAN\n",-=0);
-                       case PARSE_TYPE_LT:        STORE("TEST:      LESS THAN\n",-=0);
-                       case PARSE_TYPE_GTEQ:      STORE("TEST:      GREATER THAN OR EQUAL\n",-=0);
-                       case PARSE_TYPE_LTEQ:      STORE("TEST:      LESS THAN OR EQUAL\n",-=0);
-                       case PARSE_TYPE_LNEQ:      STORE("TEST:      NOT EQUAL\n",-=0);
-                       case PARSE_TYPE_EQEQ:      STORE("TEST:      EQUAL-EQUAL\n",-=0);
-                       
-                       case PARSE_TYPE_LBS:       STORE("BLOCK:     BEG\n",+=4);
-                       case PARSE_TYPE_RBS:       STORE("BLOCK:     END\n",-=4);
-                       case PARSE_TYPE_ELSE:      STORE("BLOCK:     ELSE\n",+=0);
-                       case PARSE_TYPE_IF:        STORE("BLOCK:     IF\n",+=0);
-                       
-                       case PARSE_TYPE_LAND:      STORE("LOGICAL:   AND\n",-=0);
-                       case PARSE_TYPE_LNOT:      STORE("LOGICAL:   NOT\n",-=0);
-                       case PARSE_TYPE_LOR:       STORE("LOGICAL:   OR\n",-=0);
-                       
-                       case PARSE_TYPE_LPARTH:    STORE("PARTH:     BEG\n",-=0);
-                       case PARSE_TYPE_RPARTH:    STORE("PARTH:     END\n",-=0);
-                       
-                       case PARSE_TYPE_WHILE:     STORE("LOOP:      WHILE\n",-=0);
-                       case PARSE_TYPE_FOR:       STORE("LOOP:      FOR\n",-=0);
-                       case PARSE_TYPE_DO:        STORE("LOOP:      DO\n",-=0);
-               }
-               tree = tree->next;
-       }
+void compile_constant_debug() {
+    int iter = 0;
+    for(; iter < compile_constants_elements; iter++) {
+        constant *c = &compile_constants_data[iter];
+        switch(c->type) {
+            case TYPE_FLOAT:  printf("constant: %s FLOAT   %f\n",       c->name, c->value[0]);                           break;
+            case TYPE_VECTOR: printf("constant: %s VECTOR {%f,%f,%f}\n",c->name, c->value[0], c->value[1], c->value[2]); break;
+            case TYPE_STRING: printf("constant: %s STRING  %s\n",       c->name, c->string); break;
+            case TYPE_VOID:   printf("constant: %s VOID    %s\n",       c->name, c->string); break;
+        }
+    }
 }
 
-/*
- * Performs a parse operation:  This is a macro to prevent bugs, if the
- * calls to lex_token are'nt exactly enough to feed to the end of the
- * actual lexees for the current thing that is being parsed, the state 
- * of the next iteration in the creation of the parse tree will be wrong
- * and everything will fail.
- */
-#define PARSE_PERFORM(X,C) {     \
-    token = lex_token(file);     \
-    { C }                        \
-    while (token != '\n') {      \
-           token = lex_token(file); \
-    }                            \
-    PARSE_TREE_ADD(X);           \
-    break;                       \
-}
-
-void parse_clear(struct parsenode *tree) {
-       if (!tree) return;
-       struct parsenode *temp = NULL;
-       while (tree != NULL) {
-               temp = tree;
-               tree = tree->next;
-               mem_d (temp);
-       }
-       
-       /* free any potential typedefs */
-       typedef_clear();
-}
-
-const char *STRING_(char ch) {
-       if (ch == ' ')
-               return "<space>";
-       if (ch == '\n')
-               return "<newline>";
-       if (ch == '\0')
-               return "<null>";
-               
-       return &ch;
-}
-
-#define TOKEN_SKIPWHITE()        \
-       token = lex_token(file);     \
-       while (token == ' ') {       \
-               token = lex_token(file); \
-       }
-
 /*
  * Generates a parse tree out of the lexees generated by the lexer.  This
  * is where the tree is built.  This is where valid check is performed.
  */
-int parse_tree(struct lex_file *file) {
-       struct parsenode *parsetree = NULL;
-       struct parsenode *parseroot = NULL;
-       
-       /*
-        * Allocate memory for our parse tree:
-        * the parse tree is just a singly linked list which will contain
-        * all the data for code generation.
-        */
-       if (!parseroot) {
-               parseroot = mem_a(sizeof(struct parsenode));
-               if (!parseroot)
-                       return error(ERROR_INTERNAL, "Ran out of memory", " ");
-               parsetree       = parseroot;
-               parsetree->type = -1; /* not a valid type -- root element */
-       }
-       
-       int     token = 0;
-       long    line  = 0;
-       while ((token = lex_token(file)) != ERROR_LEX      && \
-                   token                    != ERROR_COMPILER && \
-                   token                    != ERROR_INTERNAL && \
-                   token                    != ERROR_PARSE    && \
-                   token                    != ERROR_PREPRO   && file->length >= 0) {
-               line = file->line;
-               switch (token) {
-                       case TOKEN_TYPEDEF: {
-                               char *f; /* from */
-                               char *t; /* to   */
-                               
-                               token = lex_token(file); 
-                               token = lex_token(file); f = util_strdup(file->lastok);
-                               token = lex_token(file); 
-                               token = lex_token(file); t = util_strdup(file->lastok);
-                               
-                               typedef_add(f, t);
-                               mem_d(f);
-                               mem_d(t);
-                               
-                               token = lex_token(file);
-                               if (token == ' ')
-                                       token = lex_token(file);
-                                       
-                               if (token != ';')
-                                       error(ERROR_PARSE, "%s:%d Expected a `;` at end of typedef statement\n", file->name, file->line);
-                                       
-                               token = lex_token(file);
-                               break;
-                       }
-                       
-                       case TOKEN_VOID:      PARSE_TREE_ADD(PARSE_TYPE_VOID);   goto fall;
-                       case TOKEN_STRING:    PARSE_TREE_ADD(PARSE_TYPE_STRING); goto fall;
-                       case TOKEN_VECTOR:    PARSE_TREE_ADD(PARSE_TYPE_VECTOR); goto fall;
-                       case TOKEN_ENTITY:    PARSE_TREE_ADD(PARSE_TYPE_ENTITY); goto fall;
-                       case TOKEN_FLOAT:     PARSE_TREE_ADD(PARSE_TYPE_FLOAT);  goto fall;
-                       {
-                       fall:;
-                               char *name = NULL;
-                               int   type = token; /* story copy */
-                               
-                               /* skip over space */
-                               token = lex_token(file);
-                               if (token == ' ')
-                                       token = lex_token(file);
-                               
-                               /* save name */
-                               name = util_strdup(file->lastok);
-                               
-                               /* skip spaces */
-                               token = lex_token(file);
-                               if (token == ' ')
-                                       token = lex_token(file);
-                                       
-                               if (token == ';') {
-                                       /*
-                                        * Definitions go to the defs table, they don't have
-                                        * any sort of data with them yet.
-                                        */
-                               } else if (token == '=') {
-                                       token = lex_token(file);
-                                       if (token == ' ')
-                                               token = lex_token(file);
-                                       
-                                       /* strings are in file->lastok */
-                                       switch (type) {
-                                               case TOKEN_VOID:
-                                                       return error(ERROR_PARSE, "%s:%d Cannot assign value to type void\n", file->name, file->line);
-                                               case TOKEN_STRING:
-                                                       if (*file->lastok != '"')
-                                                               error(ERROR_PARSE, "%s:%d Expected a '\"' (quote) for string constant\n", file->name, file->line);
-                                                       break;
-                                               case TOKEN_VECTOR: {
-                                                       float compile_calc_x = 0;
-                                                       float compile_calc_y = 0;
-                                                       float compile_calc_z = 0;
-                                                       int   compile_calc_d = 0; /* dot?        */
-                                                       int   compile_calc_s = 0; /* sign (-, +) */
-                                                       
-                                                       char  compile_data[1024];
-                                                       char *compile_eval = compile_data;
-                                                       
-                                                       if (token != '{')
-                                                               error(ERROR_PARSE, "%s:%d Expected initializer list `{`,`}` for vector constant\n", file->name, file->line);    
-                                                       
-                                                       /*
-                                                        * This parses a single vector element: x,y & z.  This will handle all the
-                                                        * complicated mechanics of a vector, and can be extended as well.  This
-                                                        * is a rather large macro, and is #undef after it's use below.
-                                                        */
-                                                       #define PARSE_VEC_ELEMENT(NAME, BIT)                                                                                                                                   \
-                                                               token = lex_token(file);                                                                                                                                           \
-                                                               if (token == ' ') {                                                                                                                                                \
-                                                                       token = lex_token(file);                                                                                                                                       \
-                                                               }                                                                                                                                                                  \
-                                                               if (token == '.') {                                                                                                                                                \
-                                                                       compile_calc_d = 1;                                                                                                                                            \
-                                                               }                                                                                                                                                                  \
-                                                               if (!isdigit(token) && !compile_calc_d && token != '+' && token != '-')                                                                                            \
-                                                                       error(ERROR_PARSE,"%s:%d Invalid constant initializer element %c for vector, must be numeric\n", file->name, file->line, NAME);                                \
-                                                               if (token == '+') {                                                                                                                                                \
-                                                                       compile_calc_s = '+';                                                                                                                                          \
-                                                               }                                                                                                                                                                  \
-                                                               if (token == '-' && !compile_calc_s) {                                                                                                                             \
-                                                                       compile_calc_s = '-';                                                                                                                                          \
-                                                               }                                                                                                                                                                  \
-                                                               while (isdigit(token) || token == '.' || token == '+' || token == '-') {                                                                                           \
-                                                                       *compile_eval++ = token;                                                                                                                                       \
-                                                                       token           = lex_token(file);                                                                                                                             \
-                                                                       if (token == '.' && compile_calc_d) {                                                                                                                          \
-                                                                               error(ERROR_PARSE, "%s:%d Invalid constant initializer element %c for vector, must be numeric.\n", file->name, file->line, NAME);                          \
-                                                                               token = lex_token(file);                                                                                                                                   \
-                                                                       }                                                                                                                                                              \
-                                                                       if ((token == '-' || token == '+') && compile_calc_s) {                                                                                                        \
-                                                                               error(ERROR_PARSE, "%s:%d Invalid constant initializer sign for vector element %c\n", file->name, file->line, NAME);                                       \
-                                                                               token = lex_token(file);                                                                                                                                   \
-                                                                       } else if (token == '.' && !compile_calc_d) {                                                                                                                  \
-                                                                               compile_calc_d = 1;                                                                                                                                        \
-                                                                       } else if (token == '-' && !compile_calc_s) {                                                                                                                  \
-                                                                               compile_calc_s = '-';                                                                                                                                      \
-                                                                       } else if (token == '+' && !compile_calc_s) {                                                                                                                  \
-                                                                               compile_calc_s = '+';                                                                                                                                      \
-                                                                       }                                                                                                                                                              \
-                                                               }                                                                                                                                                                  \
-                                                               if (token == ' ') {                                                                                                                                                \
-                                                                       token = lex_token(file);                                                                                                                                       \
-                                                               }                                                                                                                                                                  \
-                                                               if (NAME != 'z') {                                                                                                                                                 \
-                                                                       if (token != ',' && token != ' ')  {                                                                                                                           \
-                                                                               error(ERROR_PARSE, "%s:%d invalid constant initializer element %c for vector (missing spaces, or comma delimited list?)\n", NAME, file->name, file->line); \
-                                                                       }                                                                                                                                                              \
-                                                               } else if (token != '}') {                                                                                                                                         \
-                                                                       error(ERROR_PARSE, "%s:%d Expected `}` on end of constant initialization for vector\n", file->name, file->line);                                               \
-                                                               }                                                                                                                                                                  \
-                                                               compile_calc_##BIT = atof(compile_data);                                                                                                                           \
-                                                               compile_calc_d = 0;                                                                                                                                                \
-                                                               compile_calc_s = 0;                                                                                                                                                \
-                                                               compile_eval   = &compile_data[0];                                                                                                                                 \
-                                                               memset(compile_data, 0, sizeof(compile_data))
-                                                       
-                                                       /*
-                                                        * Parse all elements using the macro above.
-                                                        * We must undef the macro afterwards.
-                                                        */
-                                                       PARSE_VEC_ELEMENT('x', x);
-                                                       PARSE_VEC_ELEMENT('y', y);
-                                                       PARSE_VEC_ELEMENT('z', z);
-                                                       #undef PARSE_VEC_ELEMENT
-                                                       
-                                                       /*
-                                                        * Check for the semi-colon... This is insane
-                                                        * the amount of parsing here that is.
-                                                        */
-                                                       token = lex_token(file);
-                                                       if (token == ' ')
-                                                               token = lex_token(file);
-                                                       if (token != ';')
-                                                               error(ERROR_PARSE, "%s:%d Expected `;` on end of constant initialization for vector\n", file->name, file->line);
-                                                               
-                                                       printf("VEC_X: %f\n", compile_calc_x);
-                                                       printf("VEC_Y: %f\n", compile_calc_y);
-                                                       printf("VEC_Z: %f\n", compile_calc_z);
-                                                       break;
-                                               }
-                                                       
-                                               case TOKEN_ENTITY:
-                                               case TOKEN_FLOAT:
-                                                       
-                                                       if (!isdigit(token))
-                                                               error(ERROR_PARSE, "%s:%d Expected numeric constant for float constant\n");
-                                                       break;
-                                       }
-                               } else if (token == '(') {
-                                       printf("FUNCTION ??\n");
-                               }
-                               mem_d(name);
-                       }
-                               
-                       /*
-                        * From here down is all language punctuation:  There is no
-                        * need to actual create tokens from these because they're already
-                        * tokenized as these individual tokens (which are in a special area
-                        * of the ascii table which doesn't conflict with our other tokens
-                        * which are higer than the ascii table.)
-                        */
-                       case '#':
-                               token = lex_token(file); /* skip '#' */
-                               if (token == ' ')
-                                       token = lex_token(file);
-                               /*
-                                * If we make it here we found a directive, the supported
-                                * directives so far are #include.
-                                */
-                               if (strncmp(file->lastok, "include", sizeof("include")) == 0) {
-                                       /*
-                                        * We only suport include " ", not <> like in C (why?)
-                                        * because the latter is silly.
-                                        */
-                                       while (*file->lastok != '"' && token != '\n')
-                                               token = lex_token(file);
-                                       if (token == '\n')
-                                               return error(ERROR_PARSE, "%d: Invalid use of include preprocessor directive: wanted #include \"file.h\"\n", file->line-1);
-                               }
-                       
-                               /* skip all tokens to end of directive */
-                               while (token != '\n')
-                                       token = lex_token(file);
-                               break;
-                               
-                       case LEX_IDENT:
-                               token = lex_token(file);
-                               PARSE_TREE_ADD(PARSE_TYPE_IDENT);
-                               break;
+int parse_gen(struct lex_file *file) {    
+    int     token = 0;
+    while ((token = lex_token(file)) != ERROR_LEX && file->length >= 0) {
+        switch (token) {
+            case TOKEN_TYPEDEF: {
+                char *f; /* from */
+                char *t; /* to   */
+                
+                token = lex_token(file); 
+                token = lex_token(file); f = util_strdup(file->lastok);
+                token = lex_token(file); 
+                token = lex_token(file); t = util_strdup(file->lastok);
+                
+                typedef_add(file, f, t);
+                mem_d(f);
+                mem_d(t);
+                
+                token = lex_token(file);
+                if (token == ' ')
+                    token = lex_token(file);
+                    
+                if (token != ';')
+                    error(file, ERROR_PARSE, "Expected a `;` at end of typedef statement");
+                    
+                token = lex_token(file);
+                break;
+            }
+            
+            case TOKEN_VOID:   goto fall;
+            case TOKEN_STRING: goto fall;
+            case TOKEN_VECTOR: goto fall;
+            case TOKEN_ENTITY: goto fall;
+            case TOKEN_FLOAT:  goto fall;
+            {
+            fall:;
+                char *name = NULL;
+                int   type = token; /* story copy */
+                
+                /* skip over space */
+                token = lex_token(file);
+                if (token == ' ')
+                    token = lex_token(file);
+                
+                /* save name */
+                name = util_strdup(file->lastok);
+                
+                /* skip spaces */
+                token = lex_token(file);
+                if (token == ' ')
+                    token = lex_token(file);
+                    
+                if (token == ';') {
+                    /*
+                     * Definitions go to the defs table, they don't have
+                     * any sort of data with them yet.
+                     */
+                } else if (token == '=') {
+                    token = lex_token(file);
+                    if (token == ' ')
+                        token = lex_token(file);
+                    
+                    /* strings are in file->lastok */
+                    switch (type) {
+                        case TOKEN_VOID:
+                            error(file, ERROR_PARSE, "Cannot assign value to type void\n");
+                            
+                        /* TODO: Validate (end quote), strip quotes for constant add, name constant */
+                        case TOKEN_STRING:
+                            if (*file->lastok != '"')
+                                error(file, ERROR_PARSE, "Expected a '\"' (quote) for string constant\n");
+                            /* add the compile-time constant */
+                            compile_constants_add((constant){
+                                .name   = util_strdup(name),
+                                .type   = TYPE_STRING,
+                                .value  = {0,0,0},
+                                .string = util_strdup(file->lastok)
+                            });
+                            break;
+                        /* TODO: name constant, old qc vec literals, whitespace fixes, name constant */
+                        case TOKEN_VECTOR: {
+                            float compile_calc_x = 0;
+                            float compile_calc_y = 0;
+                            float compile_calc_z = 0;
+                            int   compile_calc_d = 0; /* dot?        */
+                            int   compile_calc_s = 0; /* sign (-, +) */
+                            
+                            char  compile_data[1024];
+                            char *compile_eval = compile_data;
+                            
+                            if (token != '{')
+                                error(file, ERROR_PARSE, "Expected initializer list {} for vector constant\n");    
+                            
+                            /*
+                             * This parses a single vector element: x,y & z.  This will handle all the
+                             * complicated mechanics of a vector, and can be extended as well.  This
+                             * is a rather large macro, and is #undef'd after it's use below.
+                             */
+                            #define PARSE_VEC_ELEMENT(NAME, BIT)                                                                                                           \
+                                token = lex_token(file);                                                                                                                   \
+                                if (token == ' ')                                                                                                                          \
+                                    token = lex_token(file);                                                                                                               \
+                                if (token == '.')                                                                                                                          \
+                                    compile_calc_d = 1;                                                                                                                    \
+                                if (!isdigit(token) && !compile_calc_d && token != '+' && token != '-')                                                                    \
+                                    error(file, ERROR_PARSE,"Invalid constant initializer element %c for vector, must be numeric\n", NAME);                                \
+                                if (token == '+')                                                                                                                          \
+                                    compile_calc_s = '+';                                                                                                                  \
+                                if (token == '-' && !compile_calc_s)                                                                                                       \
+                                    compile_calc_s = '-';                                                                                                                  \
+                                while (isdigit(token) || token == '.' || token == '+' || token == '-') {                                                                   \
+                                    *compile_eval++ = token;                                                                                                               \
+                                    token           = lex_token(file);                                                                                                     \
+                                    if (token == '.' && compile_calc_d) {                                                                                                  \
+                                        error(file, ERROR_PARSE, "Invalid constant initializer element %c for vector, must be numeric.\n", NAME);                          \
+                                        token = lex_token(file);                                                                                                           \
+                                    }                                                                                                                                      \
+                                    if ((token == '-' || token == '+') && compile_calc_s) {                                                                                \
+                                        error(file, ERROR_PARSE, "Invalid constant initializer sign for vector element %c\n", NAME);                                       \
+                                        token = lex_token(file);                                                                                                           \
+                                    }                                                                                                                                      \
+                                    else if (token == '.' && !compile_calc_d)                                                                                              \
+                                        compile_calc_d = 1;                                                                                                                \
+                                    else if (token == '-' && !compile_calc_s)                                                                                              \
+                                        compile_calc_s = '-';                                                                                                              \
+                                    else if (token == '+' && !compile_calc_s)                                                                                              \
+                                        compile_calc_s = '+';                                                                                                              \
+                                }                                                                                                                                          \
+                                if (token == ' ')                                                                                                                          \
+                                    token = lex_token(file);                                                                                                               \
+                                if (NAME != 'z') {                                                                                                                         \
+                                    if (token != ',' && token != ' ')                                                                                                      \
+                                        error(file, ERROR_PARSE, "invalid constant initializer element %c for vector (missing spaces, or comma delimited list?)\n", NAME); \
+                                } else if (token != '}') {                                                                                                                 \
+                                    error(file, ERROR_PARSE, "Expected `}` on end of constant initialization for vector\n");                                               \
+                                }                                                                                                                                          \
+                                compile_calc_##BIT = atof(compile_data);                                                                                                   \
+                                compile_calc_d = 0;                                                                                                                        \
+                                compile_calc_s = 0;                                                                                                                        \
+                                compile_eval   = &compile_data[0];                                                                                                         \
+                                memset(compile_data, 0, sizeof(compile_data))
+                            
+                            /*
+                             * Parse all elements using the macro above.
+                             * We must undef the macro afterwards.
+                             */
+                            PARSE_VEC_ELEMENT('x', x);
+                            PARSE_VEC_ELEMENT('y', y);
+                            PARSE_VEC_ELEMENT('z', z);
+                            #undef PARSE_VEC_ELEMENT
+                            
+                            /* Check for the semi-colon... */
+                            token = lex_token(file);
+                            if (token == ' ')
+                                token = lex_token(file);
+                            if (token != ';')
+                                error(file, ERROR_PARSE, "Expected `;` on end of constant initialization for vector\n");
+                                
+                            /* add the compile-time constant */
+                            compile_constants_add((constant){
+                                .name   = util_strdup(name),
+                                .type   = TYPE_VECTOR,
+                                .value  = {
+                                    [0] = compile_calc_x,
+                                    [1] = compile_calc_y,
+                                    [2] = compile_calc_z
+                                },
+                                .string = NULL
+                            });
+                            break;
+                        }
+                            
+                        case TOKEN_ENTITY:
+                        case TOKEN_FLOAT: /*TODO: validate, constant generation, name constant */
+                            if (!isdigit(token))
+                                error(file, ERROR_PARSE, "Expected numeric constant for float constant\n");
+                            compile_constants_add((constant){
+                                .name   = util_strdup(name),
+                                .type   = TOKEN_FLOAT,
+                                .value  = {0,0,0},
+                                .string = NULL
+                            });
+                            break;
+                    }
+                } else if (token == '(') {
+                    printf("FUNCTION ??\n");
+                }
+                mem_d(name);
+            }
+                
+            /*
+             * From here down is all language punctuation:  There is no
+             * need to actual create tokens from these because they're already
+             * tokenized as these individual tokens (which are in a special area
+             * of the ascii table which doesn't conflict with our other tokens
+             * which are higer than the ascii table.)
+             */
+            case '#':
+                token = lex_token(file); /* skip '#' */
+                if (token == ' ')
+                    token = lex_token(file);
+                /*
+                 * If we make it here we found a directive, the supported
+                 * directives so far are #include.
+                 */
+                if (strncmp(file->lastok, "include", sizeof("include")) == 0) {
+                    /*
+                     * We only suport include " ", not <> like in C (why?)
+                     * because the latter is silly.
+                     */
+                    while (*file->lastok != '"' && token != '\n')
+                        token = lex_token(file);
+                    if (token == '\n')
+                        return error(file, ERROR_PARSE, "Invalid use of include preprocessor directive: wanted #include \"file.h\"\n");
+                        
+                    char            *copy = util_strdup(file->lastok);
+                    struct lex_file *next = lex_include(file,   copy);
+                    
+                    if (!next) {
+                        error(file, ERROR_INTERNAL, "Include subsystem failure\n");
+                        exit (-1);
+                    }
+                    compile_constants_add((constant) {
+                            .name   = "#include",
+                            .type   = TYPE_VOID,
+                            .value  = {0,0,0},
+                            .string = copy
+                    });
+                    parse_gen(next);
+                    mem_d    (copy);
+                    lex_close(next);
+                }
+                /* skip all tokens to end of directive */
+                while (token != '\n')
+                    token = lex_token(file);
+                break;
+                
+            case LEX_IDENT:
+                token = lex_token(file);
+                break;
+        }
+    }
+    compile_constant_debug();
+    lex_reset(file);
+    /* free constants */
+    {
+               size_t i = 0;
+               for (; i < compile_constants_elements; i++) {
+                       mem_d(compile_constants_data[i].name);
+                       mem_d(compile_constants_data[i].string);
                }
+               mem_d(compile_constants_data);
        }
-       parse_debug(parseroot);
-       lex_reset(file);
-       parse_clear(parseroot);
-       return 1;
-}      
+    return 1;
+}