X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parse.c;h=0dfe3e9441a5387b932cd6964de22516b26947d4;hb=cc2c0ddbabf9fe26037a345c2ed1e18d798889a5;hp=af6c6229a1dc246a82796909f4dcb3ed11467c7a;hpb=e4e6185d5f73682aeb5858aeec2fb91fd2720120;p=xonotic%2Fgmqcc.git diff --git a/parse.c b/parse.c index af6c622..0dfe3e9 100644 --- a/parse.c +++ b/parse.c @@ -93,59 +93,63 @@ "." , "<" , ">" , "&" , "|" , #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; } @@ -181,6 +185,23 @@ void parse_clear(struct parsenode *tree) { typedef_clear(); } +const char *STRING_(char ch) { + if (ch == ' ') + return ""; + if (ch == '\n') + return ""; + if (ch == '\0') + return ""; + + 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. @@ -203,37 +224,17 @@ int parse_tree(struct lex_file *file) { } 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); @@ -241,36 +242,166 @@ int parse_tree(struct lex_file *file) { 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", 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 @@ -281,11 +412,8 @@ int parse_tree(struct lex_file *file) { */ 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. @@ -297,10 +425,8 @@ int parse_tree(struct lex_file *file) { */ 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 */ @@ -308,97 +434,6 @@ int parse_tree(struct lex_file *file) { 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);