From: Dale Weiler Date: Wed, 11 Apr 2012 07:54:01 +0000 (-0400) Subject: Some perliminary code gen code (just writes a header) X-Git-Tag: 0.1-rc1~688 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=0b322a8944aac54e143cf251df5636fc3b77bcfc;p=xonotic%2Fgmqcc.git Some perliminary code gen code (just writes a header) --- diff --git a/Makefile b/Makefile index da9d0e6..051ea18 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,8 @@ OBJ = main.o \ error.o \ parse.o \ typedef.o \ - util.o + util.o \ + code.o %.o: %.c $(CC) -c $< -o $@ $(CFLAGS) diff --git a/code.c b/code.c index ef33d31..8654ced 100644 --- a/code.c +++ b/code.c @@ -20,10 +20,151 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include #include "gmqcc.h" + +typedef struct { + uint16_t opcode; + + /* operand 1 */ + union { + int16_t s1; /* signed */ + uint16_t u1; /* unsigned */ + }; + /* operand 2 */ + union { + int16_t s2; /* signed */ + uint16_t u2; /* unsigned */ + }; + /* operand 3 */ + union { + int16_t s3; /* signed */ + uint16_t u3; /* unsigned */ + }; + + /* + * This is the same as the structure in darkplaces + * { + * unsigned short op; + * short a,b,c; + * } + * But this one is more sane to work with, and the + * type sizes are guranteed. + */ +} prog_section_statement; + +typedef struct { + /* The type is (I assume) + * 0 = ev_void + * 1 = ev_string + * 2 = ev_float + * 3 = ev_vector + * 4 = ev_entity + * 5 = ev_field + * 6 = ev_function + * 7 = ev_pointer + * 8 = ev_bad (is this right for uint16_t type?) + */ + uint16_t type; + uint16_t offset; /* offset in file? (what about length) */ + uint32_t name; /* offset in string table? (confused :() */ +} prog_section_both; + /* - * This file is empty: This is where codegen will take place: Once the - * parser is completed, right now it on;y creates parse trees. Syntax - * checking and other convoluted things on the parse tree need to take - * place much like a parser. + * var and field use the same structure. But lets not use the same + * name just for safety reasons? (still castable ...). */ +typedef prog_section_both prog_section_var; +typedef prog_section_both prog_section_field; + +typedef struct { + int32_t entry; /* in statement table for instructions */ + uint32_t args; /* What is this? */ + uint32_t locals; /* Total ints of params + locals */ + uint32_t profile; /* What is this? */ + uint32_t name; /* name of function in string table */ + uint32_t nargs; /* number of arguments */ + uint8_t argsize[8]; /* size of arguments (keep 8 always?) */ +} prog_section_function; + +typedef struct { + uint32_t offset; /* Offset in file of where data begins */ + uint32_t length; /* Length of section (how many of) */ +} prog_section; + +typedef struct { + uint32_t version; /* Program version (6) */ + uint32_t crc16; /* What is this? */ + prog_section statements; /* prog_section_statement */ + prog_section vars; /* prog_section_var */ + prog_section fields; /* prog_section_field */ + prog_section functions; /* prog_section_function */ + prog_section strings; /* What is this? */ + prog_section globals; /* What is this? */ + uint32_t entfield; /* Number of entity fields */ +} prog_header; + +/* + * The macros below expand to a typesafe vector implementation, which + * can be viewed in gmqcc.h + * + * code_statements_data -- raw prog_section_statement array + * code_statements_elements -- number of elements + * code_statements_allocated -- size of the array allocated + * code_statements_add(T) -- add element (returns -1 on error) + * + * code_vars_data -- raw prog_section_var array + * code_vars_elements -- number of elements + * code_vars_allocated -- size of the array allocated + * code_vars_add(T) -- add element (returns -1 on error) + * + * code_fields_data -- raw prog_section_field array + * code_fields_elements -- number of elements + * code_fields_allocated -- size of the array allocated + * code_fields_add(T) -- add element (returns -1 on error) + * + * code_functions_data -- raw prog_section_function array + * code_functions_elements -- number of elements + * code_functions_allocated -- size of the array allocated + * code_functions_add(T) -- add element (returns -1 on error) + * + * code_globals_data -- raw prog_section_var array + * code_globals_elements -- number of elements + * code_globals_allocated -- size of the array allocated + * code_globals_add(T) -- add element (returns -1 on error) + * + * code_strings_data -- raw char* array + * code_strings_elements -- number of elements + * code_strings_allocated -- size of the array allocated + * code_strings_add(T) -- add element (returns -1 on error) + */ +VECTOR_MAKE(prog_section_statement, code_statements); +VECTOR_MAKE(prog_section_var, code_vars ); +VECTOR_MAKE(prog_section_field, code_fields ); +VECTOR_MAKE(prog_section_function, code_functions ); +VECTOR_MAKE(prog_section_var, code_globals ); +VECTOR_MAKE(char*, code_strings ); + +/* program header */ +prog_header code_header; +void code_write() { + code_header.version = 6; + code_header.crc16 = 0; /* TODO: */ + code_header.statements = (prog_section){sizeof(prog_header), code_statements_elements }; + code_header.vars = (prog_section){sizeof(prog_header)+sizeof(prog_section_statement)*code_statements_elements, code_vars_elements }; + code_header.fields = (prog_section){sizeof(prog_header)+sizeof(prog_section_var) *code_vars_elements, code_fields_elements }; + code_header.functions = (prog_section){sizeof(prog_header)+sizeof(prog_section_field) *code_fields_elements, code_functions_elements }; + code_header.globals = (prog_section){sizeof(prog_header)+sizeof(prog_section_function) *code_functions_elements, code_globals_elements }; + /* how, I think I don't have strings figured out yet :| */ + code_header.entfield = 0; /* TODO: */ + + #if 0 /* is this right? */ + fwrite(&code_header, 1, sizeof(prog_header), fp); + fwrite(code_statements_data, 1, sizeof(prog_section_statement)*code_statements_elements, fp); + fwrite(code_vars_data, 1, sizeof(prog_section_var) *code_vars_elements, fp); + fwrite(code_fields_data, 1, sizeof(prog_section_field) *code_fields_elements, fp); + fwrite(code_functions_data, 1, sizeof(prog_section_function) *code_functions_elements, fp); + fwrite(code_globals_data, 1, sizeof(prog_section_var) *code_globals_elements, fp); + #endif +} diff --git a/gmqcc.h b/gmqcc.h index 68c7367..0e29bc0 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -124,6 +124,28 @@ char *util_strdup (const char *); # define mem_d(x) util_memory_d((x), __LINE__, __FILE__) #endif +#define VECTOR_MAKE(T,N) \ + T* N##_data = NULL; \ + long N##_elements = 0; \ + long N##_allocated = 0; \ + int N##_add(T element) { \ + if (N##_elements == N##_allocated) { \ + if (N##_allocated == 0) { \ + N##_allocated = 12; \ + } else { \ + N##_allocated *= 2; \ + } \ + void *temp = realloc(N##_data, (N##_allocated * sizeof(T))); \ + if (!temp) { \ + free(temp); \ + return -1; \ + } \ + N##_data = (T*)temp; \ + } \ + N##_data[N##_elements] = element; \ + return N##_elements++; \ + } + //=================================================================== //=========================== code.c ================================ //=================================================================== diff --git a/parse.c b/parse.c index 72d2fd2..2274df9 100644 --- a/parse.c +++ b/parse.c @@ -70,6 +70,12 @@ #define PARSE_TYPE_DONE 37 #define PARSE_TYPE_IDENT 38 +int parse[PARSE_TYPE_IDENT] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 +}; + /* * Adds a parse type to the parse tree, this is where all the hard * work actually begins. @@ -82,6 +88,16 @@ parsetree = parsetree->next; \ } while (0) +#define PARSE_TREE_CHK(X,Y,Z) \ + do { \ + if(parse[X]) { \ + error(ERROR_PARSE, "Expected %c for %c\n", Y, Z); \ + exit (1); \ + } \ + } while (0) + +#define PARSE_TREE_PUT(X) do { parse[X] = 1; } while (0) + /* * This is all the punctuation handled in the parser, these don't * need tokens, they're already tokens. @@ -209,9 +225,13 @@ int parse_tree(struct lex_file *file) { token != ERROR_PREPRO && file->length >= 0) { switch (token) { case TOKEN_IF: - while ((token == ' ' || token == '\n') && file->length >= 0) - token = lex_token(file); + 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); + PARSE_TREE_CHK(PARSE_TYPE_LPARTH, ')', '('); + PARSE_TREE_PUT(PARSE_TYPE_LPARTH); break; case TOKEN_ELSE: token = lex_token(file); @@ -252,13 +272,16 @@ int parse_tree(struct lex_file *file) { * the actual parse tree check. */ case TOKEN_RETURN: + 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_CONTINUE: PARSE_PERFORM(PARSE_TYPE_CONTINUE,{}); case TOKEN_GOTO: PARSE_PERFORM(PARSE_TYPE_GOTO, {}); case TOKEN_VOID: PARSE_PERFORM(PARSE_TYPE_VOID, {}); case TOKEN_STRING: PARSE_PERFORM(PARSE_TYPE_STRING, {}); @@ -288,15 +311,18 @@ int parse_tree(struct lex_file *file) { break; case '.': - token = lex_token(file); + //token = lex_token(file); PARSE_TREE_ADD(PARSE_TYPE_DOT); break; case '(': - token = lex_token(file); + //token = lex_token(file); + PARSE_TREE_PUT(PARSE_TYPE_LPARTH); PARSE_TREE_ADD(PARSE_TYPE_LPARTH); break; case ')': - token = lex_token(file); + //token = lex_token(file); + parse[PARSE_TYPE_LPARTH] = 0; + PARSE_TREE_PUT(PARSE_TYPE_RPARTH); PARSE_TREE_ADD(PARSE_TYPE_RPARTH); break; diff --git a/test/tree.qc b/test/tree.qc index 1d9601f..b8b5568 100644 --- a/test/tree.qc +++ b/test/tree.qc @@ -1,19 +1,19 @@ -if { - if { +if(1) { + if(1) { return 0; } else { return 1; } } else { for { - if { + if(1) { return 2; } else { continue; } } do { - if { + if(1){ break; } else { goto finish;