diff --git a/Makefile b/Makefile index ea2a27f..7c33210 100644 --- a/Makefile +++ b/Makefile @@ -20,17 +20,17 @@ default: gmqcc # test targets test_ast: $(OBJ_A) $(OBJ) - $(CC) -o $@ $^ $(CFLAGS) + $(CC) -o $@ $^ $(CFLAGS) test_ir: $(OBJ_I) $(OBJ) $(CC) -o $@ $^ $(CFLAGS) test: test_ast test_ir -# compiler target +# compiler target gmqcc: $(OBJ_C) $(OBJ) $(CC) -o $@ $^ $(CFLAGS) #all target is test and all all: test gmqcc - + clean: rm -f *.o gmqcc test_ast test_ir test/*.o diff --git a/asm.c b/asm.c index 65199c9..64a9492 100644 --- a/asm.c +++ b/asm.c @@ -102,11 +102,11 @@ void asm_dumps() { * are locals. */ static GMQCC_INLINE bool asm_parse_type(const char *skip, size_t line, asm_state *state) { - if (!(strstr(skip, "FLOAT:") == &skip[0]) && - (strstr(skip, "VECTOR:") == &skip[0]) && - (strstr(skip, "ENTITY:") == &skip[0]) && - (strstr(skip, "FIELD:") == &skip[0]) && - (strstr(skip, "STRING:") == &skip[0])) return false; + if ((strstr(skip, "FLOAT:") != &skip[0]) && + (strstr(skip, "VECTOR:") != &skip[0]) && + (strstr(skip, "ENTITY:") != &skip[0]) && + (strstr(skip, "FIELD:") != &skip[0]) && + (strstr(skip, "STRING:") != &skip[0])) return false; /* TODO: determine if constant, global, or local */ switch (*skip) { @@ -194,8 +194,16 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state return false; if (strstr(skip, "FUNCTION:") == &skip[0]) { - char *copy = util_strsws(skip+10); - char *name = util_strchp(copy, strchr(copy, '\0')); + char *look = util_strdup(skip+10); + char *copy = look; + char *name = NULL; + while(*copy == ' ' || *copy == '\t') copy++; + + /* + * Chop the function name out of the string, this allocates + * a new string. + */ + name = util_strchp(copy, strchr(copy, '\0')); /* TODO: failure system, missing name */ if (!name) { @@ -380,7 +388,7 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state * We got valid function structure information now. Lets add * the function to the code writer function table. */ - function.entry = code_statements_elements-1; + function.entry = code_statements_elements; function.firstlocal = 0; function.locals = 0; function.profile = 0; @@ -391,7 +399,7 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state def.offset = code_globals_elements; def.name = code_chars_elements; code_functions_add(function); - code_globals_add(code_statements_elements); + code_globals_add (code_statements_elements); code_chars_put (name, strlen(name)); code_chars_add ('\0'); @@ -418,9 +426,18 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state * CALL* is used (depending on the amount of arguments the function * is expected to take) */ - char *c = (char*)skip; + enum { + EXPECT_FUNCTION = 1, + EXPECT_VARIABLE = 2, + EXPECT_VALUE = 3 + }; + + char *c = (char*)skip; + size_t i = 0; + char expect = 0; prog_section_statement s; - size_t i = 0; + + memset(&s, 0, sizeof(s)); /* * statements are only allowed when inside a function body @@ -444,7 +461,36 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state * instruction. */ if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) { - printf("found statement %s\n", asm_instr[i].m); + + /* + * We hit the end of a function scope, retarget the state + * and add a DONE statement to the statment table. + */ + if (i == AINSTR_END) { + s.opcode = i; + code_statements_add(s); + *state = ASM_NULL; + return true; + } + + /* + * Check the instruction type to see what sort of data + * it's expected to have. + */ + if (i >= INSTR_CALL0 && i <= INSTR_CALL8) + expect = EXPECT_FUNCTION; + else + expect = EXPECT_VARIABLE; + + util_debug( + "ASM", + "found statement %s expecting: `%s` (%ld operands)\n", + asm_instr[i].m, + (expect == EXPECT_FUNCTION)?"function name":( + (expect == EXPECT_VARIABLE)?"variable name":( + (expect == EXPECT_VALUE ?"value" : "unknown"))), + asm_instr[i].o + ); /* * Parse the operands for `i` (the instruction). The order * of asm_instr is in the order of the menomic encoding so @@ -485,26 +531,44 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state *c = '\0'; \ c = (char*)skip; \ } while (0) - - case 3: { - const char *data; OPFILL(data); - printf("OP3: %s\n", data); - s.o3.s1 = 0; - } - case 2: { - const char *data; OPFILL(data); - printf("OP2: %s\n", data); - s.o2.s1 = 0; - } + #define OPEATS(X,Y) X##Y + #define OPCCAT(X,Y) OPEATS(X,Y) + #define OPLOAD(X,Y) \ + do { \ + util_debug("ASM", "loading operand data ...\n"); \ + if (expect == EXPECT_VARIABLE) { \ + size_t f=0; \ + for (; f= 0) { util_debug("GEN", " CODE:\n"); for (;;) { - if (code_statements_data[j].opcode != INSTR_DONE && - code_statements_data[j].opcode != INSTR_RETURN) - util_debug("GEN", " %s {0x%05d,0x%05d,0x%05d}\n", + if (code_statements_data[j].opcode != AINSTR_END) + util_debug("GEN", " %s {0x%05x,0x%05x,0x%05x}\n", asm_instr[code_statements_data[j].opcode].m, code_statements_data[j].o1.s1, code_statements_data[j].o2.s1, code_statements_data[j].o3.s1 ); - else break; + else { + util_debug("GEN", " DONE {0x00000,0x00000,0x00000}\n"); + break; + } j++; } } diff --git a/data/test.qs b/data/test.qs index 0852b50..f3f0506 100644 --- a/data/test.qs +++ b/data/test.qs @@ -89,13 +89,22 @@ FUNCTION: checkextension, $99 ;code_chars_put("m_toggle", 0x8); ;code_chars_put("m_shutdown", 0xA); -FUNCTION: m_init #3VVV - DONE -FUNCTION: m_keydown #1S - DONE -FUNCTION: m_draw #1S - DONE -FUNCTION: m_toggle #1S - DONE -FUNCTION: m_shutdown #1S +FUNCTION: m_init #0 + CALL0 dprint +END +FUNCTION: m_keydown #0 + CALL0 dprint +END + +FUNCTION: m_draw #3VVV + CALL0 dprint +END + +FUNCTION: m_toggle #1S + CALL0 dprint +END + +FUNCTION: m_shutdown #1S + CALL0 dprint +END diff --git a/gmqcc.h b/gmqcc.h index 032566a..f8bb93e 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -492,7 +492,15 @@ enum { INSTR_BITAND, INSTR_BITOR, - /* Virtual instructions used by the IR + /* + * Virtual instructions used by the assembler + * keep at the end but before virtual instructions + * for the IR below. + */ + AINSTR_END, + + /* + * Virtual instructions used by the IR * Keep at the end! */ VINSTR_PHI, @@ -585,21 +593,22 @@ static const struct { { "NOT_FNC" , 0, 7 }, { "IF" , 0, 2 }, { "IFNOT" , 0, 5 }, - { "CALL0" , 0, 5 }, - { "CALL1" , 0, 5 }, - { "CALL2" , 0, 5 }, - { "CALL3" , 0, 5 }, - { "CALL4" , 0, 5 }, - { "CALL5" , 0, 5 }, - { "CALL6" , 0, 5 }, - { "CALL7" , 0, 5 }, - { "CALL8" , 0, 5 }, + { "CALL0" , 1, 5 }, + { "CALL1" , 2, 5 }, + { "CALL2" , 3, 5 }, + { "CALL3" , 4, 5 }, + { "CALL4" , 5, 5 }, + { "CALL5" , 6, 5 }, + { "CALL6" , 7, 5 }, + { "CALL7" , 8, 5 }, + { "CALL8" , 9, 5 }, { "STATE" , 0, 5 }, { "GOTO" , 0, 4 }, { "AND" , 0, 3 }, { "OR" , 0, 2 }, { "BITAND" , 0, 6 }, - { "BITOR" , 0, 5 } + { "BITOR" , 0, 5 }, + { "END" , 0, 3 } /* virtual assembler instruction */ }; void asm_init (const char *, FILE **); diff --git a/util.c b/util.c index 7735a52..123974c 100644 --- a/util.c +++ b/util.c @@ -137,39 +137,6 @@ char *util_strchp(const char *s, const char *e) { return util_strdup(s); } -/* - * Remove newline from a string (if it exists). This is - * done pointer wise instead of strlen(), and an array - * access. - */ -char *util_strrnl(const char *src) { - char *cpy = NULL; - - if (src) { - cpy = (char*)src; - while (*cpy && *cpy != '\n') - cpy++; - - *cpy = '\0'; - } - return (char*)src; -} - -/* - * Removes any whitespace prefixed on a string by moving - * skipping past it, and stroing the skip distance, so - * the string can later be freed (if it was allocated) - */ -char *util_strsws(const char *skip) { - size_t size = 0; - if (!skip) - return NULL; - - while (*skip == ' ' || *skip == '\t') - skip++,size++; - return util_strdup(skip-size); -} - /* * Returns true if string is all uppercase, otherwise * it returns false.