Merge branch 'assembler' into ast-and-ir

This commit is contained in:
Dale Weiler 2012-04-28 04:12:24 -04:00
commit 858d9734a2
6 changed files with 363 additions and 174 deletions

335
asm.c
View file

@ -21,40 +21,6 @@
* SOFTWARE.
*/
#include "gmqcc.h"
/*
* Some assembler keywords not part of the opcodes above: these are
* 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"
};
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;
}
void asm_init(const char *file, FILE **fp) {
*fp = fopen(file, "r");
code_init();
}
void asm_close(FILE *fp) {
fclose(fp);
code_write();
}
/*
* Following parse states:
* ASM_FUNCTION -- in a function accepting input statements
@ -71,6 +37,33 @@ typedef struct {
} globals;
VECTOR_MAKE(globals, assembly_constants);
/*
* Assembly text processing: this handles the internal collection
* of text to allow parsing and assemblation.
*/
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;
}
/*
* Entire external interface for main.c - to perform actual assemblation
* of assembly files.
*/
void asm_init(const char *file, FILE **fp) {
*fp = fopen(file, "r");
code_init();
}
void asm_close(FILE *fp) {
fclose(fp);
code_write();
}
void asm_clear() {
size_t i = 0;
for (; i < assembly_constants_elements; i++)
@ -78,30 +71,143 @@ void asm_clear() {
mem_d(assembly_constants_data);
}
int asm_parsetype(const char *key, char **skip, long line) {
size_t keylen = strlen(key);
if (!strncmp(key, *skip, keylen)) {
if ((*skip)[keylen] != ':'){
printf("%li: Missing `:` after decltype\n", line);
exit(1);
/*
* Parses a type, could be global or not depending on the
* assembly state: global scope with assignments are constants.
* globals with no assignments are globals. Function body types
* are locals.
*/
static inline bool asm_parse_type(const char *skip, size_t line, asm_state *state) {
if (!(strstr(skip, "FLOAT:") == &skip[0]) &&
(strstr(skip, "VECTOR:") == &skip[0]) &&
(strstr(skip, "ENTITY:") == &skip[0]) &&
(strstr(skip, "FIELD:") == &skip[0]) &&
(strstr(skip, "STRING:") == &skip[0])) return false;
/* TODO: determine if constant, global, or local */
switch (*skip) {
/* VECTOR */ case 'V': {
const char *find = skip + 7;
while (*find == ' ' || *find == '\t') find++;
printf("found VECTOR %s\n", find);
break;
}
*skip += keylen+1;
/* skip whitespace */
while (**skip == ' ' || **skip == '\t')
(*skip)++;
if (!isalpha(**skip)) {
printf("%li: Invalid identififer: %s\n", line, *skip);
exit(1);
} else {
assembly_constants_add((globals) {
.name = util_strdup("empty"),
.offset = code_globals_elements
});
return 1;
/* ENTITY */ case 'E': {
const char *find = skip + 7;
while (*find == ' ' || *find == '\t') find++;
printf("found ENTITY %s\n", find);
break;
}
/* STRING */ case 'S': {
const char *find = skip + 7;
while (*find == ' ' || *find == '\t') find++;
printf("found STRING %s\n", find);
break;
}
}
return 0;
return false;
}
/*
* Parses a function: trivial case, handles occurances of duplicated
* names among other things. Ensures valid name as well, and even
* internal engine function selection.
*/
static inline bool asm_parse_func(const char *skip, size_t line, asm_state *state) {
if (*state == ASM_FUNCTION && (strstr(skip, "FUNCTION:") == &skip[0]))
return false;
if (strstr(skip, "FUNCTION:") == &skip[0]) {
char *copy = util_strsws(skip+10);
char *name = util_strchp(copy, strchr(copy, '\0'));
/* TODO: failure system, missing name */
if (!name) {
printf("expected name on function\n");
mem_d(copy);
mem_d(name);
return false;
}
/* TODO: failure system, invalid name */
if (!isalpha(*name) || util_strupper(name)) {
printf("invalid identifer for function name\n");
mem_d(copy);
mem_d(name);
return false;
}
/*
* Function could be internal function, look for $
* to determine this.
*/
if (strchr(name, ',')) {
char *find = strchr(name, ',') + 1;
/* skip whitespace */
while (*find == ' ' || *find == '\t')
find++;
if (*find != '$') {
printf("expected $ for internal function selection, got %s instead\n", find);
mem_d(copy);
mem_d(name);
return false;
}
find ++;
if (!isdigit(*find)) {
printf("invalid internal identifier, expected valid number\n");
mem_d(copy);
mem_d(name);
return false;
}
/* reassign name */
mem_d(name);
name = util_strchp(name, strchr(name, ','));
/*
* Now add the following items to the code system:
* function
* definition (optional)
* global (optional)
* name
*/
code_functions_add((prog_section_function){
-atoi(find), /* needs to be negated */
0, 0, 0,
.name = code_chars_elements,
0, 0,{0}
});
code_defs_add((prog_section_def){
.type = TYPE_FUNCTION,
.offset = code_globals_elements,
.name = code_chars_elements
});
code_globals_add(code_chars_elements);
code_chars_put(name, strlen(name));
code_chars_add('\0');
/*
* Sanatize the numerical constant used to select the
* internal function. Must ensure it's all numeric, since
* atoi can silently drop characters from a string and still
* produce a valid constant that would lead to runtime problems.
*/
if (util_strdigit(find))
printf("found internal function %s, -%d\n", name, atoi(find));
else
printf("invalid internal function identifier, must be all numeric\n");
} else {
/* TODO: function bodies */
}
mem_d(copy);
mem_d(name);
return true;
}
return false;
}
void asm_parse(FILE *fp) {
@ -110,102 +216,33 @@ void asm_parse(FILE *fp) {
long line = 1; /* current line */
size_t size = 0; /* size of line */
asm_state state = ASM_NULL;
while ((data = skip = asm_getline(&size, fp)) != NULL) {
/* remove any whitespace at start */
while (*skip == ' ' || *skip == '\t')
skip++;
/* remove newline at end of string */
*(skip+*(&size)-1) = '\0';
if (asm_parsetype(asm_keys[5], &skip, line)) {
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 = code_globals_elements,
.name = code_chars_elements
});
code_globals_add(code_functions_elements);
code_functions_add((prog_section_function) {
.entry = code_statements_elements,
.firstlocal = 0,
.locals = 0,
.profile = 0,
.name = code_chars_elements,
.file = 0,
.nargs = 0,
.argsize = {0}
});
code_chars_put(skip, strlen(skip));
};
#if 0
/* if we make it this far then we have statements */
{
size_t i = 0; /* counter */
size_t o = 0; /* operands */
size_t c = 0; /* copy */
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 */
c = i;
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 ++;
}
/* 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){
c,
{ atof(op[0]) },
{ atof(op[1]) },
{ atof(op[2]) }
});
goto end;
}
}
}
#endif
#define asm_end(x) \
do { \
mem_d(data); \
mem_d(copy); \
line++; \
util_debug("ASM", x); \
} while (0); continue
while ((data = asm_getline (&size, fp)) != NULL) {
char *copy = util_strsws(data); /* skip whitespace */
skip = util_strrnl(copy); /* delete newline */
/* parse type */
if(asm_parse_type(skip, line, &state)){ asm_end("asm_parse_type\n"); }
/* parse func */
if(asm_parse_func(skip, line, &state)){ asm_end("asm_parse_func\n"); }
/* statement closure */
if (state == ASM_FUNCTION && (
(strstr(skip, "DONE") == &skip[0])||
(strstr(skip, "RETURN") == &skip[0]))) state = ASM_NULL;
/* if we made it this far something is wrong */
if (*skip != '\0')
printf("%li: Invalid statement %s, expression, or decleration\n", line, skip);
end:
mem_d(data);
line ++;
/* TODO: everything */
(void)state;
asm_end("asm_parse_end\n");
}
#undef asm_end
asm_clear();
}

27
code.c
View file

@ -205,18 +205,21 @@ void code_write() {
*((int32_t*)&code_functions_data[i].argsize)
);
util_debug("GEN", " NAME: %s\n", &code_chars_data[code_functions_data[i].name]);
util_debug("GEN", " CODE:\n");
for (;;) {
if (code_statements_data[j].opcode != INSTR_DONE &&
code_statements_data[j].opcode != INSTR_RETURN)
util_debug("GEN", " %s {0x%05d,0x%05d,0x%05d}\n",
asm_instr[code_statements_data[j].opcode].m,
code_statements_data[j].s1,
code_statements_data[j].s2,
code_statements_data[j].s3
);
else break;
j++;
/* Internal functions have no code */
if (code_functions_data[i].entry >= 0) {
util_debug("GEN", " CODE:\n");
for (;;) {
if (code_statements_data[j].opcode != INSTR_DONE &&
code_statements_data[j].opcode != INSTR_RETURN)
util_debug("GEN", " %s {0x%05d,0x%05d,0x%05d}\n",
asm_instr[code_statements_data[j].opcode].m,
code_statements_data[j].s1,
code_statements_data[j].s2,
code_statements_data[j].s3
);
else break;
j++;
}
}
}

View file

@ -1,8 +1,88 @@
FLOAT: f 1;
FLOAT: f 2;
FLOAT: f 3;
STRING: bar "hello world"
; these are builtin functions
FUNCTION: makevectors, $1
FUNCTION: setorigin, $2
FUNCTION: setmodel, $3
FUNCTION: setsize, $4
FUNCTION: foo
ADD_F 200.4f, 300.3, OFS_RETURN
DONE
FUNCTION: break, $6
FUNCTION: random, $7
FUNCTION: sound, $8
FUNCTION: normalize, $9
FUNCTION: error, $10
FUNCTION: objerror, $11
FUNCTION: vlen, $12
FUNCTION: vectoyaw, $13
FUNCTION: spawn, $14
FUNCTION: remove, $15
FUNCTION: traceline, $16
FUNCTION: find, $18
FUNCTION: precache_sound, $19
FUNCTION: precache_model, $20
FUNCTION: findradius, $22
FUNCTION: dprint, $25
FUNCTION: ftos, $26
FUNCTION: vtos, $27
FUNCTION: coredump, $28
FUNCTION: traceon, $29
FUNCTION: traceoff, $30
FUNCTION: eprint, $31
FUNCTION: walkmove, $32
FUNCTION: droptofloor, $34
FUNCTION: lightstyle, $35
FUNCTION: rint, $36
FUNCTION: floor, $37
FUNCTION: ceil, $38
FUNCTION: checkbottom, $40
FUNCTION: pointcontents, $41
FUNCTION: fabs, $43
FUNCTION: cvar, $45
FUNCTION: localcmd, $46
FUNCTION: nextent, $47
FUNCTION: particle, $48
FUNCTION: ChangeYaw, $49
FUNCTION: vectoangles, $51
FUNCTION: vectoangles2, $51
FUNCTION: sin, $60
FUNCTION: cos, $61
FUNCTION: sqrt, $62
FUNCTION: changepitch, $63
FUNCTION: tracetoss, $64
FUNCTION: etos, $65
FUNCTION: precache_file, $68
FUNCTION: makestatic, $69
FUNCTION: cvar_set, $72
FUNCTION: ambientsound, $74
FUNCTION: precache_model2,$75
FUNCTION: precache_sound2,$76
FUNCTION: precache_file2, $77
FUNCTION: stof, $81
FUNCTION: tracebox, $90
FUNCTION: randomvec, $91
FUNCTION: getlight, $92
FUNCTION: getlight2, $92
FUNCTION: registercvar, $93
FUNCTION: min, $94
FUNCTION: max, $95
FUNCTION: bound, $96
FUNCTION: pow, $97
FUNCTION: findfloat, $98
FUNCTION: checkextension, $99
; constants test
VECTOR: 1, 2, 3
FLOAT: 1
STRING: "hello world"

View file

@ -104,7 +104,6 @@
typedef char uint8_size_is_correct [sizeof(uint8_t) == 1?1:-1];
typedef char uint16_size_if_correct [sizeof(uint16_t) == 2?1:-1];
typedef char uint32_size_is_correct [sizeof(uint32_t) == 4?1:-1];
//typedef char int8_size_is_correct [sizeof(int8_t) == 1?1:-1];
typedef char int16_size_if_correct [sizeof(int16_t) == 2?1:-1];
typedef char int32_size_is_correct [sizeof(int32_t) == 4?1:-1];
/* intptr_t / uintptr_t correct size check */
@ -206,9 +205,13 @@ void *util_memory_a (unsigned int, unsigned int, const char *);
void util_memory_d (void *, unsigned int, const char *);
void util_meminfo ();
bool util_strupper (const char *);
bool util_strdigit (const char *);
char *util_strdup (const char *);
char *util_strrq (char *);
char *util_strrnl (char *);
char *util_strsws (const char *);
char *util_strchp (const char *, const char *);
void util_debug (const char *, const char *, ...);
int util_getline (char **, size_t *, FILE *);
void util_endianswap (void *, int, int);

View file

@ -63,15 +63,21 @@ int typedef_add(struct lex_file *file, const char *from, const char *to) {
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);
typedef_table[hash] = mem_a(sizeof(typedef_node));
if (typedef_table[hash])
typedef_table[hash]->name = util_strdup(from);
else
return error(file, ERROR_PARSE, "ran out of resources for typedef %s\n", to);
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);
typedef_table[hash] = mem_a(sizeof(typedef_node));
if (typedef_table[hash])
typedef_table[hash]->name = util_strdup(find->name);
else
return error(file, ERROR_PARSE, "ran out of resources for typedef %s\n", to);
return -100;
}
}

62
util.c
View file

@ -33,7 +33,7 @@ struct memblock_t {
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 *info = malloc(sizeof(struct memblock_t) + byte);
@ -46,6 +46,7 @@ void *util_memory_a(unsigned int byte, unsigned int line, const char *file) {
util_debug("MEM", "allocation: % 8u (bytes) address 0x%08X @ %s:%u\n", byte, data, file, line);
mem_at++;
mem_ab += info->byte;
return data;
}
@ -57,6 +58,7 @@ void util_memory_d(void *ptrn, unsigned int line, const char *file) {
util_debug("MEM", "released: % 8u (bytes) address 0x%08X @ %s:%u\n", info->byte, data, file, line);
mem_db += info->byte;
mem_dt++;
free(data);
}
@ -117,6 +119,23 @@ char *util_strrq(char *s) {
return dst;
}
/*
* Chops a substring from an existing string by creating a
* copy of it and null terminating it at the required position.
*/
char *util_strchp(const char *s, const char *e) {
if (!s || !e)
return NULL;
size_t m = 0;
char *c = util_strdup(s);
while (s != e)
s++,c++,m++;
*c = '\0';
return c-m;
}
/*
* Remove newline from a string (if it exists). This is
* done pointer wise instead of strlen(), and an array
@ -132,6 +151,47 @@ char *util_strrnl(char *src) {
return src;
}
/*
* Removes any whitespace prefixed on a string by moving
* skipping past it, and stroing the skip distance, so
* the string can later be freed (if it was allocated)
*/
char *util_strsws(const char *skip) {
size_t size = 0;
if (!skip)
return NULL;
while (*skip == ' ' || *skip == '\t')
skip++,size++;
return util_strdup(skip-size);
}
/*
* Returns true if string is all uppercase, otherwise
* it returns false.
*/
bool util_strupper(const char *str) {
while (*str) {
if(!isupper(*str))
return false;
str++;
}
return true;
}
/*
* Returns true if string is all digits, otherwise
* it returns false.
*/
bool util_strdigit(const char *str) {
while (*str) {
if(!isdigit(*str))
return false;
str++;
}
return true;
}
void util_debug(const char *area, const char *ms, ...) {
if (!opts_debug)
return;