mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-18 14:21:36 +00:00
More parsing stuff (still totally broken)
This commit is contained in:
parent
e4e6185d5f
commit
e4bc0a2d6a
8 changed files with 198 additions and 100 deletions
18
Makefile
18
Makefile
|
@ -1,12 +1,12 @@
|
|||
CC = gcc
|
||||
CFLAGS = -O3 -Wall
|
||||
OBJ = main.o \
|
||||
lex.o \
|
||||
error.o \
|
||||
parse.o \
|
||||
typedef.o \
|
||||
util.o \
|
||||
code.o
|
||||
CC = gcc
|
||||
CFLAGS += -Wall
|
||||
OBJ = main.o \
|
||||
lex.o \
|
||||
error.o \
|
||||
parse.o \
|
||||
typedef.o \
|
||||
util.o \
|
||||
code.o
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $< -o $@ $(CFLAGS)
|
||||
|
|
54
code.c
54
code.c
|
@ -146,18 +146,29 @@ VECTOR_MAKE(prog_section_field, code_fields );
|
|||
VECTOR_MAKE(prog_section_function, code_functions );
|
||||
VECTOR_MAKE(int, code_globals );
|
||||
VECTOR_MAKE(char, code_strings );
|
||||
static uint16_t code_crc16 = 0;
|
||||
prog_header code_header ={0};
|
||||
|
||||
/* program header */
|
||||
prog_header code_header;
|
||||
void code_write() {
|
||||
|
||||
#if 0
|
||||
/* Add test program */
|
||||
code_strings_add('\0');
|
||||
|
||||
const char *X;
|
||||
size_t size = sizeof(X);
|
||||
size_t iter = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
void code_test() {
|
||||
const char *X;
|
||||
size_t size = sizeof(X);
|
||||
size_t iter = 0;
|
||||
|
||||
#define FOO(Y) \
|
||||
X = Y; \
|
||||
|
@ -174,10 +185,6 @@ void code_write() {
|
|||
FOO("m_toggle");
|
||||
FOO("m_shutdown");
|
||||
|
||||
int i;
|
||||
for (i=0; i<28; i++)
|
||||
code_globals_add(0); /* 28 empty */
|
||||
|
||||
code_globals_add(1); /* m_init */
|
||||
code_globals_add(2); /* print */
|
||||
code_globals_add(14); /* hello world in string table */
|
||||
|
@ -187,7 +194,6 @@ void code_write() {
|
|||
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){0, 0, 0, 0, .name=0, 0, 0, {0}}); /* NULL */
|
||||
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 */
|
||||
|
@ -195,10 +201,9 @@ void code_write() {
|
|||
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){0, 0, 0, 0}); /* NULL */
|
||||
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});
|
||||
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}});
|
||||
|
||||
code_header.version = 6;
|
||||
code_header.crc16 = 0; /* TODO: */
|
||||
|
@ -209,10 +214,13 @@ void code_write() {
|
|||
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: */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* write out everything one SHOT! */
|
||||
/* program header */
|
||||
void code_write() {
|
||||
code_init();
|
||||
code_test();
|
||||
|
||||
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);
|
||||
|
|
17
gmqcc.h
17
gmqcc.h
|
@ -28,15 +28,18 @@
|
|||
//============================ lex.c ================================
|
||||
//===================================================================
|
||||
struct lex_file {
|
||||
FILE *file;
|
||||
char peek [5];
|
||||
FILE *file; /* file handler */
|
||||
char *name; /* name of file */
|
||||
char peek [5];
|
||||
char lastok[8192];
|
||||
|
||||
int line;
|
||||
int last;
|
||||
int current;
|
||||
int length;
|
||||
int size;
|
||||
|
||||
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? */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
3
lex.c
3
lex.c
|
@ -48,6 +48,7 @@ struct lex_file *lex_open(FILE *fp) {
|
|||
lex->size = lex->length; /* copy, this is never changed */
|
||||
fseek(lex->file, 0, SEEK_SET);
|
||||
lex->last = 0;
|
||||
lex->line = 1;
|
||||
|
||||
memset(lex->peek, 0, sizeof(lex->peek));
|
||||
return lex;
|
||||
|
@ -276,7 +277,7 @@ int lex_token(struct lex_file *file) {
|
|||
/* valid identifier */
|
||||
if (ch > 0 && (ch == '_' || isalpha(ch))) {
|
||||
lex_clear(file);
|
||||
while (ch > 0 && (isalpha(ch) || ch == '_')) {
|
||||
while (ch > 0 && ch != ' ' && ch != '(' && ch != '\n') {
|
||||
lex_addch(ch, file);
|
||||
ch = lex_getsource(file);
|
||||
}
|
||||
|
|
2
main.c
2
main.c
|
@ -36,11 +36,13 @@ int main(int argc, char **argv) {
|
|||
return error(ERROR_COMPILER, "Source file: %s not found\n", ifile);
|
||||
} else {
|
||||
struct lex_file *lex = lex_open(fp);
|
||||
lex->name = util_strdup(ifile);
|
||||
if (!lex) {
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
parse_tree(lex);
|
||||
mem_d(lex->name);
|
||||
lex_close (lex);
|
||||
}
|
||||
|
||||
|
|
186
parse.c
186
parse.c
|
@ -93,59 +93,63 @@
|
|||
"." , "<" , ">" , "&" , "|" ,
|
||||
#endif
|
||||
|
||||
#define STORE(X) { \
|
||||
printf(X); \
|
||||
break; \
|
||||
#define STORE(X,C) { \
|
||||
long f = fill; \
|
||||
while(f--) { \
|
||||
putchar(' '); \
|
||||
} \
|
||||
fill C; \
|
||||
printf(X); \
|
||||
break; \
|
||||
}
|
||||
|
||||
void parse_debug(struct parsenode *tree) {
|
||||
long fill = 0;
|
||||
while (tree) {
|
||||
switch (tree->type) {
|
||||
case PARSE_TYPE_ADD: STORE("OPERATOR: ADD \n");
|
||||
case PARSE_TYPE_BAND: STORE("OPERATOR: BITAND \n");
|
||||
case PARSE_TYPE_BOR: STORE("OPERATOR: BITOR \n");
|
||||
case PARSE_TYPE_COMMA: STORE("OPERATOR: SEPERATOR\n");
|
||||
case PARSE_TYPE_DOT: STORE("OPERATOR: DOT\n");
|
||||
case PARSE_TYPE_DIVIDE: STORE("OPERATOR: DIVIDE\n");
|
||||
case PARSE_TYPE_EQUAL: STORE("OPERATOR: ASSIGNMENT\n");
|
||||
case PARSE_TYPE_ADD: STORE("OPERATOR: ADD \n", -=0);
|
||||
case PARSE_TYPE_BAND: STORE("OPERATOR: BITAND \n",-=0);
|
||||
case PARSE_TYPE_BOR: STORE("OPERATOR: BITOR \n",-=0);
|
||||
case PARSE_TYPE_COMMA: STORE("OPERATOR: SEPERATOR\n",-=0);
|
||||
case PARSE_TYPE_DOT: STORE("OPERATOR: DOT\n",-=0);
|
||||
case PARSE_TYPE_DIVIDE: STORE("OPERATOR: DIVIDE\n",-=0);
|
||||
case PARSE_TYPE_EQUAL: STORE("OPERATOR: ASSIGNMENT\n",-=0);
|
||||
|
||||
case PARSE_TYPE_BREAK: STORE("STATEMENT: BREAK \n");
|
||||
case PARSE_TYPE_CONTINUE: STORE("STATEMENT: CONTINUE\n");
|
||||
case PARSE_TYPE_GOTO: STORE("STATEMENT: GOTO\n");
|
||||
case PARSE_TYPE_RETURN: STORE("STATEMENT: RETURN\n");
|
||||
case PARSE_TYPE_DONE: STORE("STATEMENT: DONE\n");
|
||||
case PARSE_TYPE_BREAK: STORE("STATEMENT: BREAK \n",-=0);
|
||||
case PARSE_TYPE_CONTINUE: STORE("STATEMENT: CONTINUE\n",-=0);
|
||||
case PARSE_TYPE_GOTO: STORE("STATEMENT: GOTO\n",-=0);
|
||||
case PARSE_TYPE_RETURN: STORE("STATEMENT: RETURN\n",-=0);
|
||||
case PARSE_TYPE_DONE: STORE("STATEMENT: DONE\n",-=0);
|
||||
|
||||
case PARSE_TYPE_VOID: STORE("DECLTYPE: VOID\n");
|
||||
case PARSE_TYPE_STRING: STORE("DECLTYPE: STRING\n");
|
||||
case PARSE_TYPE_ELIP: STORE("DECLTYPE: VALIST\n");
|
||||
case PARSE_TYPE_ENTITY: STORE("DECLTYPE: ENTITY\n");
|
||||
case PARSE_TYPE_FLOAT: STORE("DECLTYPE: FLOAT\n");
|
||||
case PARSE_TYPE_VECTOR: STORE("DECLTYPE: VECTOR\n");
|
||||
case PARSE_TYPE_VOID: STORE("DECLTYPE: VOID\n",-=0);
|
||||
case PARSE_TYPE_STRING: STORE("DECLTYPE: STRING\n",-=0);
|
||||
case PARSE_TYPE_ELIP: STORE("DECLTYPE: VALIST\n",-=0);
|
||||
case PARSE_TYPE_ENTITY: STORE("DECLTYPE: ENTITY\n",-=0);
|
||||
case PARSE_TYPE_FLOAT: STORE("DECLTYPE: FLOAT\n",-=0);
|
||||
case PARSE_TYPE_VECTOR: STORE("DECLTYPE: VECTOR\n",-=0);
|
||||
|
||||
case PARSE_TYPE_GT: STORE("TEST: GREATER THAN\n");
|
||||
case PARSE_TYPE_LT: STORE("TEST: LESS THAN\n");
|
||||
case PARSE_TYPE_GTEQ: STORE("TEST: GREATER THAN OR EQUAL\n");
|
||||
case PARSE_TYPE_LTEQ: STORE("TEST: LESS THAN OR EQUAL\n");
|
||||
case PARSE_TYPE_LNEQ: STORE("TEST: NOT EQUAL\n");
|
||||
case PARSE_TYPE_EQEQ: STORE("TEST: EQUAL-EQUAL\n");
|
||||
case PARSE_TYPE_GT: STORE("TEST: GREATER THAN\n",-=0);
|
||||
case PARSE_TYPE_LT: STORE("TEST: LESS THAN\n",-=0);
|
||||
case PARSE_TYPE_GTEQ: STORE("TEST: GREATER THAN OR EQUAL\n",-=0);
|
||||
case PARSE_TYPE_LTEQ: STORE("TEST: LESS THAN OR EQUAL\n",-=0);
|
||||
case PARSE_TYPE_LNEQ: STORE("TEST: NOT EQUAL\n",-=0);
|
||||
case PARSE_TYPE_EQEQ: STORE("TEST: EQUAL-EQUAL\n",-=0);
|
||||
|
||||
case PARSE_TYPE_LBS: STORE("BLOCK: BEG\n");
|
||||
case PARSE_TYPE_RBS: STORE("BLOCK: END\n");
|
||||
case PARSE_TYPE_ELSE: STORE("BLOCK: ELSE\n");
|
||||
case PARSE_TYPE_IF: STORE("BLOCK: IF\n");
|
||||
case PARSE_TYPE_LBS: STORE("BLOCK: BEG\n",+=4);
|
||||
case PARSE_TYPE_RBS: STORE("BLOCK: END\n",-=4);
|
||||
case PARSE_TYPE_ELSE: STORE("BLOCK: ELSE\n",+=0);
|
||||
case PARSE_TYPE_IF: STORE("BLOCK: IF\n",+=0);
|
||||
|
||||
case PARSE_TYPE_LAND: STORE("LOGICAL: AND\n");
|
||||
case PARSE_TYPE_LNOT: STORE("LOGICAL: NOT\n");
|
||||
case PARSE_TYPE_LOR: STORE("LOGICAL: OR\n");
|
||||
case PARSE_TYPE_LAND: STORE("LOGICAL: AND\n",-=0);
|
||||
case PARSE_TYPE_LNOT: STORE("LOGICAL: NOT\n",-=0);
|
||||
case PARSE_TYPE_LOR: STORE("LOGICAL: OR\n",-=0);
|
||||
|
||||
case PARSE_TYPE_LPARTH: STORE("PARTH: BEG\n");
|
||||
case PARSE_TYPE_RPARTH: STORE("PARTH: END\n");
|
||||
case PARSE_TYPE_LPARTH: STORE("PARTH: BEG\n",-=0);
|
||||
case PARSE_TYPE_RPARTH: STORE("PARTH: END\n",-=0);
|
||||
|
||||
case PARSE_TYPE_WHILE: STORE("LOOP: WHILE\n");
|
||||
case PARSE_TYPE_FOR: STORE("LOOP: FOR\n");
|
||||
case PARSE_TYPE_DO: STORE("LOOP: DO\n");
|
||||
|
||||
//case PARSE_TYPE_IDENT: STORE("IDENT: ???\n");
|
||||
case PARSE_TYPE_WHILE: STORE("LOOP: WHILE\n",-=0);
|
||||
case PARSE_TYPE_FOR: STORE("LOOP: FOR\n",-=0);
|
||||
case PARSE_TYPE_DO: STORE("LOOP: DO\n",-=0);
|
||||
}
|
||||
tree = tree->next;
|
||||
}
|
||||
|
@ -181,6 +185,23 @@ void parse_clear(struct parsenode *tree) {
|
|||
typedef_clear();
|
||||
}
|
||||
|
||||
const char *STRING_(char ch) {
|
||||
if (ch == ' ')
|
||||
return "<space>";
|
||||
if (ch == '\n')
|
||||
return "<newline>";
|
||||
if (ch == '\0')
|
||||
return "<null>";
|
||||
|
||||
return &ch;
|
||||
}
|
||||
|
||||
#define TOKEN_SKIPWHITE() \
|
||||
token = lex_token(file); \
|
||||
while (token == ' ') { \
|
||||
token = lex_token(file); \
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -210,9 +231,9 @@ int parse_tree(struct lex_file *file) {
|
|||
token != ERROR_PREPRO && file->length >= 0) {
|
||||
switch (token) {
|
||||
case TOKEN_IF:
|
||||
token = lex_token(file);
|
||||
TOKEN_SKIPWHITE();
|
||||
if (token != '(')
|
||||
error(ERROR_PARSE, "Expected `(` on if statement:\n");
|
||||
error(ERROR_PARSE, "%s:%d Expected `(` after `if` for if statement\n", file->name, file->line);
|
||||
PARSE_TREE_ADD(PARSE_TYPE_IF);
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
|
||||
break;
|
||||
|
@ -221,7 +242,6 @@ int parse_tree(struct lex_file *file) {
|
|||
PARSE_TREE_ADD(PARSE_TYPE_ELSE);
|
||||
break;
|
||||
case TOKEN_FOR:
|
||||
//token = lex_token(file);
|
||||
while ((token == ' ' || token == '\n') && file->length >= 0)
|
||||
token = lex_token(file);
|
||||
PARSE_TREE_ADD(PARSE_TYPE_FOR);
|
||||
|
@ -267,10 +287,70 @@ int parse_tree(struct lex_file *file) {
|
|||
case TOKEN_BREAK: PARSE_PERFORM(PARSE_TYPE_BREAK, {});
|
||||
case TOKEN_GOTO: PARSE_PERFORM(PARSE_TYPE_GOTO, {});
|
||||
case TOKEN_VOID: PARSE_PERFORM(PARSE_TYPE_VOID, {});
|
||||
case TOKEN_STRING: PARSE_PERFORM(PARSE_TYPE_STRING, {});
|
||||
case TOKEN_FLOAT: PARSE_PERFORM(PARSE_TYPE_FLOAT, {});
|
||||
case TOKEN_VECTOR: PARSE_PERFORM(PARSE_TYPE_VECTOR, {});
|
||||
case TOKEN_ENTITY: PARSE_PERFORM(PARSE_TYPE_ENTITY, {});
|
||||
|
||||
case TOKEN_STRING: PARSE_TREE_ADD(PARSE_TYPE_STRING);
|
||||
case TOKEN_VECTOR: PARSE_TREE_ADD(PARSE_TYPE_VECTOR);
|
||||
case TOKEN_ENTITY: PARSE_TREE_ADD(PARSE_TYPE_ENTITY);
|
||||
case TOKEN_FLOAT: PARSE_TREE_ADD(PARSE_TYPE_FLOAT);
|
||||
/* fall into this for all types */
|
||||
{
|
||||
char *name = NULL;
|
||||
TOKEN_SKIPWHITE();
|
||||
name = util_strdup(file->lastok);
|
||||
//token = lex_token (file);
|
||||
|
||||
/* is it NOT a definition? */
|
||||
if (token != ';') {
|
||||
while (token == ' ')
|
||||
token = lex_token(file);
|
||||
|
||||
/* it's a function? */
|
||||
if (token == '(') {
|
||||
/*
|
||||
* Now I essentially have to do a ton of parsing for
|
||||
* function definition.
|
||||
*/
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LPARTH);
|
||||
token = lex_token(file);
|
||||
while (token != '\n' && token != ')') {
|
||||
switch (token) {
|
||||
case TOKEN_VOID: PARSE_TREE_ADD(PARSE_TYPE_VOID); break;
|
||||
case TOKEN_STRING: PARSE_TREE_ADD(PARSE_TYPE_STRING); break;
|
||||
case TOKEN_ENTITY: PARSE_TREE_ADD(PARSE_TYPE_ENTITY); break;
|
||||
case TOKEN_FLOAT: PARSE_TREE_ADD(PARSE_TYPE_FLOAT); break;
|
||||
/*
|
||||
* TODO: Need to parse function pointers: I have no clue how
|
||||
* I'm actually going to pull that off, it's going to be hard
|
||||
* since you can have a function pointer-pointer-pointer ....
|
||||
*/
|
||||
}
|
||||
}
|
||||
/* just a definition */
|
||||
if (token == ')') {
|
||||
/*
|
||||
* I like to put my { on the same line as the ) for
|
||||
* functions, ifs, elses, so we must support that!.
|
||||
*/
|
||||
PARSE_TREE_ADD(PARSE_TYPE_RPARTH);
|
||||
token = lex_token(file);
|
||||
token = lex_token(file);
|
||||
if(token == '{')
|
||||
PARSE_TREE_ADD(PARSE_TYPE_LBS);
|
||||
}
|
||||
else if (token == '\n')
|
||||
error(ERROR_COMPILER, "%s:%d Expecting `;` after function definition %s\n", file->name, file->line, name);
|
||||
|
||||
} else if (token == '=') {
|
||||
PARSE_TREE_ADD(PARSE_TYPE_EQUAL);
|
||||
} else {
|
||||
error(ERROR_COMPILER, "%s:%d Invalid decltype: expected `(` [function], or `=` [constant] for %s\n", file->name, file->line, name);
|
||||
}
|
||||
} else {
|
||||
/* definition */
|
||||
printf("FOUND DEFINITION\n");
|
||||
}
|
||||
mem_d(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* From here down is all language punctuation: There is no
|
||||
|
@ -281,11 +361,11 @@ int parse_tree(struct lex_file *file) {
|
|||
*/
|
||||
case '#':
|
||||
token = lex_token(file); /* skip '#' */
|
||||
while (isspace(token)) {
|
||||
if (token == '\n')
|
||||
return error(ERROR_PARSE, "Expected valid preprocessor directive after `#` %s\n");
|
||||
token = lex_token(file); /* try again */
|
||||
}
|
||||
//while (isspace(token)) {
|
||||
// if (token == '\n')
|
||||
// return error(ERROR_PARSE, "Expected valid preprocessor directive after `#` %s\n");
|
||||
// token = lex_token(file); /* try again */
|
||||
//}
|
||||
/*
|
||||
* If we make it here we found a directive, the supported
|
||||
* directives so far are #include.
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
float test_if() {
|
||||
if (1 == 1) {
|
||||
float test_1data = 1;
|
||||
float test_2data = 2;
|
||||
|
||||
float test_if()
|
||||
{
|
||||
if (test_1data == test_2data) {
|
||||
/* do this code */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
float type_float;
|
||||
vector type_vector;
|
||||
string type_string;
|
||||
entity type_entity;
|
||||
void type_void;
|
||||
float typef;
|
||||
vector typev;
|
||||
string types;
|
||||
entity typee;
|
||||
void typev;
|
||||
|
|
Loading…
Reference in a new issue