const size_t o; /* operands */
const size_t l; /* menomic len */
} const asm_instr[] = {
- [INSTR_DONE] = { "DONE" , 0, 4 },
- [INSTR_MUL_F] = { "MUL_F" , 0, 5 },
- [INSTR_MUL_V] = { "MUL_V" , 0, 5 },
- [INSTR_MUL_FV] = { "MUL_FV" , 0, 6 },
- [INSTR_MUL_VF] = { "MUL_VF" , 0, 6 },
+ [INSTR_DONE] = { "DONE" , 1, 4 },
+ [INSTR_MUL_F] = { "MUL_F" , 3, 5 },
+ [INSTR_MUL_V] = { "MUL_V" , 3, 5 },
+ [INSTR_MUL_FV] = { "MUL_FV" , 3, 6 },
+ [INSTR_MUL_VF] = { "MUL_VF" , 3, 6 },
[INSTR_DIV_F] = { "DIV" , 0, 3 },
- [INSTR_ADD_F] = { "ADD_F" , 0, 5 },
- [INSTR_ADD_V] = { "ADD_V" , 0, 5 },
- [INSTR_SUB_F] = { "SUB_F" , 0, 5 },
- [INSTR_SUB_V] = { "DUB_V" , 0, 5 },
+ [INSTR_ADD_F] = { "ADD_F" , 3, 5 },
+ [INSTR_ADD_V] = { "ADD_V" , 3, 5 },
+ [INSTR_SUB_F] = { "SUB_F" , 3, 5 },
+ [INSTR_SUB_V] = { "DUB_V" , 3, 5 },
[INSTR_EQ_F] = { "EQ_F" , 0, 4 },
[INSTR_EQ_V] = { "EQ_V" , 0, 4 },
[INSTR_EQ_S] = { "EQ_S" , 0, 4 },
static char *const asm_getline(size_t *byte, FILE *fp) {
char *line = NULL;
- ssize_t read = getline(&line, byte, fp);
+ ssize_t read = util_getline(&line, byte, fp);
*byte = read;
if (read == -1) {
- free (line);
+ mem_d (line);
return NULL;
}
return line;
fclose(fp);
code_write();
}
+
+/*
+ * Following parse states:
+ * ASM_FUNCTION -- in a function accepting input statements
+ * ....
+ */
+typedef enum {
+ ASM_NULL,
+ ASM_FUNCTION
+} asm_state;
+
+typedef struct {
+ char *name; /* name of constant */
+ int offset; /* location in globals */
+} globals;
+VECTOR_MAKE(globals, assembly_constants);
void asm_parse(FILE *fp) {
- char *data = NULL;
- char *skip = NULL;
- long line = 1; /* current line */
- size_t size = 0; /* size of line */
+ char *data = NULL;
+ char *skip = NULL;
+ long line = 1; /* current line */
+ size_t size = 0; /* size of line */
+ asm_state state = ASM_NULL;
while ((data = asm_getline(&size, fp)) != NULL) {
skip = data;
(void)offset_functions; \
(void)offset_fields; \
(void)offset_defs; \
+ assembly_constants_add((globals){ \
+ .name = util_strdup(skip), \
+ .offset = offset_globals \
+ }); \
} \
goto end; \
}
.offset = offset_globals, /* offset to offset in string table (for data)*/
.name = offset_chars /* location of name in string table (for name)*/
});
+ code_strings_add('h');
});
/* FUNCTION */
DECLTYPE(asm_keys[5], {
/* TODO: parse */
+ if (state != ASM_NULL) {
+ printf("%li: Error unfinished function block, expected DONE or RETURN\n", line);
+ goto end;
+ }
+
+ state = ASM_FUNCTION;
code_defs_add((prog_section_def){
.type = TYPE_VOID,
.offset = offset_globals,
/* if we make it this far then we have statements */
{
- size_t i = 0;
+ size_t i = 0; /* counter */
+ size_t o = 0; /* operands */
+ char *t = NULL; /* token */
+
+ /*
+ * Most ops a single statement can have is three.
+ * lets allocate some space for all of those here.
+ */
+ char op[3][32768] = {{0},{0},{0}};
for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
- /* TODO */
+ if (state != ASM_FUNCTION) {
+ printf("%li: Statement not inside function block\n", line);
+ goto end;
+ }
+
+ /* update parser state */
+ if (i == INSTR_DONE || i == INSTR_RETURN) {
+ goto end;
+ state = ASM_NULL;
+ }
+
+ /* parse the statement */
+ o = asm_instr[i].o; /* operands */
+ skip += asm_instr[i].l; /* skip instruction */
+ t = strtok(skip, " ,");
+ i = 0;
+ while (t != NULL && i < 3) {
+ strcpy(op[i], t);
+ t = strtok(NULL, " ,");
+ i ++;
+ }
+
+ util_debug("ASM", "Operand 1: %s\n", util_strrnl(op[0]));
+ util_debug("ASM", "Operand 2: %s\n", util_strrnl(op[1]));
+ util_debug("ASM", "Operand 3: %s\n", util_strrnl(op[2]));
+
+ /* check */
+ if (i != o) {
+ printf("not enough operands, expected: %li, got %li\n", o, i);
+ }
+
+ /* TODO: hashtable value LOAD .... etc */
+ code_statements_add((prog_section_statement){
+ i, {0}, {0}, {0}
+ });
goto end;
}
}
}
/* if we made it this far something is wrong */
- printf("ERROR");
+ if (*skip != '\0')
+ printf("%li: Invalid statement, expression, or decleration\n", line);
end:
- free(data);
+ //free(data);
+ mem_d(data);
+ line ++;
}
}
fwrite(code_globals_data, 1, sizeof(int) *code_globals_elements, fp);
fwrite(code_strings_data, 1, 1 *code_strings_elements, fp);
- free(code_statements_data);
- free(code_defs_data);
- free(code_fields_data);
- free(code_functions_data);
- free(code_globals_data);
- free(code_strings_data);
+ mem_d(code_statements_data);
+ mem_d(code_defs_data);
+ mem_d(code_fields_data);
+ mem_d(code_functions_data);
+ mem_d(code_globals_data);
+ mem_d(code_strings_data);
- util_debug("CODE","wrote program.dat\n\
+ util_debug("GEN","wrote program.dat:\n\
version: = %d\n\
crc16: = %d\n\
- statements {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- defs {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- fields {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- functions {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- globals {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- strings {\n\
- .offset = %d\n\
- .length = %d\n\
- }\n\
- entfield: = %d\n",
+ entfield: = %d\n\
+ statements {.offset = % 8d, .length = % 8d}\n\
+ defs {.offset = % 8d, .length = % 8d}\n\
+ fields {.offset = % 8d, .length = % 8d}\n\
+ functions {.offset = % 8d, .length = % 8d}\n\
+ globals {.offset = % 8d, .length = % 8d}\n\
+ strings {.offset = % 8d, .length = % 8d}\n",
code_header.version,
code_header.crc16,
+ code_header.entfield,
code_header.statements.offset,
code_header.statements.length,
code_header.defs.offset,
code_header.strings.offset,
code_header.strings.length,
code_header.globals.offset,
- code_header.globals.length,
- code_header.entfield
+ code_header.globals.length
);
fclose(fp);
* SOFTWARE.
*/
#include <stdarg.h>
+#include <errno.h>
#include "gmqcc.h"
struct memblock_t {
}
/*
- * Removed quotes from a string, escapes from \ in string
+ * Remove quotes from a string, escapes from \ in string
* as well. This function shouldn't be used to create a
* char array that is later freed (it uses pointer arith)
*/
return dst;
}
+/*
+ * Remove newline from a string (if it exists). This is
+ * done pointer wise instead of strlen(), and an array
+ * access.
+ */
+char *util_strrnl(char *s) {
+ char *cpy = s;
+ while (cpy && *cpy && *cpy != '\n')
+ cpy++;
+
+ *cpy = '\0';
+ return s;
+}
+
void util_debug(const char *area, const char *ms, ...) {
va_list va;
va_start(va, ms);
vfprintf(stdout, ms, va);
va_end (va);
}
+
+/*
+ * Implements libc getline for systems that don't have it, which is
+ * assmed all. This works the same as getline().
+ */
+int util_getline(char **lineptr, size_t *n, FILE *stream) {
+ int chr;
+ int ret;
+ char *pos;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+ if (!*lineptr) {
+ if (!(*lineptr = mem_a((*n = 64))))
+ return -1;
+ }
+
+ chr = *n;
+ pos = *lineptr;
+
+ for (;;) {
+ int c = getc(stream);
+
+ if (chr < 2) {
+ char *tmp = mem_a((*n+=(*n>16)?*n:64));
+ if (!tmp)
+ return -1;
+
+ chr = *n + *lineptr - pos;
+ strcpy(tmp,*lineptr);
+
+ if (!(*lineptr = tmp))
+ return -1;
+
+ pos = *n - chr + *lineptr;
+ }
+
+ if (ferror(stream))
+ return -1;
+ if (c == EOF) {
+ if (pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *pos++ = c;
+ chr--;
+ if (c == '\n')
+ break;
+ }
+ *pos = '\0';
+ return (ret = pos - *lineptr);
+}