tabulators->four spaces

This commit is contained in:
Dale Weiler 2012-04-17 16:24:22 -04:00
parent 9031c57e39
commit 477e80f1fb
9 changed files with 1264 additions and 1264 deletions

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);
}