"." , "<" , ">" , "&" , "|" ,
#endif
-#define STORE(X) { \
- printf(X); \
- break; \
+#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");
- case PARSE_TYPE_BAND: STORE("OPERATOR: BITAND \n");
- case PARSE_TYPE_BOR: STORE("OPERATOR: BITOR \n");
- case PARSE_TYPE_COMMA: STORE("OPERATOR: SEPERATOR\n");
- case PARSE_TYPE_DOT: STORE("OPERATOR: DOT\n");
- case PARSE_TYPE_DIVIDE: STORE("OPERATOR: DIVIDE\n");
- case PARSE_TYPE_EQUAL: STORE("OPERATOR: ASSIGNMENT\n");
+ 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");
- case PARSE_TYPE_CONTINUE: STORE("STATEMENT: CONTINUE\n");
- case PARSE_TYPE_GOTO: STORE("STATEMENT: GOTO\n");
- case PARSE_TYPE_RETURN: STORE("STATEMENT: RETURN\n");
- case PARSE_TYPE_DONE: STORE("STATEMENT: DONE\n");
+ 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");
- case PARSE_TYPE_STRING: STORE("DECLTYPE: STRING\n");
- case PARSE_TYPE_ELIP: STORE("DECLTYPE: VALIST\n");
- case PARSE_TYPE_ENTITY: STORE("DECLTYPE: ENTITY\n");
- case PARSE_TYPE_FLOAT: STORE("DECLTYPE: FLOAT\n");
- case PARSE_TYPE_VECTOR: STORE("DECLTYPE: VECTOR\n");
+ 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");
- case PARSE_TYPE_LT: STORE("TEST: LESS THAN\n");
- case PARSE_TYPE_GTEQ: STORE("TEST: GREATER THAN OR EQUAL\n");
- case PARSE_TYPE_LTEQ: STORE("TEST: LESS THAN OR EQUAL\n");
- case PARSE_TYPE_LNEQ: STORE("TEST: NOT EQUAL\n");
- case PARSE_TYPE_EQEQ: STORE("TEST: EQUAL-EQUAL\n");
+ 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");
- case PARSE_TYPE_RBS: STORE("BLOCK: END\n");
- case PARSE_TYPE_ELSE: STORE("BLOCK: ELSE\n");
- case PARSE_TYPE_IF: STORE("BLOCK: IF\n");
+ 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");
- case PARSE_TYPE_LNOT: STORE("LOGICAL: NOT\n");
- case PARSE_TYPE_LOR: STORE("LOGICAL: OR\n");
+ 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");
- case PARSE_TYPE_RPARTH: STORE("PARTH: END\n");
+ 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");
- case PARSE_TYPE_FOR: STORE("LOOP: FOR\n");
- case PARSE_TYPE_DO: STORE("LOOP: DO\n");
-
- //case PARSE_TYPE_IDENT: STORE("IDENT: ???\n");
+ 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;
}
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 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_IF:
- token = lex_token(file);
- if (token != '(')
- error(ERROR_PARSE, "Expected `(` on if statement:\n");
- PARSE_TREE_ADD(PARSE_TYPE_IF);
- PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
- break;
- case TOKEN_ELSE:
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_ELSE);
- break;
- case TOKEN_FOR:
- //token = lex_token(file);
- while ((token == ' ' || token == '\n') && file->length >= 0)
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_FOR);
- break;
-
- /*
- * This is a quick and easy way to do typedefs at parse time
- * all power is in typedef_add(), in typedef.c. We handle
- * the tokens accordingly here.
- */
case TOKEN_TYPEDEF: {
- char *f,*t;
+ char *f; /* from */
+ char *t; /* to */
token = lex_token(file);
token = lex_token(file); f = util_strdup(file->lastok);
token = lex_token(file); t = util_strdup(file->lastok);
typedef_add(f, t);
-
mem_d(f);
mem_d(t);
- while (token != '\n')
+ 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;
}
- /*
- * Returns are addable as-is, statement checking is during
- * the actual parse tree check.
- */
- case TOKEN_RETURN:
+ 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);
- PARSE_TREE_ADD(PARSE_TYPE_RETURN);
- break;
- case TOKEN_CONTINUE:
- PARSE_TREE_ADD(PARSE_TYPE_CONTINUE);
- break;
-
- case TOKEN_DO: PARSE_PERFORM(PARSE_TYPE_DO, {});
- case TOKEN_WHILE: PARSE_PERFORM(PARSE_TYPE_WHILE, {});
- case TOKEN_BREAK: PARSE_PERFORM(PARSE_TYPE_BREAK, {});
- case TOKEN_GOTO: PARSE_PERFORM(PARSE_TYPE_GOTO, {});
- case TOKEN_VOID: PARSE_PERFORM(PARSE_TYPE_VOID, {});
- case TOKEN_STRING: PARSE_PERFORM(PARSE_TYPE_STRING, {});
- case TOKEN_FLOAT: PARSE_PERFORM(PARSE_TYPE_FLOAT, {});
- case TOKEN_VECTOR: PARSE_PERFORM(PARSE_TYPE_VECTOR, {});
- case TOKEN_ENTITY: PARSE_PERFORM(PARSE_TYPE_ENTITY, {});
+ 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", file->name, file->line, NAME); \
+ } \
+ } 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
*/
case '#':
token = lex_token(file); /* skip '#' */
- while (isspace(token)) {
- if (token == '\n')
- return error(ERROR_PARSE, "Expected valid preprocessor directive after `#` %s\n");
- token = lex_token(file); /* try again */
- }
+ if (token == ' ')
+ token = lex_token(file);
/*
* If we make it here we found a directive, the supported
* directives so far are #include.
*/
while (*file->lastok != '"' && token != '\n')
token = lex_token(file);
-
- /* we handle lexing at that point now */
if (token == '\n')
- return error(ERROR_PARSE, "%d: Invalid use of include preprocessor directive: wanted #include \"file.h\"\n", file->line);
+ 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 */
token = lex_token(file);
break;
- case '.':
- PARSE_TREE_ADD(PARSE_TYPE_DOT);
- break;
- case '(':
- PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
- break;
- case ')':
- PARSE_TREE_ADD(PARSE_TYPE_RPARTH);
- break;
-
- case '&': /* & */
- token = lex_token(file);
- if (token == '&') { /* && */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_LAND);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_BAND);
- break;
- case '|': /* | */
- token = lex_token(file);
- if (token == '|') { /* || */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_LOR);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_BOR);
- break;
- case '!': /* ! */
- token = lex_token(file);
- if (token == '=') { /* != */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_LNEQ);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_LNOT);
- break;
- case '<': /* < */
- token = lex_token(file);
- if (token == '=') { /* <= */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_LTEQ);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_LT);
- break;
- case '>': /* > */
- token = lex_token(file);
- if (token == '=') { /* >= */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_GTEQ);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_GT);
- break;
- case '=': /* = */
- token = lex_token(file);
- if (token == '=') { /* == */
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_EQEQ);
- break;
- }
- PARSE_TREE_ADD(PARSE_TYPE_EQUAL);
- break;
- case ';':
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_DONE);
- break;
- case '-':
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_MINUS);
- break;
- case '+':
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_ADD);
- break;
- case '{':
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_LBS);
- break;
- case '}':
- token = lex_token(file);
- PARSE_TREE_ADD(PARSE_TYPE_RBS);
- break;
-
- /*
- * TODO: Fix lexer to spit out ( ) as tokens, it seems the
- * using '(' or ')' in parser doesn't work properly unless
- * there are spaces before them to allow the lexer to properly
- * seperate identifiers. -- otherwise it eats all of it.
- */
case LEX_IDENT:
token = lex_token(file);
PARSE_TREE_ADD(PARSE_TYPE_IDENT);