mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-31 03:50:36 +00:00
tabulators->four spaces
This commit is contained in:
parent
9031c57e39
commit
477e80f1fb
9 changed files with 1264 additions and 1264 deletions
528
assembler.c
528
assembler.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -27,76 +27,76 @@
|
|||
* and also I plan to allow inline assembly for the compiler.
|
||||
*/
|
||||
static const struct {
|
||||
const char *m; /* menomic */
|
||||
const size_t o; /* operands */
|
||||
const size_t l; /* menomic len */
|
||||
const char *m; /* menomic */
|
||||
const size_t o; /* operands */
|
||||
const size_t l; /* menomic len */
|
||||
} const asm_instr[] = {
|
||||
[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" , 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 },
|
||||
[INSTR_EQ_E] = { "EQ_E" , 0, 4 },
|
||||
[INSTR_EQ_FNC] = { "ES_FNC" , 0, 6 },
|
||||
[INSTR_NE_F] = { "NE_F" , 0, 4 },
|
||||
[INSTR_NE_V] = { "NE_V" , 0, 4 },
|
||||
[INSTR_NE_S] = { "NE_S" , 0, 4 },
|
||||
[INSTR_NE_E] = { "NE_E" , 0, 4 },
|
||||
[INSTR_NE_FNC] = { "NE_FNC" , 0, 6 },
|
||||
[INSTR_LE] = { "LE" , 0, 2 },
|
||||
[INSTR_GE] = { "GE" , 0, 2 },
|
||||
[INSTR_LT] = { "LT" , 0, 2 },
|
||||
[INSTR_GT] = { "GT" , 0, 2 },
|
||||
[INSTR_LOAD_F] = { "FIELD_F" , 0, 7 },
|
||||
[INSTR_LOAD_V] = { "FIELD_V" , 0, 7 },
|
||||
[INSTR_LOAD_S] = { "FIELD_S" , 0, 7 },
|
||||
[INSTR_LOAD_ENT] = { "FIELD_ENT" , 0, 9 },
|
||||
[INSTR_LOAD_FLD] = { "FIELD_FLD" , 0, 9 },
|
||||
[INSTR_LOAD_FNC] = { "FIELD_FNC" , 0, 9 },
|
||||
[INSTR_ADDRESS] = { "ADDRESS" , 0, 7 },
|
||||
[INSTR_STORE_F] = { "STORE_F" , 0, 7 },
|
||||
[INSTR_STORE_V] = { "STORE_V" , 0, 7 },
|
||||
[INSTR_STORE_S] = { "STORE_S" , 0, 7 },
|
||||
[INSTR_STORE_ENT] = { "STORE_ENT" , 0, 9 },
|
||||
[INSTR_STORE_FLD] = { "STORE_FLD" , 0, 9 },
|
||||
[INSTR_STORE_FNC] = { "STORE_FNC" , 0, 9 },
|
||||
[INSTR_STOREP_F] = { "STOREP_F" , 0, 8 },
|
||||
[INSTR_STOREP_V] = { "STOREP_V" , 0, 8 },
|
||||
[INSTR_STOREP_S] = { "STOREP_S" , 0, 8 },
|
||||
[INSTR_STOREP_ENT] = { "STOREP_ENT", 0, 10},
|
||||
[INSTR_STOREP_FLD] = { "STOREP_FLD", 0, 10},
|
||||
[INSTR_STOREP_FNC] = { "STOREP_FNC", 0, 10},
|
||||
[INSTR_RETURN] = { "RETURN" , 0, 6 },
|
||||
[INSTR_NOT_F] = { "NOT_F" , 0, 5 },
|
||||
[INSTR_NOT_V] = { "NOT_V" , 0, 5 },
|
||||
[INSTR_NOT_S] = { "NOT_S" , 0, 5 },
|
||||
[INSTR_NOT_ENT] = { "NOT_ENT" , 0, 7 },
|
||||
[INSTR_NOT_FNC] = { "NOT_FNC" , 0, 7 },
|
||||
[INSTR_IF] = { "IF" , 0, 2 },
|
||||
[INSTR_IFNOT] = { "IFNOT" , 0, 5 },
|
||||
[INSTR_CALL0] = { "CALL0" , 0, 5 },
|
||||
[INSTR_CALL1] = { "CALL1" , 0, 5 },
|
||||
[INSTR_CALL2] = { "CALL2" , 0, 5 },
|
||||
[INSTR_CALL3] = { "CALL3" , 0, 5 },
|
||||
[INSTR_CALL4] = { "CALL4" , 0, 5 },
|
||||
[INSTR_CALL5] = { "CALL5" , 0, 5 },
|
||||
[INSTR_CALL6] = { "CALL6" , 0, 5 },
|
||||
[INSTR_CALL7] = { "CALL7" , 0, 5 },
|
||||
[INSTR_CALL8] = { "CALL8" , 0, 5 },
|
||||
[INSTR_STATE] = { "STATE" , 0, 5 },
|
||||
[INSTR_GOTO] = { "GOTO" , 0, 4 },
|
||||
[INSTR_AND] = { "AND" , 0, 3 },
|
||||
[INSTR_OR] = { "OR" , 0, 2 },
|
||||
[INSTR_BITAND] = { "BITAND" , 0, 6 },
|
||||
[INSTR_BITOR] = { "BITOR" , 0, 5 }
|
||||
[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" , 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 },
|
||||
[INSTR_EQ_E] = { "EQ_E" , 0, 4 },
|
||||
[INSTR_EQ_FNC] = { "ES_FNC" , 0, 6 },
|
||||
[INSTR_NE_F] = { "NE_F" , 0, 4 },
|
||||
[INSTR_NE_V] = { "NE_V" , 0, 4 },
|
||||
[INSTR_NE_S] = { "NE_S" , 0, 4 },
|
||||
[INSTR_NE_E] = { "NE_E" , 0, 4 },
|
||||
[INSTR_NE_FNC] = { "NE_FNC" , 0, 6 },
|
||||
[INSTR_LE] = { "LE" , 0, 2 },
|
||||
[INSTR_GE] = { "GE" , 0, 2 },
|
||||
[INSTR_LT] = { "LT" , 0, 2 },
|
||||
[INSTR_GT] = { "GT" , 0, 2 },
|
||||
[INSTR_LOAD_F] = { "FIELD_F" , 0, 7 },
|
||||
[INSTR_LOAD_V] = { "FIELD_V" , 0, 7 },
|
||||
[INSTR_LOAD_S] = { "FIELD_S" , 0, 7 },
|
||||
[INSTR_LOAD_ENT] = { "FIELD_ENT" , 0, 9 },
|
||||
[INSTR_LOAD_FLD] = { "FIELD_FLD" , 0, 9 },
|
||||
[INSTR_LOAD_FNC] = { "FIELD_FNC" , 0, 9 },
|
||||
[INSTR_ADDRESS] = { "ADDRESS" , 0, 7 },
|
||||
[INSTR_STORE_F] = { "STORE_F" , 0, 7 },
|
||||
[INSTR_STORE_V] = { "STORE_V" , 0, 7 },
|
||||
[INSTR_STORE_S] = { "STORE_S" , 0, 7 },
|
||||
[INSTR_STORE_ENT] = { "STORE_ENT" , 0, 9 },
|
||||
[INSTR_STORE_FLD] = { "STORE_FLD" , 0, 9 },
|
||||
[INSTR_STORE_FNC] = { "STORE_FNC" , 0, 9 },
|
||||
[INSTR_STOREP_F] = { "STOREP_F" , 0, 8 },
|
||||
[INSTR_STOREP_V] = { "STOREP_V" , 0, 8 },
|
||||
[INSTR_STOREP_S] = { "STOREP_S" , 0, 8 },
|
||||
[INSTR_STOREP_ENT] = { "STOREP_ENT", 0, 10},
|
||||
[INSTR_STOREP_FLD] = { "STOREP_FLD", 0, 10},
|
||||
[INSTR_STOREP_FNC] = { "STOREP_FNC", 0, 10},
|
||||
[INSTR_RETURN] = { "RETURN" , 0, 6 },
|
||||
[INSTR_NOT_F] = { "NOT_F" , 0, 5 },
|
||||
[INSTR_NOT_V] = { "NOT_V" , 0, 5 },
|
||||
[INSTR_NOT_S] = { "NOT_S" , 0, 5 },
|
||||
[INSTR_NOT_ENT] = { "NOT_ENT" , 0, 7 },
|
||||
[INSTR_NOT_FNC] = { "NOT_FNC" , 0, 7 },
|
||||
[INSTR_IF] = { "IF" , 0, 2 },
|
||||
[INSTR_IFNOT] = { "IFNOT" , 0, 5 },
|
||||
[INSTR_CALL0] = { "CALL0" , 0, 5 },
|
||||
[INSTR_CALL1] = { "CALL1" , 0, 5 },
|
||||
[INSTR_CALL2] = { "CALL2" , 0, 5 },
|
||||
[INSTR_CALL3] = { "CALL3" , 0, 5 },
|
||||
[INSTR_CALL4] = { "CALL4" , 0, 5 },
|
||||
[INSTR_CALL5] = { "CALL5" , 0, 5 },
|
||||
[INSTR_CALL6] = { "CALL6" , 0, 5 },
|
||||
[INSTR_CALL7] = { "CALL7" , 0, 5 },
|
||||
[INSTR_CALL8] = { "CALL8" , 0, 5 },
|
||||
[INSTR_STATE] = { "STATE" , 0, 5 },
|
||||
[INSTR_GOTO] = { "GOTO" , 0, 4 },
|
||||
[INSTR_AND] = { "AND" , 0, 3 },
|
||||
[INSTR_OR] = { "OR" , 0, 2 },
|
||||
[INSTR_BITAND] = { "BITAND" , 0, 6 },
|
||||
[INSTR_BITOR] = { "BITOR" , 0, 5 }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -104,23 +104,23 @@ static const struct {
|
|||
* for creating functions, or constants.
|
||||
*/
|
||||
const char *const asm_keys[] = {
|
||||
"FLOAT" , /* define float */
|
||||
"VECTOR" , /* define vector */
|
||||
"ENTITY" , /* define ent */
|
||||
"FIELD" , /* define field */
|
||||
"STRING" , /* define string */
|
||||
"FUNCTION"
|
||||
"FLOAT" , /* define float */
|
||||
"VECTOR" , /* define vector */
|
||||
"ENTITY" , /* define ent */
|
||||
"FIELD" , /* define field */
|
||||
"STRING" , /* define string */
|
||||
"FUNCTION"
|
||||
};
|
||||
|
||||
static char *const asm_getline(size_t *byte, FILE *fp) {
|
||||
char *line = NULL;
|
||||
ssize_t read = util_getline(&line, byte, fp);
|
||||
*byte = read;
|
||||
if (read == -1) {
|
||||
mem_d (line);
|
||||
return NULL;
|
||||
}
|
||||
return line;
|
||||
char *line = NULL;
|
||||
ssize_t read = util_getline(&line, byte, fp);
|
||||
*byte = read;
|
||||
if (read == -1) {
|
||||
mem_d (line);
|
||||
return NULL;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
#define asm_rmnewline(L,S) *((L)+*(S)-1) = '\0'
|
||||
|
@ -130,199 +130,199 @@ static char *const asm_getline(size_t *byte, FILE *fp) {
|
|||
}
|
||||
|
||||
void asm_init(const char *file, FILE **fp) {
|
||||
*fp = fopen(file, "r");
|
||||
code_init();
|
||||
*fp = fopen(file, "r");
|
||||
code_init();
|
||||
}
|
||||
|
||||
void asm_close(FILE *fp) {
|
||||
fclose(fp);
|
||||
code_write();
|
||||
fclose(fp);
|
||||
code_write();
|
||||
}
|
||||
|
||||
/*
|
||||
* Following parse states:
|
||||
* ASM_FUNCTION -- in a function accepting input statements
|
||||
* ....
|
||||
* ASM_FUNCTION -- in a function accepting input statements
|
||||
* ....
|
||||
*/
|
||||
typedef enum {
|
||||
ASM_NULL,
|
||||
ASM_FUNCTION
|
||||
ASM_NULL,
|
||||
ASM_FUNCTION
|
||||
} asm_state;
|
||||
|
||||
typedef struct {
|
||||
char *name; /* name of constant */
|
||||
int offset; /* location in globals */
|
||||
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 */
|
||||
asm_state state = ASM_NULL;
|
||||
|
||||
while ((data = asm_getline(&size, fp)) != NULL) {
|
||||
skip = data;
|
||||
asm_skipwhite(skip);
|
||||
asm_rmnewline(skip, &size);
|
||||
|
||||
#define DECLTYPE(X, CODE) \
|
||||
if (!strncmp(X, skip, strlen(X))) { \
|
||||
if (skip[strlen(X)] != ':') { \
|
||||
printf("%li: Missing `:` after decltype\n",line); \
|
||||
exit (1); \
|
||||
} \
|
||||
skip += strlen(X)+1; \
|
||||
asm_skipwhite(skip); \
|
||||
if(!isalpha(*skip)) { \
|
||||
printf("%li: Invalid identififer: %s\n", line, skip); \
|
||||
exit (1); \
|
||||
} else { \
|
||||
size_t offset_code = code_statements_elements+1; \
|
||||
size_t offset_chars = code_strings_elements +1; \
|
||||
size_t offset_globals = code_globals_elements +1; \
|
||||
size_t offset_functions = code_functions_elements +1; \
|
||||
size_t offset_fields = code_fields_elements +1; \
|
||||
size_t offset_defs = code_defs_elements +1; \
|
||||
CODE \
|
||||
/* silent unused warnings */ \
|
||||
(void)offset_code; \
|
||||
(void)offset_chars; \
|
||||
(void)offset_globals; \
|
||||
(void)offset_functions; \
|
||||
(void)offset_fields; \
|
||||
(void)offset_defs; \
|
||||
assembly_constants_add((globals){ \
|
||||
.name = util_strdup(skip), \
|
||||
.offset = offset_globals \
|
||||
}); \
|
||||
} \
|
||||
goto end; \
|
||||
}
|
||||
|
||||
/* FLOAT */
|
||||
DECLTYPE(asm_keys[0], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_FLOAT,
|
||||
.offset = offset_globals, /* global table */
|
||||
.name = offset_chars /* string table TODO */
|
||||
});
|
||||
float f = 0; /*TODO*/
|
||||
code_globals_add(*(int*)&f);
|
||||
|
||||
});
|
||||
DECLTYPE(asm_keys[1], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_FLOAT,
|
||||
.offset = offset_globals, /* global table */
|
||||
.name = offset_chars /* string table TODO */
|
||||
});
|
||||
float f1 = 0;
|
||||
float f2 = 0;
|
||||
float f3 = 0;
|
||||
code_globals_add(*(int*)&f1);
|
||||
code_globals_add(*(int*)&f2);
|
||||
code_globals_add(*(int*)&f3);
|
||||
});
|
||||
/* ENTITY */ DECLTYPE(asm_keys[2], {});
|
||||
/* FIELD */ DECLTYPE(asm_keys[3], {});
|
||||
/* STRING */
|
||||
DECLTYPE(asm_keys[4], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_STRING,
|
||||
.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,
|
||||
.name = offset_chars
|
||||
});
|
||||
code_globals_add(offset_functions);
|
||||
code_functions_add((prog_section_function){
|
||||
.entry = offset_code,
|
||||
.firstlocal = 0,
|
||||
.locals = 0,
|
||||
.profile = 0,
|
||||
.name = offset_chars,
|
||||
.file = 0,
|
||||
.nargs = 0,
|
||||
.argsize = {0}
|
||||
});
|
||||
});
|
||||
|
||||
/* if we make it this far then we have statements */
|
||||
{
|
||||
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)) {
|
||||
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 */
|
||||
if (*skip != '\0')
|
||||
printf("%li: Invalid statement, expression, or decleration\n", line);
|
||||
|
||||
end:
|
||||
//free(data);
|
||||
mem_d(data);
|
||||
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;
|
||||
asm_skipwhite(skip);
|
||||
asm_rmnewline(skip, &size);
|
||||
|
||||
#define DECLTYPE(X, CODE) \
|
||||
if (!strncmp(X, skip, strlen(X))) { \
|
||||
if (skip[strlen(X)] != ':') { \
|
||||
printf("%li: Missing `:` after decltype\n",line); \
|
||||
exit (1); \
|
||||
} \
|
||||
skip += strlen(X)+1; \
|
||||
asm_skipwhite(skip); \
|
||||
if(!isalpha(*skip)) { \
|
||||
printf("%li: Invalid identififer: %s\n", line, skip); \
|
||||
exit (1); \
|
||||
} else { \
|
||||
size_t offset_code = code_statements_elements+1; \
|
||||
size_t offset_chars = code_strings_elements +1; \
|
||||
size_t offset_globals = code_globals_elements +1; \
|
||||
size_t offset_functions = code_functions_elements +1; \
|
||||
size_t offset_fields = code_fields_elements +1; \
|
||||
size_t offset_defs = code_defs_elements +1; \
|
||||
CODE \
|
||||
/* silent unused warnings */ \
|
||||
(void)offset_code; \
|
||||
(void)offset_chars; \
|
||||
(void)offset_globals; \
|
||||
(void)offset_functions; \
|
||||
(void)offset_fields; \
|
||||
(void)offset_defs; \
|
||||
assembly_constants_add((globals){ \
|
||||
.name = util_strdup(skip), \
|
||||
.offset = offset_globals \
|
||||
}); \
|
||||
} \
|
||||
goto end; \
|
||||
}
|
||||
|
||||
/* FLOAT */
|
||||
DECLTYPE(asm_keys[0], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_FLOAT,
|
||||
.offset = offset_globals, /* global table */
|
||||
.name = offset_chars /* string table TODO */
|
||||
});
|
||||
float f = 0; /*TODO*/
|
||||
code_globals_add(*(int*)&f);
|
||||
|
||||
});
|
||||
DECLTYPE(asm_keys[1], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_FLOAT,
|
||||
.offset = offset_globals, /* global table */
|
||||
.name = offset_chars /* string table TODO */
|
||||
});
|
||||
float f1 = 0;
|
||||
float f2 = 0;
|
||||
float f3 = 0;
|
||||
code_globals_add(*(int*)&f1);
|
||||
code_globals_add(*(int*)&f2);
|
||||
code_globals_add(*(int*)&f3);
|
||||
});
|
||||
/* ENTITY */ DECLTYPE(asm_keys[2], {});
|
||||
/* FIELD */ DECLTYPE(asm_keys[3], {});
|
||||
/* STRING */
|
||||
DECLTYPE(asm_keys[4], {
|
||||
code_defs_add((prog_section_def){
|
||||
.type = TYPE_STRING,
|
||||
.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,
|
||||
.name = offset_chars
|
||||
});
|
||||
code_globals_add(offset_functions);
|
||||
code_functions_add((prog_section_function){
|
||||
.entry = offset_code,
|
||||
.firstlocal = 0,
|
||||
.locals = 0,
|
||||
.profile = 0,
|
||||
.name = offset_chars,
|
||||
.file = 0,
|
||||
.nargs = 0,
|
||||
.argsize = {0}
|
||||
});
|
||||
});
|
||||
|
||||
/* if we make it this far then we have statements */
|
||||
{
|
||||
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)) {
|
||||
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 */
|
||||
if (*skip != '\0')
|
||||
printf("%li: Invalid statement, expression, or decleration\n", line);
|
||||
|
||||
end:
|
||||
//free(data);
|
||||
mem_d(data);
|
||||
line ++;
|
||||
}
|
||||
}
|
||||
|
|
218
code.c
218
code.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -23,20 +23,20 @@
|
|||
#include "gmqcc.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset; /* Offset in file of where data begins */
|
||||
uint32_t length; /* Length of section (how many of) */
|
||||
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 defs; /* prog_section_def */
|
||||
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 */
|
||||
uint32_t version; /* Program version (6) */
|
||||
uint32_t crc16; /* What is this? */
|
||||
prog_section statements; /* prog_section_statement */
|
||||
prog_section defs; /* prog_section_def */
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -81,91 +81,91 @@ VECTOR_MAKE(int, code_globals );
|
|||
VECTOR_MAKE(char, code_strings );
|
||||
|
||||
void code_init() {
|
||||
/*
|
||||
* The way progs.dat is suppose to work is odd, there needs to be
|
||||
* some null (empty) statements, functions, and 28 globals
|
||||
*/
|
||||
prog_section_function empty_function = {0,0,0,0,0,0,0,{0}};
|
||||
prog_section_statement empty_statement = {0,{0},{0},{0}};
|
||||
int i;
|
||||
for(i = 0; i < 28; i++)
|
||||
code_globals_add(0);
|
||||
|
||||
code_strings_add ('\0');
|
||||
code_functions_add (empty_function);
|
||||
code_statements_add(empty_statement);
|
||||
/*
|
||||
* The way progs.dat is suppose to work is odd, there needs to be
|
||||
* some null (empty) statements, functions, and 28 globals
|
||||
*/
|
||||
prog_section_function empty_function = {0,0,0,0,0,0,0,{0}};
|
||||
prog_section_statement empty_statement = {0,{0},{0},{0}};
|
||||
int i;
|
||||
for(i = 0; i < 28; i++)
|
||||
code_globals_add(0);
|
||||
|
||||
code_strings_add ('\0');
|
||||
code_functions_add (empty_function);
|
||||
code_statements_add(empty_statement);
|
||||
}
|
||||
|
||||
void code_test() {
|
||||
const char *X;
|
||||
size_t size = sizeof(X);
|
||||
size_t iter = 0;
|
||||
|
||||
#define FOO(Y) \
|
||||
X = Y; \
|
||||
size = sizeof(Y); \
|
||||
for (iter=0; iter < size; iter++) { \
|
||||
code_strings_add(X[iter]); \
|
||||
}
|
||||
|
||||
FOO("m_init");
|
||||
FOO("print");
|
||||
FOO("hello world\n");
|
||||
FOO("m_keydown");
|
||||
FOO("m_draw");
|
||||
FOO("m_toggle");
|
||||
FOO("m_shutdown");
|
||||
|
||||
code_globals_add(1); /* m_init */
|
||||
code_globals_add(2); /* print */
|
||||
code_globals_add(14); /* hello world in string table */
|
||||
|
||||
/* now the defs */
|
||||
code_defs_add((prog_section_def){.type=TYPE_VOID, .offset=28/*globals[28]*/, .name=1 }); /* m_init */
|
||||
code_defs_add((prog_section_def){.type=TYPE_FUNCTION,.offset=29/*globals[29]*/, .name=8 }); /* print */
|
||||
code_defs_add((prog_section_def){.type=TYPE_STRING, .offset=30/*globals[30]*/, .name=14}); /*hello_world*/
|
||||
|
||||
code_functions_add((prog_section_function){1, 0, 0, 0, .name=1, 0, 0, {0}}); /* m_init */
|
||||
code_functions_add((prog_section_function){-4, 0, 0, 0, .name=8, 0, 0, {0}}); /* print */
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13, 0,0, {0}}); /* m_keydown */
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10, 0,0, {0}});
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10+7, 0,0, {0}});
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10+7+9, 0,0, {0}});
|
||||
|
||||
code_statements_add((prog_section_statement){INSTR_STORE_F, {30}/*30 is hello_world */, {OFS_PARM0}, {0}});
|
||||
code_statements_add((prog_section_statement){INSTR_CALL1, {29}/*29 is print */, {0}, {0}});
|
||||
code_statements_add((prog_section_statement){INSTR_RETURN, {0}, {0}, {0}});
|
||||
const char *X;
|
||||
size_t size = sizeof(X);
|
||||
size_t iter = 0;
|
||||
|
||||
#define FOO(Y) \
|
||||
X = Y; \
|
||||
size = sizeof(Y); \
|
||||
for (iter=0; iter < size; iter++) { \
|
||||
code_strings_add(X[iter]); \
|
||||
}
|
||||
|
||||
FOO("m_init");
|
||||
FOO("print");
|
||||
FOO("hello world\n");
|
||||
FOO("m_keydown");
|
||||
FOO("m_draw");
|
||||
FOO("m_toggle");
|
||||
FOO("m_shutdown");
|
||||
|
||||
code_globals_add(1); /* m_init */
|
||||
code_globals_add(2); /* print */
|
||||
code_globals_add(14); /* hello world in string table */
|
||||
|
||||
/* now the defs */
|
||||
code_defs_add((prog_section_def){.type=TYPE_VOID, .offset=28/*globals[28]*/, .name=1 }); /* m_init */
|
||||
code_defs_add((prog_section_def){.type=TYPE_FUNCTION,.offset=29/*globals[29]*/, .name=8 }); /* print */
|
||||
code_defs_add((prog_section_def){.type=TYPE_STRING, .offset=30/*globals[30]*/, .name=14}); /*hello_world*/
|
||||
|
||||
code_functions_add((prog_section_function){1, 0, 0, 0, .name=1, 0, 0, {0}}); /* m_init */
|
||||
code_functions_add((prog_section_function){-4, 0, 0, 0, .name=8, 0, 0, {0}}); /* print */
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13, 0,0, {0}}); /* m_keydown */
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10, 0,0, {0}});
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10+7, 0,0, {0}});
|
||||
code_functions_add((prog_section_function){0, 0, 0, 0, .name=14+13+10+7+9, 0,0, {0}});
|
||||
|
||||
code_statements_add((prog_section_statement){INSTR_STORE_F, {30}/*30 is hello_world */, {OFS_PARM0}, {0}});
|
||||
code_statements_add((prog_section_statement){INSTR_CALL1, {29}/*29 is print */, {0}, {0}});
|
||||
code_statements_add((prog_section_statement){INSTR_RETURN, {0}, {0}, {0}});
|
||||
}
|
||||
|
||||
void code_write() {
|
||||
prog_header code_header={0};
|
||||
code_header.version = 6;
|
||||
code_header.crc16 = 0; /* TODO: */
|
||||
code_header.statements = (prog_section){sizeof(prog_header), code_statements_elements };
|
||||
code_header.defs = (prog_section){code_header.statements.offset + sizeof(prog_section_statement)*code_statements_elements, code_defs_elements };
|
||||
code_header.fields = (prog_section){code_header.defs.offset + sizeof(prog_section_def) *code_defs_elements, code_fields_elements };
|
||||
code_header.functions = (prog_section){code_header.fields.offset + sizeof(prog_section_field) *code_fields_elements, code_functions_elements };
|
||||
code_header.globals = (prog_section){code_header.functions.offset + sizeof(prog_section_function) *code_functions_elements, code_globals_elements };
|
||||
code_header.strings = (prog_section){code_header.globals.offset + sizeof(int) *code_globals_elements, code_strings_elements };
|
||||
code_header.entfield = 0; /* TODO: */
|
||||
|
||||
FILE *fp = fopen("program.dat", "wb");
|
||||
fwrite(&code_header, 1, sizeof(prog_header), fp);
|
||||
fwrite(code_statements_data, 1, sizeof(prog_section_statement)*code_statements_elements, fp);
|
||||
fwrite(code_defs_data, 1, sizeof(prog_section_def) *code_defs_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(int) *code_globals_elements, fp);
|
||||
fwrite(code_strings_data, 1, 1 *code_strings_elements, fp);
|
||||
|
||||
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("GEN","wrote program.dat:\n\
|
||||
prog_header code_header={0};
|
||||
code_header.version = 6;
|
||||
code_header.crc16 = 0; /* TODO: */
|
||||
code_header.statements = (prog_section){sizeof(prog_header), code_statements_elements };
|
||||
code_header.defs = (prog_section){code_header.statements.offset + sizeof(prog_section_statement)*code_statements_elements, code_defs_elements };
|
||||
code_header.fields = (prog_section){code_header.defs.offset + sizeof(prog_section_def) *code_defs_elements, code_fields_elements };
|
||||
code_header.functions = (prog_section){code_header.fields.offset + sizeof(prog_section_field) *code_fields_elements, code_functions_elements };
|
||||
code_header.globals = (prog_section){code_header.functions.offset + sizeof(prog_section_function) *code_functions_elements, code_globals_elements };
|
||||
code_header.strings = (prog_section){code_header.globals.offset + sizeof(int) *code_globals_elements, code_strings_elements };
|
||||
code_header.entfield = 0; /* TODO: */
|
||||
|
||||
FILE *fp = fopen("program.dat", "wb");
|
||||
fwrite(&code_header, 1, sizeof(prog_header), fp);
|
||||
fwrite(code_statements_data, 1, sizeof(prog_section_statement)*code_statements_elements, fp);
|
||||
fwrite(code_defs_data, 1, sizeof(prog_section_def) *code_defs_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(int) *code_globals_elements, fp);
|
||||
fwrite(code_strings_data, 1, 1 *code_strings_elements, fp);
|
||||
|
||||
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("GEN","wrote program.dat:\n\
|
||||
version: = %d\n\
|
||||
crc16: = %d\n\
|
||||
entfield: = %d\n\
|
||||
|
@ -175,22 +175,22 @@ void code_write() {
|
|||
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.defs.length,
|
||||
code_header.fields.offset,
|
||||
code_header.fields.length,
|
||||
code_header.functions.offset,
|
||||
code_header.functions.length,
|
||||
code_header.strings.offset,
|
||||
code_header.strings.length,
|
||||
code_header.globals.offset,
|
||||
code_header.globals.length
|
||||
);
|
||||
|
||||
fclose(fp);
|
||||
code_header.version,
|
||||
code_header.crc16,
|
||||
code_header.entfield,
|
||||
code_header.statements.offset,
|
||||
code_header.statements.length,
|
||||
code_header.defs.offset,
|
||||
code_header.defs.length,
|
||||
code_header.fields.offset,
|
||||
code_header.fields.length,
|
||||
code_header.functions.offset,
|
||||
code_header.functions.length,
|
||||
code_header.strings.offset,
|
||||
code_header.strings.length,
|
||||
code_header.globals.offset,
|
||||
code_header.globals.length
|
||||
);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
88
error.c
88
error.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -29,62 +29,62 @@
|
|||
* intereting like colors for the console.
|
||||
*/
|
||||
#ifndef WIN32
|
||||
# define CON_BLACK 30
|
||||
# define CON_RED 31
|
||||
# define CON_GREEN 32
|
||||
# define CON_BROWN 33
|
||||
# define CON_BLUE 34
|
||||
# define CON_MAGENTA 35
|
||||
# define CON_CYAN 36
|
||||
# define CON_WHITE 37
|
||||
# define CON_BLACK 30
|
||||
# define CON_RED 31
|
||||
# define CON_GREEN 32
|
||||
# define CON_BROWN 33
|
||||
# define CON_BLUE 34
|
||||
# define CON_MAGENTA 35
|
||||
# define CON_CYAN 36
|
||||
# define CON_WHITE 37
|
||||
static const int error_color[] = {
|
||||
CON_RED,
|
||||
CON_CYAN,
|
||||
CON_MAGENTA,
|
||||
CON_BLUE,
|
||||
CON_BROWN,
|
||||
CON_WHITE
|
||||
CON_RED,
|
||||
CON_CYAN,
|
||||
CON_MAGENTA,
|
||||
CON_BLUE,
|
||||
CON_BROWN,
|
||||
CON_WHITE
|
||||
};
|
||||
#endif
|
||||
int error_total = 0;
|
||||
int error_max = 10;
|
||||
|
||||
static const char *const error_list[] = {
|
||||
"Parsing Error:",
|
||||
"Lexing Error:",
|
||||
"Internal Error:",
|
||||
"Compilation Error:",
|
||||
"Preprocessor Error:"
|
||||
"Parsing Error:",
|
||||
"Lexing Error:",
|
||||
"Internal Error:",
|
||||
"Compilation Error:",
|
||||
"Preprocessor Error:"
|
||||
};
|
||||
|
||||
int error(struct lex_file *file, int status, const char *msg, ...) {
|
||||
char bu[1024*4]; /* enough? */
|
||||
char fu[1024*4]; /* enough? */
|
||||
va_list va;
|
||||
|
||||
if (error_total + 1 > error_max) {
|
||||
fprintf(stderr, "%d errors and more following, bailing\n", error_total);
|
||||
exit (-1);
|
||||
}
|
||||
error_total ++;
|
||||
char bu[1024*4]; /* enough? */
|
||||
char fu[1024*4]; /* enough? */
|
||||
va_list va;
|
||||
|
||||
if (error_total + 1 > error_max) {
|
||||
fprintf(stderr, "%d errors and more following, bailing\n", error_total);
|
||||
exit (-1);
|
||||
}
|
||||
error_total ++;
|
||||
/* color */
|
||||
# ifndef WIN32
|
||||
sprintf (bu, "\033[0;%dm%s \033[0;%dm %s:%d ", error_color[status-SHRT_MAX], error_list[status-SHRT_MAX], error_color[(status-1)-SHRT_MAX], file->name, file->line);
|
||||
# ifndef WIN32
|
||||
sprintf (bu, "\033[0;%dm%s \033[0;%dm %s:%d ", error_color[status-SHRT_MAX], error_list[status-SHRT_MAX], error_color[(status-1)-SHRT_MAX], file->name, file->line);
|
||||
#else
|
||||
sprintf (bu, "%s ", error_list[status-SHRT_MAX]);
|
||||
sprintf (bu, "%s ", error_list[status-SHRT_MAX]);
|
||||
#endif
|
||||
va_start (va, msg);
|
||||
vsprintf (fu, msg, va);
|
||||
va_end (va);
|
||||
fputs (bu, stderr);
|
||||
fputs (fu, stderr);
|
||||
va_start (va, msg);
|
||||
vsprintf (fu, msg, va);
|
||||
va_end (va);
|
||||
fputs (bu, stderr);
|
||||
fputs (fu, stderr);
|
||||
|
||||
/* color */
|
||||
# ifndef WIN32
|
||||
fputs ("\033[0m", stderr);
|
||||
# endif
|
||||
|
||||
fflush (stderr);
|
||||
|
||||
return status;
|
||||
# ifndef WIN32
|
||||
fputs ("\033[0m", stderr);
|
||||
# endif
|
||||
|
||||
fflush (stderr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
304
gmqcc.h
304
gmqcc.h
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -33,30 +33,30 @@
|
|||
* assume is all systems. (int8_t not required)
|
||||
*/
|
||||
#if CHAR_MIN == -128
|
||||
typedef unsigned char uint8_t; /* same as below */
|
||||
typedef unsigned char uint8_t; /* same as below */
|
||||
#elif SCHAR_MIN == -128
|
||||
typedef unsigned char uint8_t; /* same as above */
|
||||
typedef unsigned char uint8_t; /* same as above */
|
||||
#endif
|
||||
#if SHRT_MAX == 0x7FFF
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
#elif INT_MAX == 0x7FFF
|
||||
typedef int int16_t;
|
||||
typedef unsigned int uint16_t;
|
||||
typedef int int16_t;
|
||||
typedef unsigned int uint16_t;
|
||||
#endif
|
||||
#if INT_MAX == 0x7FFFFFFF
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#elif LONG_MAX == 0x7FFFFFFF
|
||||
typedef long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
typedef long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
#endif
|
||||
#ifdef _LP64 /* long pointer == 64 */
|
||||
typedef unsigned long uintptr_t;
|
||||
typedef long intptr_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
typedef long intptr_t;
|
||||
#else
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef int intptr_t;
|
||||
#endif
|
||||
/* Ensure type sizes are correct: */
|
||||
typedef char uint8_size_is_correct [sizeof(uint8_t) == 1?1:-1];
|
||||
|
@ -73,16 +73,16 @@ typedef char uintptr_size_is_correct[sizeof(uintptr_t)== sizeof(int*)?1:-1];
|
|||
//============================ lex.c ================================
|
||||
//===================================================================
|
||||
struct lex_file {
|
||||
FILE *file; /* file handler */
|
||||
char *name; /* name of file */
|
||||
char peek [5];
|
||||
char lastok[8192];
|
||||
|
||||
int last; /* last token */
|
||||
int current; /* current token */
|
||||
int length; /* bytes left to parse */
|
||||
int size; /* never changes (size of file) */
|
||||
int line; /* what line are we on? */
|
||||
FILE *file; /* file handler */
|
||||
char *name; /* name of file */
|
||||
char peek [5];
|
||||
char lastok[8192];
|
||||
|
||||
int last; /* last token */
|
||||
int current; /* current token */
|
||||
int length; /* bytes left to parse */
|
||||
int size; /* never changes (size of file) */
|
||||
int line; /* what line are we on? */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -144,7 +144,7 @@ int parse_gen(struct lex_file *);
|
|||
//========================== typedef.c ==============================
|
||||
//===================================================================
|
||||
typedef struct typedef_node_t {
|
||||
char *name;
|
||||
char *name;
|
||||
} typedef_node;
|
||||
|
||||
void typedef_init();
|
||||
|
@ -165,11 +165,11 @@ void util_debug (const char *, const char *, ...);
|
|||
int util_getline (char **, size_t *, FILE *);
|
||||
|
||||
#ifdef NOTRACK
|
||||
# define mem_a(x) malloc(x)
|
||||
# define mem_d(x) free (x)
|
||||
# define mem_a(x) malloc(x)
|
||||
# define mem_d(x) free (x)
|
||||
#else
|
||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) util_memory_d((x), __LINE__, __FILE__)
|
||||
# define mem_a(x) util_memory_a((x), __LINE__, __FILE__)
|
||||
# define mem_d(x) util_memory_d((x), __LINE__, __FILE__)
|
||||
#endif
|
||||
|
||||
#define VECTOR_MAKE(T,N) \
|
||||
|
@ -211,75 +211,75 @@ int util_getline (char **, size_t *, FILE *);
|
|||
* Each paramater incerements by 3 since vector types hold
|
||||
* 3 components (x,y,z).
|
||||
*/
|
||||
#define OFS_NULL 0
|
||||
#define OFS_RETURN 1
|
||||
#define OFS_PARM0 (OFS_RETURN+3)
|
||||
#define OFS_PARM1 (OFS_PARM0 +3)
|
||||
#define OFS_PARM2 (OFS_PARM1 +3)
|
||||
#define OFS_PARM3 (OFS_PARM2 +3)
|
||||
#define OFS_PARM4 (OFS_PARM3 +3)
|
||||
#define OFS_NULL 0
|
||||
#define OFS_RETURN 1
|
||||
#define OFS_PARM0 (OFS_RETURN+3)
|
||||
#define OFS_PARM1 (OFS_PARM0 +3)
|
||||
#define OFS_PARM2 (OFS_PARM1 +3)
|
||||
#define OFS_PARM3 (OFS_PARM2 +3)
|
||||
#define OFS_PARM4 (OFS_PARM3 +3)
|
||||
#define OFS_PARM5 (OFS_PARM4 +3)
|
||||
#define OFS_PARM6 (OFS_PARM5 +3)
|
||||
#define OFS_PARM7 (OFS_PARM6 +3)
|
||||
|
||||
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.
|
||||
*/
|
||||
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 types:
|
||||
* 0 = ev_void
|
||||
* 1 = ev_string
|
||||
* 2 = ev_float
|
||||
* 3 = ev_vector
|
||||
* 4 = ev_entity
|
||||
* 5 = ev_field
|
||||
* 6 = ev_function
|
||||
* 7 = ev_pointer -- engine only
|
||||
* 8 = ev_bad -- engine only
|
||||
*/
|
||||
uint16_t type;
|
||||
uint16_t offset;
|
||||
uint32_t name;
|
||||
/* The types:
|
||||
* 0 = ev_void
|
||||
* 1 = ev_string
|
||||
* 2 = ev_float
|
||||
* 3 = ev_vector
|
||||
* 4 = ev_entity
|
||||
* 5 = ev_field
|
||||
* 6 = ev_function
|
||||
* 7 = ev_pointer -- engine only
|
||||
* 8 = ev_bad -- engine only
|
||||
*/
|
||||
uint16_t type;
|
||||
uint16_t offset;
|
||||
uint32_t name;
|
||||
} prog_section_both;
|
||||
typedef prog_section_both prog_section_def;
|
||||
typedef prog_section_both prog_section_field;
|
||||
|
||||
typedef struct {
|
||||
int32_t entry; /* in statement table for instructions */
|
||||
uint32_t firstlocal; /* First local in local table */
|
||||
uint32_t locals; /* Total ints of params + locals */
|
||||
uint32_t profile; /* Always zero (engine uses this) */
|
||||
uint32_t name; /* name of function in string table */
|
||||
uint32_t file; /* file of the source file */
|
||||
uint32_t nargs; /* number of arguments */
|
||||
uint8_t argsize[8]; /* size of arguments (keep 8 always?) */
|
||||
int32_t entry; /* in statement table for instructions */
|
||||
uint32_t firstlocal; /* First local in local table */
|
||||
uint32_t locals; /* Total ints of params + locals */
|
||||
uint32_t profile; /* Always zero (engine uses this) */
|
||||
uint32_t name; /* name of function in string table */
|
||||
uint32_t file; /* file of the source file */
|
||||
uint32_t nargs; /* number of arguments */
|
||||
uint8_t argsize[8]; /* size of arguments (keep 8 always?) */
|
||||
} prog_section_function;
|
||||
|
||||
/*
|
||||
|
@ -288,72 +288,72 @@ typedef struct {
|
|||
* this is what things compile to (from the C code).
|
||||
*/
|
||||
enum {
|
||||
INSTR_DONE,
|
||||
INSTR_MUL_F,
|
||||
INSTR_MUL_V,
|
||||
INSTR_MUL_FV,
|
||||
INSTR_MUL_VF,
|
||||
INSTR_DIV_F,
|
||||
INSTR_ADD_F,
|
||||
INSTR_ADD_V,
|
||||
INSTR_SUB_F,
|
||||
INSTR_SUB_V,
|
||||
INSTR_EQ_F,
|
||||
INSTR_EQ_V,
|
||||
INSTR_EQ_S,
|
||||
INSTR_EQ_E,
|
||||
INSTR_EQ_FNC,
|
||||
INSTR_NE_F,
|
||||
INSTR_NE_V,
|
||||
INSTR_NE_S,
|
||||
INSTR_NE_E,
|
||||
INSTR_NE_FNC,
|
||||
INSTR_LE,
|
||||
INSTR_GE,
|
||||
INSTR_LT,
|
||||
INSTR_GT,
|
||||
INSTR_LOAD_F,
|
||||
INSTR_LOAD_V,
|
||||
INSTR_LOAD_S,
|
||||
INSTR_LOAD_ENT,
|
||||
INSTR_LOAD_FLD,
|
||||
INSTR_LOAD_FNC,
|
||||
INSTR_ADDRESS,
|
||||
INSTR_STORE_F,
|
||||
INSTR_STORE_V,
|
||||
INSTR_STORE_S,
|
||||
INSTR_STORE_ENT,
|
||||
INSTR_STORE_FLD,
|
||||
INSTR_STORE_FNC,
|
||||
INSTR_STOREP_F,
|
||||
INSTR_STOREP_V,
|
||||
INSTR_STOREP_S,
|
||||
INSTR_STOREP_ENT,
|
||||
INSTR_STOREP_FLD,
|
||||
INSTR_STOREP_FNC,
|
||||
INSTR_RETURN,
|
||||
INSTR_NOT_F,
|
||||
INSTR_NOT_V,
|
||||
INSTR_NOT_S,
|
||||
INSTR_NOT_ENT,
|
||||
INSTR_NOT_FNC,
|
||||
INSTR_IF,
|
||||
INSTR_IFNOT,
|
||||
INSTR_CALL0,
|
||||
INSTR_CALL1,
|
||||
INSTR_CALL2,
|
||||
INSTR_CALL3,
|
||||
INSTR_CALL4,
|
||||
INSTR_CALL5,
|
||||
INSTR_CALL6,
|
||||
INSTR_CALL7,
|
||||
INSTR_CALL8,
|
||||
INSTR_STATE,
|
||||
INSTR_GOTO,
|
||||
INSTR_AND,
|
||||
INSTR_OR,
|
||||
INSTR_BITAND,
|
||||
INSTR_BITOR
|
||||
INSTR_DONE,
|
||||
INSTR_MUL_F,
|
||||
INSTR_MUL_V,
|
||||
INSTR_MUL_FV,
|
||||
INSTR_MUL_VF,
|
||||
INSTR_DIV_F,
|
||||
INSTR_ADD_F,
|
||||
INSTR_ADD_V,
|
||||
INSTR_SUB_F,
|
||||
INSTR_SUB_V,
|
||||
INSTR_EQ_F,
|
||||
INSTR_EQ_V,
|
||||
INSTR_EQ_S,
|
||||
INSTR_EQ_E,
|
||||
INSTR_EQ_FNC,
|
||||
INSTR_NE_F,
|
||||
INSTR_NE_V,
|
||||
INSTR_NE_S,
|
||||
INSTR_NE_E,
|
||||
INSTR_NE_FNC,
|
||||
INSTR_LE,
|
||||
INSTR_GE,
|
||||
INSTR_LT,
|
||||
INSTR_GT,
|
||||
INSTR_LOAD_F,
|
||||
INSTR_LOAD_V,
|
||||
INSTR_LOAD_S,
|
||||
INSTR_LOAD_ENT,
|
||||
INSTR_LOAD_FLD,
|
||||
INSTR_LOAD_FNC,
|
||||
INSTR_ADDRESS,
|
||||
INSTR_STORE_F,
|
||||
INSTR_STORE_V,
|
||||
INSTR_STORE_S,
|
||||
INSTR_STORE_ENT,
|
||||
INSTR_STORE_FLD,
|
||||
INSTR_STORE_FNC,
|
||||
INSTR_STOREP_F,
|
||||
INSTR_STOREP_V,
|
||||
INSTR_STOREP_S,
|
||||
INSTR_STOREP_ENT,
|
||||
INSTR_STOREP_FLD,
|
||||
INSTR_STOREP_FNC,
|
||||
INSTR_RETURN,
|
||||
INSTR_NOT_F,
|
||||
INSTR_NOT_V,
|
||||
INSTR_NOT_S,
|
||||
INSTR_NOT_ENT,
|
||||
INSTR_NOT_FNC,
|
||||
INSTR_IF,
|
||||
INSTR_IFNOT,
|
||||
INSTR_CALL0,
|
||||
INSTR_CALL1,
|
||||
INSTR_CALL2,
|
||||
INSTR_CALL3,
|
||||
INSTR_CALL4,
|
||||
INSTR_CALL5,
|
||||
INSTR_CALL6,
|
||||
INSTR_CALL7,
|
||||
INSTR_CALL8,
|
||||
INSTR_STATE,
|
||||
INSTR_GOTO,
|
||||
INSTR_AND,
|
||||
INSTR_OR,
|
||||
INSTR_BITAND,
|
||||
INSTR_BITOR
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
528
lex.c
528
lex.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -27,43 +27,43 @@
|
|||
* than keyword lexing.
|
||||
*/
|
||||
static const char *const lex_keywords[] = {
|
||||
"do", "else", "if", "while",
|
||||
"break", "continue", "return", "goto",
|
||||
"for", "typedef"
|
||||
"do", "else", "if", "while",
|
||||
"break", "continue", "return", "goto",
|
||||
"for", "typedef"
|
||||
};
|
||||
|
||||
struct lex_file *lex_open(FILE *fp) {
|
||||
struct lex_file *lex = mem_a(sizeof(struct lex_file));
|
||||
if (!lex || !fp)
|
||||
return NULL;
|
||||
|
||||
lex->file = fp;
|
||||
fseek(lex->file, 0, SEEK_END);
|
||||
lex->length = ftell(lex->file);
|
||||
lex->size = lex->length; /* copy, this is never changed */
|
||||
fseek(lex->file, 0, SEEK_SET);
|
||||
lex->last = 0;
|
||||
lex->line = 0;
|
||||
|
||||
memset(lex->peek, 0, sizeof(lex->peek));
|
||||
return lex;
|
||||
struct lex_file *lex = mem_a(sizeof(struct lex_file));
|
||||
if (!lex || !fp)
|
||||
return NULL;
|
||||
|
||||
lex->file = fp;
|
||||
fseek(lex->file, 0, SEEK_END);
|
||||
lex->length = ftell(lex->file);
|
||||
lex->size = lex->length; /* copy, this is never changed */
|
||||
fseek(lex->file, 0, SEEK_SET);
|
||||
lex->last = 0;
|
||||
lex->line = 0;
|
||||
|
||||
memset(lex->peek, 0, sizeof(lex->peek));
|
||||
return lex;
|
||||
}
|
||||
|
||||
void lex_close(struct lex_file *file) {
|
||||
if (!file) return;
|
||||
|
||||
fclose(file->file); /* may already be closed */
|
||||
mem_d (file);
|
||||
if (!file) return;
|
||||
|
||||
fclose(file->file); /* may already be closed */
|
||||
mem_d (file);
|
||||
}
|
||||
|
||||
static void lex_addch(int ch, struct lex_file *file) {
|
||||
if (file->current < sizeof(file->lastok)-1)
|
||||
file->lastok[file->current++] = (char)ch;
|
||||
if (file->current == sizeof(file->lastok)-1)
|
||||
file->lastok[file->current] = (char)'\0';
|
||||
if (file->current < sizeof(file->lastok)-1)
|
||||
file->lastok[file->current++] = (char)ch;
|
||||
if (file->current == sizeof(file->lastok)-1)
|
||||
file->lastok[file->current] = (char)'\0';
|
||||
}
|
||||
static inline void lex_clear(struct lex_file *file) {
|
||||
file->current = 0;
|
||||
file->current = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -72,15 +72,15 @@ static inline void lex_clear(struct lex_file *file) {
|
|||
* it's own internal state for this.
|
||||
*/
|
||||
static int lex_inget(struct lex_file *file) {
|
||||
file->length --;
|
||||
if (file->last > 0)
|
||||
return file->peek[--file->last];
|
||||
return fgetc(file->file);
|
||||
file->length --;
|
||||
if (file->last > 0)
|
||||
return file->peek[--file->last];
|
||||
return fgetc(file->file);
|
||||
}
|
||||
static void lex_unget(int ch, struct lex_file *file) {
|
||||
if (file->last < sizeof(file->peek))
|
||||
file->peek[file->last++] = ch;
|
||||
file->length ++;
|
||||
if (file->last < sizeof(file->peek))
|
||||
file->peek[file->last++] = ch;
|
||||
file->length ++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,249 +88,249 @@ static void lex_unget(int ch, struct lex_file *file) {
|
|||
* supports. Moving up in this world!
|
||||
*/
|
||||
static int lex_trigraph(struct lex_file *file) {
|
||||
int ch;
|
||||
if ((ch = lex_inget(file)) != '?') {
|
||||
lex_unget(ch, file);
|
||||
return '?';
|
||||
}
|
||||
|
||||
ch = lex_inget(file);
|
||||
switch (ch) {
|
||||
case '(' : return '[' ;
|
||||
case ')' : return ']' ;
|
||||
case '/' : return '\\';
|
||||
case '\'': return '^' ;
|
||||
case '<' : return '{' ;
|
||||
case '>' : return '}' ;
|
||||
case '!' : return '|' ;
|
||||
case '-' : return '~' ;
|
||||
case '=' : return '#' ;
|
||||
default:
|
||||
lex_unget('?', file);
|
||||
lex_unget(ch , file);
|
||||
return '?';
|
||||
}
|
||||
return '?';
|
||||
int ch;
|
||||
if ((ch = lex_inget(file)) != '?') {
|
||||
lex_unget(ch, file);
|
||||
return '?';
|
||||
}
|
||||
|
||||
ch = lex_inget(file);
|
||||
switch (ch) {
|
||||
case '(' : return '[' ;
|
||||
case ')' : return ']' ;
|
||||
case '/' : return '\\';
|
||||
case '\'': return '^' ;
|
||||
case '<' : return '{' ;
|
||||
case '>' : return '}' ;
|
||||
case '!' : return '|' ;
|
||||
case '-' : return '~' ;
|
||||
case '=' : return '#' ;
|
||||
default:
|
||||
lex_unget('?', file);
|
||||
lex_unget(ch , file);
|
||||
return '?';
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
static int lex_digraph(struct lex_file *file, int first) {
|
||||
int ch = lex_inget(file);
|
||||
switch (first) {
|
||||
case '<':
|
||||
if (ch == '%') return '{';
|
||||
if (ch == ':') return '[';
|
||||
break;
|
||||
case '%':
|
||||
if (ch == '>') return '}';
|
||||
if (ch == ':') return '#';
|
||||
break;
|
||||
case ':':
|
||||
if (ch == '>') return ']';
|
||||
break;
|
||||
}
|
||||
|
||||
lex_unget(ch, file);
|
||||
return first;
|
||||
int ch = lex_inget(file);
|
||||
switch (first) {
|
||||
case '<':
|
||||
if (ch == '%') return '{';
|
||||
if (ch == ':') return '[';
|
||||
break;
|
||||
case '%':
|
||||
if (ch == '>') return '}';
|
||||
if (ch == ':') return '#';
|
||||
break;
|
||||
case ':':
|
||||
if (ch == '>') return ']';
|
||||
break;
|
||||
}
|
||||
|
||||
lex_unget(ch, file);
|
||||
return first;
|
||||
}
|
||||
|
||||
static int lex_getch(struct lex_file *file) {
|
||||
int ch = lex_inget(file);
|
||||
int ch = lex_inget(file);
|
||||
|
||||
static int str = 0;
|
||||
switch (ch) {
|
||||
case '?' :
|
||||
return lex_trigraph(file);
|
||||
case '<' :
|
||||
case ':' :
|
||||
case '%' :
|
||||
case '"' : str = !str; if (str) { file->line ++; }
|
||||
return lex_digraph(file, ch);
|
||||
|
||||
case '\n':
|
||||
if (!str)
|
||||
file->line++;
|
||||
}
|
||||
|
||||
return ch;
|
||||
static int str = 0;
|
||||
switch (ch) {
|
||||
case '?' :
|
||||
return lex_trigraph(file);
|
||||
case '<' :
|
||||
case ':' :
|
||||
case '%' :
|
||||
case '"' : str = !str; if (str) { file->line ++; }
|
||||
return lex_digraph(file, ch);
|
||||
|
||||
case '\n':
|
||||
if (!str)
|
||||
file->line++;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int lex_get(struct lex_file *file) {
|
||||
int ch;
|
||||
if (!isspace(ch = lex_getch(file)))
|
||||
return ch;
|
||||
|
||||
/* skip over all spaces */
|
||||
while (isspace(ch) && ch != '\n')
|
||||
ch = lex_getch(file);
|
||||
|
||||
if (ch == '\n')
|
||||
return ch;
|
||||
lex_unget(ch, file);
|
||||
return ' ';
|
||||
int ch;
|
||||
if (!isspace(ch = lex_getch(file)))
|
||||
return ch;
|
||||
|
||||
/* skip over all spaces */
|
||||
while (isspace(ch) && ch != '\n')
|
||||
ch = lex_getch(file);
|
||||
|
||||
if (ch == '\n')
|
||||
return ch;
|
||||
lex_unget(ch, file);
|
||||
return ' ';
|
||||
}
|
||||
|
||||
static int lex_skipchr(struct lex_file *file) {
|
||||
int ch;
|
||||
int it;
|
||||
|
||||
lex_clear(file);
|
||||
lex_addch('\'', file);
|
||||
|
||||
for (it = 0; it < 2 && ((ch = lex_inget(file)) != '\''); it++) {
|
||||
lex_addch(ch, file);
|
||||
|
||||
if (ch == '\n')
|
||||
return ERROR_LEX;
|
||||
if (ch == '\\')
|
||||
lex_addch(lex_getch(file), file);
|
||||
}
|
||||
lex_addch('\'', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
if (it > 2)
|
||||
return ERROR_LEX;
|
||||
|
||||
return LEX_CHRLIT;
|
||||
int ch;
|
||||
int it;
|
||||
|
||||
lex_clear(file);
|
||||
lex_addch('\'', file);
|
||||
|
||||
for (it = 0; it < 2 && ((ch = lex_inget(file)) != '\''); it++) {
|
||||
lex_addch(ch, file);
|
||||
|
||||
if (ch == '\n')
|
||||
return ERROR_LEX;
|
||||
if (ch == '\\')
|
||||
lex_addch(lex_getch(file), file);
|
||||
}
|
||||
lex_addch('\'', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
if (it > 2)
|
||||
return ERROR_LEX;
|
||||
|
||||
return LEX_CHRLIT;
|
||||
}
|
||||
|
||||
static int lex_skipstr(struct lex_file *file) {
|
||||
int ch;
|
||||
lex_clear(file);
|
||||
lex_addch('"', file);
|
||||
|
||||
while ((ch = lex_getch(file)) != '"') {
|
||||
if (ch == '\n' || ch == EOF)
|
||||
return ERROR_LEX;
|
||||
|
||||
lex_addch(ch, file);
|
||||
if (ch == '\\')
|
||||
lex_addch(lex_inget(file), file);
|
||||
}
|
||||
|
||||
lex_addch('"', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
return LEX_STRLIT;
|
||||
int ch;
|
||||
lex_clear(file);
|
||||
lex_addch('"', file);
|
||||
|
||||
while ((ch = lex_getch(file)) != '"') {
|
||||
if (ch == '\n' || ch == EOF)
|
||||
return ERROR_LEX;
|
||||
|
||||
lex_addch(ch, file);
|
||||
if (ch == '\\')
|
||||
lex_addch(lex_inget(file), file);
|
||||
}
|
||||
|
||||
lex_addch('"', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
return LEX_STRLIT;
|
||||
}
|
||||
static int lex_skipcmt(struct lex_file *file) {
|
||||
int ch;
|
||||
lex_clear(file);
|
||||
ch = lex_getch(file);
|
||||
|
||||
if (ch == '/') {
|
||||
lex_addch('/', file);
|
||||
lex_addch('/', file);
|
||||
|
||||
while ((ch = lex_getch(file)) != '\n') {
|
||||
if (ch == '\\') {
|
||||
lex_addch(ch, file);
|
||||
lex_addch(lex_getch(file), file);
|
||||
} else {
|
||||
lex_addch(ch, file);
|
||||
}
|
||||
}
|
||||
lex_addch('\0', file);
|
||||
return LEX_COMMENT;
|
||||
}
|
||||
|
||||
if (ch != '*') {
|
||||
lex_unget(ch, file);
|
||||
return '/';
|
||||
}
|
||||
|
||||
lex_addch('/', file);
|
||||
|
||||
/* hate this */
|
||||
do {
|
||||
lex_addch(ch, file);
|
||||
while ((ch = lex_getch(file)) != '*') {
|
||||
if (ch == EOF)
|
||||
return error(file, ERROR_LEX, "malformatted comment");
|
||||
else
|
||||
lex_addch(ch, file);
|
||||
}
|
||||
lex_addch(ch, file);
|
||||
} while ((ch = lex_getch(file)) != '/');
|
||||
|
||||
lex_addch('/', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
return LEX_COMMENT;
|
||||
int ch;
|
||||
lex_clear(file);
|
||||
ch = lex_getch(file);
|
||||
|
||||
if (ch == '/') {
|
||||
lex_addch('/', file);
|
||||
lex_addch('/', file);
|
||||
|
||||
while ((ch = lex_getch(file)) != '\n') {
|
||||
if (ch == '\\') {
|
||||
lex_addch(ch, file);
|
||||
lex_addch(lex_getch(file), file);
|
||||
} else {
|
||||
lex_addch(ch, file);
|
||||
}
|
||||
}
|
||||
lex_addch('\0', file);
|
||||
return LEX_COMMENT;
|
||||
}
|
||||
|
||||
if (ch != '*') {
|
||||
lex_unget(ch, file);
|
||||
return '/';
|
||||
}
|
||||
|
||||
lex_addch('/', file);
|
||||
|
||||
/* hate this */
|
||||
do {
|
||||
lex_addch(ch, file);
|
||||
while ((ch = lex_getch(file)) != '*') {
|
||||
if (ch == EOF)
|
||||
return error(file, ERROR_LEX, "malformatted comment");
|
||||
else
|
||||
lex_addch(ch, file);
|
||||
}
|
||||
lex_addch(ch, file);
|
||||
} while ((ch = lex_getch(file)) != '/');
|
||||
|
||||
lex_addch('/', file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
return LEX_COMMENT;
|
||||
}
|
||||
|
||||
static int lex_getsource(struct lex_file *file) {
|
||||
int ch = lex_get(file);
|
||||
|
||||
/* skip char/string/comment */
|
||||
switch (ch) {
|
||||
case '\'': return lex_skipchr(file);
|
||||
case '"': return lex_skipstr(file);
|
||||
case '/': return lex_skipcmt(file);
|
||||
default:
|
||||
return ch;
|
||||
}
|
||||
int ch = lex_get(file);
|
||||
|
||||
/* skip char/string/comment */
|
||||
switch (ch) {
|
||||
case '\'': return lex_skipchr(file);
|
||||
case '"': return lex_skipstr(file);
|
||||
case '/': return lex_skipcmt(file);
|
||||
default:
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
int lex_token(struct lex_file *file) {
|
||||
int ch = lex_getsource(file);
|
||||
int it;
|
||||
|
||||
/* valid identifier */
|
||||
if (ch > 0 && (ch == '_' || isalpha(ch))) {
|
||||
lex_clear(file);
|
||||
|
||||
/*
|
||||
* Yes this is dirty, but there is no other _sane_ easy
|
||||
* way to do it, this is what I call defensive programming
|
||||
* if something breaks, add more defense :-)
|
||||
*/
|
||||
while (ch > 0 && ch != ' ' && ch != '(' &&
|
||||
ch != '\n' && ch != ';' && ch != ')') {
|
||||
lex_addch(ch, file);
|
||||
ch = lex_getsource(file);
|
||||
}
|
||||
lex_unget(ch, file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
/* look inside the table for a keyword .. */
|
||||
for (it = 0; it < sizeof(lex_keywords)/sizeof(*lex_keywords); it++)
|
||||
if (!strncmp(file->lastok, lex_keywords[it], sizeof(lex_keywords[it])))
|
||||
return it;
|
||||
|
||||
/* try a type? */
|
||||
#define TEST_TYPE(X) \
|
||||
do { \
|
||||
if (!strncmp(X, "float", sizeof("float"))) \
|
||||
return TOKEN_FLOAT; \
|
||||
if (!strncmp(X, "vector", sizeof("vector"))) \
|
||||
return TOKEN_VECTOR; \
|
||||
if (!strncmp(X, "string", sizeof("string"))) \
|
||||
return TOKEN_STRING; \
|
||||
if (!strncmp(X, "entity", sizeof("entity"))) \
|
||||
return TOKEN_ENTITY; \
|
||||
if (!strncmp(X, "void" , sizeof("void"))) \
|
||||
return TOKEN_VOID; \
|
||||
} while(0)
|
||||
|
||||
TEST_TYPE(file->lastok);
|
||||
|
||||
/* try the hashtable for typedefs? */
|
||||
if (typedef_find(file->lastok))
|
||||
TEST_TYPE(typedef_find(file->lastok)->name);
|
||||
|
||||
#undef TEST_TYPE
|
||||
return LEX_IDENT;
|
||||
}
|
||||
return ch;
|
||||
int ch = lex_getsource(file);
|
||||
int it;
|
||||
|
||||
/* valid identifier */
|
||||
if (ch > 0 && (ch == '_' || isalpha(ch))) {
|
||||
lex_clear(file);
|
||||
|
||||
/*
|
||||
* Yes this is dirty, but there is no other _sane_ easy
|
||||
* way to do it, this is what I call defensive programming
|
||||
* if something breaks, add more defense :-)
|
||||
*/
|
||||
while (ch > 0 && ch != ' ' && ch != '(' &&
|
||||
ch != '\n' && ch != ';' && ch != ')') {
|
||||
lex_addch(ch, file);
|
||||
ch = lex_getsource(file);
|
||||
}
|
||||
lex_unget(ch, file);
|
||||
lex_addch('\0', file);
|
||||
|
||||
/* look inside the table for a keyword .. */
|
||||
for (it = 0; it < sizeof(lex_keywords)/sizeof(*lex_keywords); it++)
|
||||
if (!strncmp(file->lastok, lex_keywords[it], sizeof(lex_keywords[it])))
|
||||
return it;
|
||||
|
||||
/* try a type? */
|
||||
#define TEST_TYPE(X) \
|
||||
do { \
|
||||
if (!strncmp(X, "float", sizeof("float"))) \
|
||||
return TOKEN_FLOAT; \
|
||||
if (!strncmp(X, "vector", sizeof("vector"))) \
|
||||
return TOKEN_VECTOR; \
|
||||
if (!strncmp(X, "string", sizeof("string"))) \
|
||||
return TOKEN_STRING; \
|
||||
if (!strncmp(X, "entity", sizeof("entity"))) \
|
||||
return TOKEN_ENTITY; \
|
||||
if (!strncmp(X, "void" , sizeof("void"))) \
|
||||
return TOKEN_VOID; \
|
||||
} while(0)
|
||||
|
||||
TEST_TYPE(file->lastok);
|
||||
|
||||
/* try the hashtable for typedefs? */
|
||||
if (typedef_find(file->lastok))
|
||||
TEST_TYPE(typedef_find(file->lastok)->name);
|
||||
|
||||
#undef TEST_TYPE
|
||||
return LEX_IDENT;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
void lex_reset(struct lex_file *file) {
|
||||
file->current = 0;
|
||||
file->last = 0;
|
||||
file->length = file->size;
|
||||
fseek(file->file, 0, SEEK_SET);
|
||||
|
||||
memset(file->peek, 0, sizeof(file->peek ));
|
||||
memset(file->lastok, 0, sizeof(file->lastok));
|
||||
file->current = 0;
|
||||
file->last = 0;
|
||||
file->length = file->size;
|
||||
fseek(file->file, 0, SEEK_SET);
|
||||
|
||||
memset(file->peek, 0, sizeof(file->peek ));
|
||||
memset(file->lastok, 0, sizeof(file->lastok));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -339,17 +339,17 @@ void lex_reset(struct lex_file *file) {
|
|||
* recrusion.
|
||||
*/
|
||||
struct lex_file *lex_include(struct lex_file *lex, char *file) {
|
||||
util_strrq(file);
|
||||
if (strncmp(lex->name, file, strlen(lex->name)) == 0) {
|
||||
error(lex, ERROR_LEX, "Source file cannot include itself\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
FILE *fp = fopen(file, "r");
|
||||
if (!fp) {
|
||||
error(lex, ERROR_LEX, "Include file `%s` doesn't exist\n", file);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
return lex_open(fp);
|
||||
util_strrq(file);
|
||||
if (strncmp(lex->name, file, strlen(lex->name)) == 0) {
|
||||
error(lex, ERROR_LEX, "Source file cannot include itself\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
FILE *fp = fopen(file, "r");
|
||||
if (!fp) {
|
||||
error(lex, ERROR_LEX, "Include file `%s` doesn't exist\n", file);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
return lex_open(fp);
|
||||
}
|
||||
|
|
26
main.c
26
main.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -22,16 +22,16 @@
|
|||
*/
|
||||
#include "gmqcc.h"
|
||||
int main(int argc, char **argv) {
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
//const char *ifile = argv[0];
|
||||
FILE *fp;
|
||||
|
||||
/*TODO: proper interface swith switches*/
|
||||
|
||||
asm_init ("test.qs", &fp);
|
||||
asm_parse(fp);
|
||||
asm_close(fp);
|
||||
return 0;
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
//const char *ifile = argv[0];
|
||||
FILE *fp;
|
||||
|
||||
/*TODO: proper interface swith switches*/
|
||||
|
||||
asm_init ("test.qs", &fp);
|
||||
asm_parse(fp);
|
||||
asm_close(fp);
|
||||
return 0;
|
||||
}
|
||||
|
|
520
parse.c
520
parse.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -24,272 +24,272 @@
|
|||
|
||||
/* compile-time constant for type constants */
|
||||
typedef struct {
|
||||
char *name;
|
||||
int type;
|
||||
float value[3];
|
||||
char *string; /* string value if constant is string literal */
|
||||
char *name;
|
||||
int type;
|
||||
float value[3];
|
||||
char *string; /* string value if constant is string literal */
|
||||
} constant;
|
||||
VECTOR_MAKE(constant, compile_constants);
|
||||
|
||||
void compile_constant_debug() {
|
||||
int iter = 0;
|
||||
for(; iter < compile_constants_elements; iter++) {
|
||||
constant *c = &compile_constants_data[iter];
|
||||
switch(c->type) {
|
||||
case TYPE_FLOAT: printf("constant: %s FLOAT %f\n", c->name, c->value[0]); break;
|
||||
case TYPE_VECTOR: printf("constant: %s VECTOR {%f,%f,%f}\n",c->name, c->value[0], c->value[1], c->value[2]); break;
|
||||
case TYPE_STRING: printf("constant: %s STRING %s\n", c->name, c->string); break;
|
||||
case TYPE_VOID: printf("constant: %s VOID %s\n", c->name, c->string); break;
|
||||
}
|
||||
}
|
||||
int iter = 0;
|
||||
for(; iter < compile_constants_elements; iter++) {
|
||||
constant *c = &compile_constants_data[iter];
|
||||
switch(c->type) {
|
||||
case TYPE_FLOAT: printf("constant: %s FLOAT %f\n", c->name, c->value[0]); break;
|
||||
case TYPE_VECTOR: printf("constant: %s VECTOR {%f,%f,%f}\n",c->name, c->value[0], c->value[1], c->value[2]); break;
|
||||
case TYPE_STRING: printf("constant: %s STRING %s\n", c->name, c->string); break;
|
||||
case TYPE_VOID: printf("constant: %s VOID %s\n", c->name, c->string); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 parse_gen(struct lex_file *file) {
|
||||
int token = 0;
|
||||
while ((token = lex_token(file)) != ERROR_LEX && file->length >= 0) {
|
||||
switch (token) {
|
||||
case TOKEN_TYPEDEF: {
|
||||
char *f; /* from */
|
||||
char *t; /* to */
|
||||
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); f = util_strdup(file->lastok);
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); t = util_strdup(file->lastok);
|
||||
|
||||
typedef_add(file, f, t);
|
||||
mem_d(f);
|
||||
mem_d(t);
|
||||
|
||||
token = lex_token(file);
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
|
||||
if (token != ';')
|
||||
error(file, ERROR_PARSE, "Expected a `;` at end of typedef statement");
|
||||
|
||||
token = lex_token(file);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_VOID: goto fall;
|
||||
case TOKEN_STRING: goto fall;
|
||||
case TOKEN_VECTOR: goto fall;
|
||||
case TOKEN_ENTITY: goto fall;
|
||||
case TOKEN_FLOAT: goto fall;
|
||||
{
|
||||
fall:;
|
||||
char *name = NULL;
|
||||
int type = token; /* story copy */
|
||||
|
||||
/* skip over space */
|
||||
token = lex_token(file);
|
||||
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:
|
||||
error(file, ERROR_PARSE, "Cannot assign value to type void\n");
|
||||
|
||||
/* TODO: Validate (end quote), strip quotes for constant add, name constant */
|
||||
case TOKEN_STRING:
|
||||
if (*file->lastok != '"')
|
||||
error(file, ERROR_PARSE, "Expected a '\"' (quote) for string constant\n");
|
||||
/* add the compile-time constant */
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TYPE_STRING,
|
||||
.value = {0,0,0},
|
||||
.string = util_strdup(file->lastok)
|
||||
});
|
||||
break;
|
||||
/* TODO: name constant, old qc vec literals, whitespace fixes, name constant */
|
||||
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(file, ERROR_PARSE, "Expected initializer list {} for vector constant\n");
|
||||
|
||||
/*
|
||||
* 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'd 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(file, ERROR_PARSE,"Invalid constant initializer element %c for vector, must be numeric\n", 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(file, ERROR_PARSE, "Invalid constant initializer element %c for vector, must be numeric.\n", NAME); \
|
||||
token = lex_token(file); \
|
||||
} \
|
||||
if ((token == '-' || token == '+') && compile_calc_s) { \
|
||||
error(file, ERROR_PARSE, "Invalid constant initializer sign for vector element %c\n", 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(file, ERROR_PARSE, "invalid constant initializer element %c for vector (missing spaces, or comma delimited list?)\n", NAME); \
|
||||
} else if (token != '}') { \
|
||||
error(file, ERROR_PARSE, "Expected `}` on end of constant initialization for vector\n"); \
|
||||
} \
|
||||
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... */
|
||||
token = lex_token(file);
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
if (token != ';')
|
||||
error(file, ERROR_PARSE, "Expected `;` on end of constant initialization for vector\n");
|
||||
|
||||
/* add the compile-time constant */
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TYPE_VECTOR,
|
||||
.value = {
|
||||
[0] = compile_calc_x,
|
||||
[1] = compile_calc_y,
|
||||
[2] = compile_calc_z
|
||||
},
|
||||
.string = NULL
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_ENTITY:
|
||||
case TOKEN_FLOAT: /*TODO: validate, constant generation, name constant */
|
||||
if (!isdigit(token))
|
||||
error(file, ERROR_PARSE, "Expected numeric constant for float constant\n");
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TOKEN_FLOAT,
|
||||
.value = {0,0,0},
|
||||
.string = NULL
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else if (token == '(') {
|
||||
printf("FUNCTION ??\n");
|
||||
}
|
||||
mem_d(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* From here down is all language punctuation: There is no
|
||||
* need to actual create tokens from these because they're already
|
||||
* tokenized as these individual tokens (which are in a special area
|
||||
* of the ascii table which doesn't conflict with our other tokens
|
||||
* which are higer than the ascii table.)
|
||||
*/
|
||||
case '#':
|
||||
token = lex_token(file); /* skip '#' */
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
/*
|
||||
* If we make it here we found a directive, the supported
|
||||
* directives so far are #include.
|
||||
*/
|
||||
if (strncmp(file->lastok, "include", sizeof("include")) == 0) {
|
||||
/*
|
||||
* We only suport include " ", not <> like in C (why?)
|
||||
* because the latter is silly.
|
||||
*/
|
||||
while (*file->lastok != '"' && token != '\n')
|
||||
token = lex_token(file);
|
||||
if (token == '\n')
|
||||
return error(file, ERROR_PARSE, "Invalid use of include preprocessor directive: wanted #include \"file.h\"\n");
|
||||
|
||||
char *copy = util_strdup(file->lastok);
|
||||
struct lex_file *next = lex_include(file, copy);
|
||||
|
||||
if (!next) {
|
||||
error(file, ERROR_INTERNAL, "Include subsystem failure\n");
|
||||
exit (-1);
|
||||
}
|
||||
compile_constants_add((constant) {
|
||||
.name = "#include",
|
||||
.type = TYPE_VOID,
|
||||
.value = {0,0,0},
|
||||
.string = copy
|
||||
});
|
||||
parse_gen(next);
|
||||
mem_d (copy);
|
||||
lex_close(next);
|
||||
}
|
||||
/* skip all tokens to end of directive */
|
||||
while (token != '\n')
|
||||
token = lex_token(file);
|
||||
break;
|
||||
|
||||
case LEX_IDENT:
|
||||
token = lex_token(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
compile_constant_debug();
|
||||
lex_reset(file);
|
||||
return 1;
|
||||
}
|
||||
int parse_gen(struct lex_file *file) {
|
||||
int token = 0;
|
||||
while ((token = lex_token(file)) != ERROR_LEX && file->length >= 0) {
|
||||
switch (token) {
|
||||
case TOKEN_TYPEDEF: {
|
||||
char *f; /* from */
|
||||
char *t; /* to */
|
||||
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); f = util_strdup(file->lastok);
|
||||
token = lex_token(file);
|
||||
token = lex_token(file); t = util_strdup(file->lastok);
|
||||
|
||||
typedef_add(file, f, t);
|
||||
mem_d(f);
|
||||
mem_d(t);
|
||||
|
||||
token = lex_token(file);
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
|
||||
if (token != ';')
|
||||
error(file, ERROR_PARSE, "Expected a `;` at end of typedef statement");
|
||||
|
||||
token = lex_token(file);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_VOID: goto fall;
|
||||
case TOKEN_STRING: goto fall;
|
||||
case TOKEN_VECTOR: goto fall;
|
||||
case TOKEN_ENTITY: goto fall;
|
||||
case TOKEN_FLOAT: goto fall;
|
||||
{
|
||||
fall:;
|
||||
char *name = NULL;
|
||||
int type = token; /* story copy */
|
||||
|
||||
/* skip over space */
|
||||
token = lex_token(file);
|
||||
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:
|
||||
error(file, ERROR_PARSE, "Cannot assign value to type void\n");
|
||||
|
||||
/* TODO: Validate (end quote), strip quotes for constant add, name constant */
|
||||
case TOKEN_STRING:
|
||||
if (*file->lastok != '"')
|
||||
error(file, ERROR_PARSE, "Expected a '\"' (quote) for string constant\n");
|
||||
/* add the compile-time constant */
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TYPE_STRING,
|
||||
.value = {0,0,0},
|
||||
.string = util_strdup(file->lastok)
|
||||
});
|
||||
break;
|
||||
/* TODO: name constant, old qc vec literals, whitespace fixes, name constant */
|
||||
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(file, ERROR_PARSE, "Expected initializer list {} for vector constant\n");
|
||||
|
||||
/*
|
||||
* 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'd 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(file, ERROR_PARSE,"Invalid constant initializer element %c for vector, must be numeric\n", 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(file, ERROR_PARSE, "Invalid constant initializer element %c for vector, must be numeric.\n", NAME); \
|
||||
token = lex_token(file); \
|
||||
} \
|
||||
if ((token == '-' || token == '+') && compile_calc_s) { \
|
||||
error(file, ERROR_PARSE, "Invalid constant initializer sign for vector element %c\n", 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(file, ERROR_PARSE, "invalid constant initializer element %c for vector (missing spaces, or comma delimited list?)\n", NAME); \
|
||||
} else if (token != '}') { \
|
||||
error(file, ERROR_PARSE, "Expected `}` on end of constant initialization for vector\n"); \
|
||||
} \
|
||||
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... */
|
||||
token = lex_token(file);
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
if (token != ';')
|
||||
error(file, ERROR_PARSE, "Expected `;` on end of constant initialization for vector\n");
|
||||
|
||||
/* add the compile-time constant */
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TYPE_VECTOR,
|
||||
.value = {
|
||||
[0] = compile_calc_x,
|
||||
[1] = compile_calc_y,
|
||||
[2] = compile_calc_z
|
||||
},
|
||||
.string = NULL
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_ENTITY:
|
||||
case TOKEN_FLOAT: /*TODO: validate, constant generation, name constant */
|
||||
if (!isdigit(token))
|
||||
error(file, ERROR_PARSE, "Expected numeric constant for float constant\n");
|
||||
compile_constants_add((constant){
|
||||
.name = util_strdup(name),
|
||||
.type = TOKEN_FLOAT,
|
||||
.value = {0,0,0},
|
||||
.string = NULL
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else if (token == '(') {
|
||||
printf("FUNCTION ??\n");
|
||||
}
|
||||
mem_d(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* From here down is all language punctuation: There is no
|
||||
* need to actual create tokens from these because they're already
|
||||
* tokenized as these individual tokens (which are in a special area
|
||||
* of the ascii table which doesn't conflict with our other tokens
|
||||
* which are higer than the ascii table.)
|
||||
*/
|
||||
case '#':
|
||||
token = lex_token(file); /* skip '#' */
|
||||
if (token == ' ')
|
||||
token = lex_token(file);
|
||||
/*
|
||||
* If we make it here we found a directive, the supported
|
||||
* directives so far are #include.
|
||||
*/
|
||||
if (strncmp(file->lastok, "include", sizeof("include")) == 0) {
|
||||
/*
|
||||
* We only suport include " ", not <> like in C (why?)
|
||||
* because the latter is silly.
|
||||
*/
|
||||
while (*file->lastok != '"' && token != '\n')
|
||||
token = lex_token(file);
|
||||
if (token == '\n')
|
||||
return error(file, ERROR_PARSE, "Invalid use of include preprocessor directive: wanted #include \"file.h\"\n");
|
||||
|
||||
char *copy = util_strdup(file->lastok);
|
||||
struct lex_file *next = lex_include(file, copy);
|
||||
|
||||
if (!next) {
|
||||
error(file, ERROR_INTERNAL, "Include subsystem failure\n");
|
||||
exit (-1);
|
||||
}
|
||||
compile_constants_add((constant) {
|
||||
.name = "#include",
|
||||
.type = TYPE_VOID,
|
||||
.value = {0,0,0},
|
||||
.string = copy
|
||||
});
|
||||
parse_gen(next);
|
||||
mem_d (copy);
|
||||
lex_close(next);
|
||||
}
|
||||
/* skip all tokens to end of directive */
|
||||
while (token != '\n')
|
||||
token = lex_token(file);
|
||||
break;
|
||||
|
||||
case LEX_IDENT:
|
||||
token = lex_token(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
compile_constant_debug();
|
||||
lex_reset(file);
|
||||
return 1;
|
||||
}
|
||||
|
|
108
typedef.c
108
typedef.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -24,69 +24,69 @@
|
|||
static typedef_node *typedef_table[1024];
|
||||
|
||||
void typedef_init() {
|
||||
int i;
|
||||
for(i = 0; i < sizeof(typedef_table)/sizeof(*typedef_table); i++)
|
||||
typedef_table[i] = NULL;
|
||||
int i;
|
||||
for(i = 0; i < sizeof(typedef_table)/sizeof(*typedef_table); i++)
|
||||
typedef_table[i] = NULL;
|
||||
}
|
||||
|
||||
unsigned int typedef_hash(const char *s) {
|
||||
unsigned int hash = 0;
|
||||
unsigned int size = strlen(s);
|
||||
unsigned int iter;
|
||||
|
||||
for (iter = 0; iter < size; iter++) {
|
||||
hash += s[iter];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return hash % 1024;
|
||||
unsigned int hash = 0;
|
||||
unsigned int size = strlen(s);
|
||||
unsigned int iter;
|
||||
|
||||
for (iter = 0; iter < size; iter++) {
|
||||
hash += s[iter];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return hash % 1024;
|
||||
}
|
||||
|
||||
typedef_node *typedef_find(const char *s) {
|
||||
unsigned int hash = typedef_hash(s);
|
||||
typedef_node *find = typedef_table[hash];
|
||||
return find;
|
||||
unsigned int hash = typedef_hash(s);
|
||||
typedef_node *find = typedef_table[hash];
|
||||
return find;
|
||||
}
|
||||
|
||||
void typedef_clear() {
|
||||
int i;
|
||||
for(i = 1024; i > 0; i--) {
|
||||
if(typedef_table[i]) {
|
||||
mem_d(typedef_table[i]->name);
|
||||
mem_d(typedef_table[i]);
|
||||
}
|
||||
}
|
||||
int i;
|
||||
for(i = 1024; i > 0; i--) {
|
||||
if(typedef_table[i]) {
|
||||
mem_d(typedef_table[i]->name);
|
||||
mem_d(typedef_table[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int typedef_add(struct lex_file *file, const char *from, const char *to) {
|
||||
unsigned int hash = typedef_hash(to);
|
||||
typedef_node *find = typedef_table[hash];
|
||||
|
||||
if (find)
|
||||
return error(file, ERROR_PARSE, "typedef for %s already exists or conflicts\n", to);
|
||||
|
||||
/* check if the type exists first */
|
||||
if (strncmp(from, "float", sizeof("float")) == 0 ||
|
||||
strncmp(from, "vector", sizeof("vector")) == 0 ||
|
||||
strncmp(from, "string", sizeof("string")) == 0 ||
|
||||
strncmp(from, "entity", sizeof("entity")) == 0 ||
|
||||
strncmp(from, "void", sizeof("void")) == 0) {
|
||||
|
||||
typedef_table[hash] = mem_a(sizeof(typedef_node));
|
||||
typedef_table[hash]->name = util_strdup(from);
|
||||
return -100;
|
||||
} else {
|
||||
/* search the typedefs for it (typedef-a-typedef?) */
|
||||
typedef_node *find = typedef_table[typedef_hash(from)];
|
||||
if (find) {
|
||||
typedef_table[hash] = mem_a(sizeof(typedef_node));
|
||||
typedef_table[hash]->name = util_strdup(find->name);
|
||||
return -100;
|
||||
}
|
||||
}
|
||||
return error(file, ERROR_PARSE, "cannot typedef `%s` (not a type)\n", from);
|
||||
unsigned int hash = typedef_hash(to);
|
||||
typedef_node *find = typedef_table[hash];
|
||||
|
||||
if (find)
|
||||
return error(file, ERROR_PARSE, "typedef for %s already exists or conflicts\n", to);
|
||||
|
||||
/* check if the type exists first */
|
||||
if (strncmp(from, "float", sizeof("float")) == 0 ||
|
||||
strncmp(from, "vector", sizeof("vector")) == 0 ||
|
||||
strncmp(from, "string", sizeof("string")) == 0 ||
|
||||
strncmp(from, "entity", sizeof("entity")) == 0 ||
|
||||
strncmp(from, "void", sizeof("void")) == 0) {
|
||||
|
||||
typedef_table[hash] = mem_a(sizeof(typedef_node));
|
||||
typedef_table[hash]->name = util_strdup(from);
|
||||
return -100;
|
||||
} else {
|
||||
/* search the typedefs for it (typedef-a-typedef?) */
|
||||
typedef_node *find = typedef_table[typedef_hash(from)];
|
||||
if (find) {
|
||||
typedef_table[hash] = mem_a(sizeof(typedef_node));
|
||||
typedef_table[hash]->name = util_strdup(find->name);
|
||||
return -100;
|
||||
}
|
||||
}
|
||||
return error(file, ERROR_PARSE, "cannot typedef `%s` (not a type)\n", from);
|
||||
}
|
||||
|
|
208
util.c
208
util.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (C) 2012
|
||||
* Dale Weiler
|
||||
* Dale Weiler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
|
@ -25,29 +25,29 @@
|
|||
#include "gmqcc.h"
|
||||
|
||||
struct memblock_t {
|
||||
const char *file;
|
||||
unsigned int line;
|
||||
unsigned int byte;
|
||||
const char *file;
|
||||
unsigned int line;
|
||||
unsigned int byte;
|
||||
};
|
||||
|
||||
void *util_memory_a(unsigned int byte, unsigned int line, const char *file) {
|
||||
struct memblock_t *data = malloc(sizeof(struct memblock_t) + byte);
|
||||
if (!data) return NULL;
|
||||
data->line = line;
|
||||
data->byte = byte;
|
||||
data->file = file;
|
||||
|
||||
util_debug("MEM", "allocation: %08u (bytes) at %s:%u\n", byte, file, line);
|
||||
return (void*)((uintptr_t)data+sizeof(struct memblock_t));
|
||||
struct memblock_t *data = malloc(sizeof(struct memblock_t) + byte);
|
||||
if (!data) return NULL;
|
||||
data->line = line;
|
||||
data->byte = byte;
|
||||
data->file = file;
|
||||
|
||||
util_debug("MEM", "allocation: %08u (bytes) at %s:%u\n", byte, file, line);
|
||||
return (void*)((uintptr_t)data+sizeof(struct memblock_t));
|
||||
}
|
||||
|
||||
void util_memory_d(void *ptrn, unsigned int line, const char *file) {
|
||||
if (!ptrn) return;
|
||||
void *data = (void*)((uintptr_t)ptrn-sizeof(struct memblock_t));
|
||||
struct memblock_t *info = (struct memblock_t*)data;
|
||||
|
||||
util_debug("MEM", "released: %08u (bytes) at %s:%u\n", info->byte, file, line);
|
||||
free(data);
|
||||
if (!ptrn) return;
|
||||
void *data = (void*)((uintptr_t)ptrn-sizeof(struct memblock_t));
|
||||
struct memblock_t *info = (struct memblock_t*)data;
|
||||
|
||||
util_debug("MEM", "released: %08u (bytes) at %s:%u\n", info->byte, file, line);
|
||||
free(data);
|
||||
}
|
||||
|
||||
#ifndef mem_d
|
||||
|
@ -62,21 +62,21 @@ void util_memory_d(void *ptrn, unsigned int line, const char *file) {
|
|||
* to track all memory (without replacing malloc).
|
||||
*/
|
||||
char *util_strdup(const char *s) {
|
||||
size_t len;
|
||||
char *ptr;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
len = strlen(s);
|
||||
ptr = mem_a (len+1);
|
||||
|
||||
if (ptr && len) {
|
||||
memcpy(ptr, s, len);
|
||||
ptr[len] = '\0';
|
||||
}
|
||||
|
||||
return ptr;
|
||||
size_t len;
|
||||
char *ptr;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
len = strlen(s);
|
||||
ptr = mem_a (len+1);
|
||||
|
||||
if (ptr && len) {
|
||||
memcpy(ptr, s, len);
|
||||
ptr[len] = '\0';
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -85,20 +85,20 @@ char *util_strdup(const char *s) {
|
|||
* char array that is later freed (it uses pointer arith)
|
||||
*/
|
||||
char *util_strrq(char *s) {
|
||||
char *dst = s;
|
||||
char *src = s;
|
||||
char chr;
|
||||
while ((chr = *src++) != '\0') {
|
||||
if (chr == '\\') {
|
||||
*dst++ = chr;
|
||||
if ((chr = *src++) == '\0')
|
||||
break;
|
||||
*dst++ = chr;
|
||||
} else if (chr != '"')
|
||||
*dst++ = chr;
|
||||
}
|
||||
*dst = '\0';
|
||||
return dst;
|
||||
char *dst = s;
|
||||
char *src = s;
|
||||
char chr;
|
||||
while ((chr = *src++) != '\0') {
|
||||
if (chr == '\\') {
|
||||
*dst++ = chr;
|
||||
if ((chr = *src++) == '\0')
|
||||
break;
|
||||
*dst++ = chr;
|
||||
} else if (chr != '"')
|
||||
*dst++ = chr;
|
||||
}
|
||||
*dst = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -107,24 +107,24 @@ char *util_strrq(char *s) {
|
|||
* access.
|
||||
*/
|
||||
char *util_strrnl(char *src) {
|
||||
if (!src) return NULL;
|
||||
char *cpy = src;
|
||||
while (*cpy && *cpy != '\n')
|
||||
cpy++;
|
||||
|
||||
*cpy = '\0';
|
||||
return src;
|
||||
if (!src) return NULL;
|
||||
char *cpy = src;
|
||||
while (*cpy && *cpy != '\n')
|
||||
cpy++;
|
||||
|
||||
*cpy = '\0';
|
||||
return src;
|
||||
}
|
||||
|
||||
void util_debug(const char *area, const char *ms, ...) {
|
||||
va_list va;
|
||||
va_start(va, ms);
|
||||
fprintf (stdout, "DEBUG: ");
|
||||
fputc ('[', stdout);
|
||||
fprintf (stdout, area);
|
||||
fputs ("] ", stdout);
|
||||
vfprintf(stdout, ms, va);
|
||||
va_end (va);
|
||||
va_list va;
|
||||
va_start(va, ms);
|
||||
fprintf (stdout, "DEBUG: ");
|
||||
fputc ('[', stdout);
|
||||
fprintf (stdout, area);
|
||||
fputs ("] ", stdout);
|
||||
vfprintf(stdout, ms, va);
|
||||
va_end (va);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -132,51 +132,51 @@ void util_debug(const char *area, const char *ms, ...) {
|
|||
* assmed all. This works the same as getline().
|
||||
*/
|
||||
int util_getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
int chr;
|
||||
int ret;
|
||||
char *pos;
|
||||
int chr;
|
||||
int ret;
|
||||
char *pos;
|
||||
|
||||
if (!lineptr || !n || !stream)
|
||||
return -1;
|
||||
if (!*lineptr) {
|
||||
if (!(*lineptr = mem_a((*n = 64))))
|
||||
return -1;
|
||||
}
|
||||
if (!lineptr || !n || !stream)
|
||||
return -1;
|
||||
if (!*lineptr) {
|
||||
if (!(*lineptr = mem_a((*n = 64))))
|
||||
return -1;
|
||||
}
|
||||
|
||||
chr = *n;
|
||||
pos = *lineptr;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
*pos++ = c;
|
||||
chr--;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
*pos = '\0';
|
||||
return (ret = pos - *lineptr);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue