diff --git a/sys/sdl/gm2/Makefile b/sys/sdl/gm2/Makefile index eef9daed..5d21d8fc 100644 --- a/sys/sdl/gm2/Makefile +++ b/sys/sdl/gm2/Makefile @@ -2,18 +2,19 @@ CFLAGS = -g -Wall -Wpointer-arith -I. -I../../../csrc/. -I../../tga/mapgen/. -I. GMSRC = $(shell ls ../../../csrc/*.c) $(shell ls ../common/*.c ) GMSRC += map.c main.c item.c -GMSRC += ../../../tools/ugl/ugl_bc.c +#GMSRC += ../../../tools/ugl/ugl_bc.c +GMSRC += ugl_bc.c GMOBJ = $(GMSRC:.c=.o) MAPGENSRC = $(shell ls ../../../csrc/*.c) mapgen.c u8g2_d_tga.c -MAPGENSRC += ../../../tools/ugl/ugl_arrays.c -MAPGENSRC += ../../../tools/ugl/ugl_error.c -MAPGENSRC += ../../../tools/ugl/ugl_parse.c -#MAPGENSRC += ../../../tools/ugl/ugl_bc.c +MAPGENSRC += ugl_arrays.c ugl_error.c ugl_parse.c MAPGENOBJ = $(MAPGENSRC:.c=.o) +UGLSRC = ugl_arrays.c ugl_error.c ugl_parse.c ugl_bc.c ugl_main.c item.c map.c + +UGLOBJ = $(UGLSRC:.c=.o) gm: $(GMOBJ) map.c @@ -22,9 +23,12 @@ gm: $(GMOBJ) map.c mapgen: $(MAPGENOBJ) $(CC) $(CFLAGS) $(LDFLAGS) $(MAPGENOBJ) -o mapgen -map.c: mapgen gm.map +map.c: mapgen gm.map ./mapgen -o map.c gm.map + +ugl: $(UGLOBJ) map.c + $(CC) $(CFLAGS) $(LDFLAGS) $(UGLOBJ) -o ugl clean: - -rm $(GMOBJ) $(MAPGENOBJ) gm mapgen map.c + -rm $(GMOBJ) $(MAPGENOBJ) $(UGLOBJ) gm mapgen map.c diff --git a/sys/sdl/gm2/test.ugl b/sys/sdl/gm2/test.ugl new file mode 100644 index 00000000..1a75404b --- /dev/null +++ b/sys/sdl/gm2/test.ugl @@ -0,0 +1,22 @@ + +proc main + if print(0) + print(123) + else + print(999) + endif + print(test(777)) + print(add(3,4)) +endproc + +# expects one argument, which has to be removed with the pop function +# procedures always have to ensure to remove their args +# test expects one argument a(1) +proc test + locals 1 + a(2, a(1)) # store a(1) in local var a(2) + print(a(2)) # print local var a(2) + print(a(1)) # print argument a(1) + print(a(0)) # print return value a(0) (should be zero) + return(888) +endproc diff --git a/sys/sdl/gm2/ugl_arrays.c b/sys/sdl/gm2/ugl_arrays.c new file mode 100644 index 00000000..29ad28b9 --- /dev/null +++ b/sys/sdl/gm2/ugl_arrays.c @@ -0,0 +1,247 @@ + + +#include "ugl.h" +#include "ugl_bc.h" +#include +#include + +/* arrays & variables */ + + +#define UGL_MAX_BYTECODE_LEN (63*1024) +uint8_t ugl_bytecode_array[UGL_MAX_BYTECODE_LEN]; +uint16_t ugl_bytecode_len; + +#define UGL_MAX_LABEL_CNT 128 +char ugl_label_name[UGL_MAX_LABEL_CNT][UGL_MAX_IDENTIFIER_LEN+1]; +uint16_t ugl_label_bytecode_pos[UGL_MAX_LABEL_CNT]; /* position in the bytecode array */ +int ugl_label_cnt; + +/* procedures */ + +void ugl_AddBytecode(uint8_t x) +{ + ugl_bytecode_array[ugl_bytecode_len] = x; + ugl_bytecode_len++; +} + +void ugl_InitBytecode(void) +{ + ugl_bytecode_len = 0; + ugl_AddBytecode(BC_CMD_RETURN_FROM_PROCEDURE); +} + +/* +extern uint8_t ugl_bytecode_array[]; +void ugl_ExecBytecode(void) +{ + bc_t bc; + bc_exec(&bc, ugl_bytecode_array, 0); +} +*/ + + +void ugl_CheckForAllLabelsDefined(void) +{ + int i; + for( i = 0; i < ugl_label_cnt; i++ ) + { + if ( ugl_label_bytecode_pos[ugl_label_cnt] == 0x0ffff ) + { + ugl_err("undefined label '%s'", ugl_label_name[i] ); + } + } +} + +void ugl_ResolveSymbols(void) +{ + uint8_t *code = ugl_bytecode_array; + uint8_t *dest = ugl_bytecode_array+ugl_bytecode_len; + uint16_t val; + uint8_t cmd; + + ugl_CheckForAllLabelsDefined(); + + ugl_glog("Resolve start=%p, end=%p", code, dest); + ugl_glog("Resolve bytecode len=%d", ugl_bytecode_len); + + while( code < dest ) + { + cmd = *code; + ugl_glog("Resolve pos=%p, cmd=%02x", code, cmd); + code++; + val = cmd; + val &=0x0f0; /* put upper four bit as upper 4bit of the 12bit value into val */ + val <<= 4; + switch(cmd&15) + { + case BC_CMD_LOAD_12BIT: + code++; + break; + case BC_CMD_CALL_BUILDIN: + code++; + break; + case BC_CMD_CALL_BUILDIN_POP_STACK: + code++; + break; + case BC_CMD_BRANCH: + val |= *code; + code++; + ugl_glog("Resolve BRANCH '%s' (idx=%d)", ugl_label_name[val], val); + val = ugl_GetLabelBytecodePos(val); + val = (val - (uint16_t)(code - ugl_bytecode_array)); + ugl_glog("Resolve BRANCH delta=0x%03x", val); + *(code-2) &= 0x0f; + *(code-2) |= (val >> 4) & 0x0f0; + *(code-1) = val & 255; + break; + case BC_CMD_POP_ARG_STACK: + break; + case BC_CMD_PUSH_ARG_STACK: + break; + case BC_CMD_CALL_PROCEDURE: + val = code[0]; + val <<= 8; + val |= code[1]; + + ugl_glog("Resolve CALL Procedre '%s' pos=%u", ugl_label_name[val], ugl_GetLabelBytecodePos(val)); + + val = ugl_GetLabelBytecodePos(val); + + *code = val>>8; + code++; + *code = val&255; + code++; + break; + + default: /* assume 0x0f, extended command */ + switch( cmd ) + { + case BC_CMD_LOAD_0: + break; + case BC_CMD_LOAD_1: + break; + case BC_CMD_LOAD_16BIT: + code++; + code++; + break; + case BC_CMD_RETURN_FROM_PROCEDURE: + break; + case BC_CMD_JUMP_NOT_ZERO: + case BC_CMD_JUMP_ZERO: + val = code[0]; + val <<= 8; + val |= code[1]; + + + ugl_glog("Resolve JUMP '%s'", ugl_label_name[val]); + + val = ugl_GetLabelBytecodePos(val); + + *code = val>>8; + code++; + *code = val&255; + code++; + + break; +#ifdef NOT_USED + case BC_CMD_CALL_PROCEDURE: + val = code[0]; + val <<= 8; + val |= code[1]; + + ugl_glog("Resolve CALL Procedre '%s' pos=%u", ugl_label_name[val], ugl_GetLabelBytecodePos(val)); + + val = ugl_GetLabelBytecodePos(val); + + *code = val>>8; + code++; + *code = val&255; + code++; + + break; +#endif +/* + case BC_CMD_POP_ARG_STACK: + break; +*/ + default: + ugl_err("Resolve: Unexpected command"); + break; + } + break; + } /* switch() */ + } /* while */ +} + + + + + +static int ugl_FindLabel(const char *name) +{ + int i; + for( i = 0; i < ugl_label_cnt; i++ ) + { + if (strcmp(name, ugl_label_name[i] ) == 0 ) + return i; + } + return -1; +} + +static int ugl_AddLabel(const char *name) +{ + strcpy(ugl_label_name[ugl_label_cnt], name); + ugl_label_bytecode_pos[ugl_label_cnt] = 0x0ffff; + ugl_label_cnt++; + if ( ugl_label_cnt >= UGL_MAX_LABEL_CNT ) + ugl_err("max number of labels reached, label=%s", name); + return ugl_label_cnt-1; +} + +int ugl_GetLabel(const char *name) +{ + int idx; + idx = ugl_FindLabel(name); + if ( idx >= 0 ) + return idx; + return ugl_AddLabel(name); +} + +void ugl_SetLabelBytecodePos(const char *name, uint16_t bytecode_pos) +{ + int idx; + idx = ugl_GetLabel(name); + if ( ugl_label_bytecode_pos[idx] != 0x0ffff ) + ugl_err("double definition of label '%s'", name); + ugl_label_bytecode_pos[idx] = bytecode_pos; +} + +uint16_t ugl_GetLabelBytecodePos(int idx) +{ + if ( ugl_label_bytecode_pos[idx] == 0x0ffff ) + ugl_err("undefined label '%s'", ugl_label_name[idx]); + return ugl_label_bytecode_pos[idx]; +} + +void ugl_WriteBytecodeCArray(FILE *fp, const char *name) +{ + uint16_t i; + fprintf(fp, "unsigned char %s[] =\n \"", name); + + i = 0; + while ( i < ugl_bytecode_len ) + { + fprintf(fp, "\\x%02x", ugl_bytecode_array[i]); + if ( i+1 == ugl_bytecode_len ) + { + break; + } + if ( (i & 0x0f) == 0x0f ) + { + fprintf(fp, "\"\n \""); + } + i++; + } + fprintf(fp, "\";\n\n"); +} \ No newline at end of file diff --git a/sys/sdl/gm2/ugl_bc.c b/sys/sdl/gm2/ugl_bc.c new file mode 100644 index 00000000..b11bfb5c --- /dev/null +++ b/sys/sdl/gm2/ugl_bc.c @@ -0,0 +1,414 @@ +/* + + ugl_bc.c + + items can be at three places + 1) map + 2) inventory + 3) hero + + map --> inventory take + inventory --> map drop + inventory --> hero equip + hero --> inventory unequip + hero --> map drop + + + inputs: + hDir() // direction into which the hero wants to walk, had waked or looks + iDir() // direction into which the item/creatue/missel wants to go, went or looks + hX() // hero X position + hY() // hero Y position + posByH // set current position to the position of the hero + posByI // set current position to the position of the current item + posAppyDir(dir) // change the possition going one step into the specified direction + +*/ + +#include "ugl_bc.h" +#include +#include + +#ifndef UGL_TEST +#include "item.h" +#include "map.h" +#endif + + + +void bc_push_on_arg_stack(bc_t *bc, uint16_t val) +{ + bc->arg_stack[bc->arg_stack_pointer] = val; + bc->arg_stack_pointer++; +} + +uint16_t bc_pop_from_arg_stack(bc_t *bc) +{ + assert( bc->arg_stack_pointer > 0 ); + bc->arg_stack_pointer--; + return bc->arg_stack[bc->arg_stack_pointer] ; +} + +void bc_duplicate_arg_stack_top_value(bc_t *bc) +{ + bc->arg_stack[bc->arg_stack_pointer] = bc->arg_stack[bc->arg_stack_pointer-1]; + bc->arg_stack_pointer++; +} + +void bc_push_on_return_stack(bc_t *bc, uint16_t val) +{ + bc->return_stack[bc->return_stack_pointer] = val; + bc->return_stack_pointer++; +} + +uint16_t bc_pop_from_return_stack(bc_t *bc) +{ + assert( bc->return_stack_pointer > 0 ); + bc->return_stack_pointer--; + return bc->return_stack[bc->return_stack_pointer]; +} + + +uint16_t bc_get_value(uint8_t *code) +{ + uint16_t val; + val = *code; + code++; + val <<= 8; + val |= *code; + code++; + return val; +} + +void bc_init(bc_t *bc) +{ + bc->arg_stack_pointer = 0; + bc->return_stack_pointer = 0; +} + +#define BC_DBG_OUT_POS(pos) printf("%05d ", (int)(pos)) +#define BC_DBG_OUT_HEX(c) printf("0x%02x ", (int)(c)) +#define BC_DBG_OUT_STR(str) printf("%s ", (str)) +#define BC_DBG_OUT_NUM(n) printf("%d ", (int)(n)) +#define BC_DBG_OUT_NUM3(n) printf("%03d ", (int)(n)) +#define BC_DBG_OUT_CR() printf("\n") + +void bc_exec(bc_t *bc, uint8_t *code, uint16_t pos) +{ + uint16_t val; + uint8_t cmd; + + bc_init(bc); + bc->code = code; + bc->code_pos = pos; + + for(;;) + { + cmd = bc->code[bc->code_pos]; + BC_DBG_OUT_POS(bc->code_pos); + BC_DBG_OUT_NUM3(bc->arg_stack_pointer); + BC_DBG_OUT_HEX(cmd); + bc->code_pos++; + val = cmd; + val &=0x0f0; /* put upper four bit as upper 4bit of the 12bit value into val */ + val <<= 4; + switch(cmd&15) + { + case BC_CMD_LOAD_12BIT: + BC_DBG_OUT_STR("LOAD12"); + val |= bc->code[bc->code_pos]; + BC_DBG_OUT_NUM(val); + bc->code_pos++; + bc_push_on_arg_stack(bc, val); + BC_DBG_OUT_CR(); + break; + case BC_CMD_CALL_BUILDIN: + BC_DBG_OUT_STR("CALL BUILDIN"); + val |= bc->code[bc->code_pos]; + BC_DBG_OUT_NUM(val); + bc->code_pos++; + BC_DBG_OUT_CR(); + bc_buildin_list[val](bc); + break; + case BC_CMD_CALL_BUILDIN_POP_STACK: + BC_DBG_OUT_STR("CALL BUILDIN POP ARG STACK"); + val |= bc->code[bc->code_pos]; + BC_DBG_OUT_NUM(val); + bc->code_pos++; + BC_DBG_OUT_CR(); + bc_buildin_list[val](bc); + bc_pop_from_arg_stack(bc); + break; + case BC_CMD_BRANCH: + BC_DBG_OUT_STR("BRANCH"); + val |= bc->code[bc->code_pos]; + bc->code_pos++; + if ( val < 0x0800 ) + { + bc->code_pos += val; + } + else + { + val = 0x1000 - val; + bc->code_pos -= val; + } + BC_DBG_OUT_POS(bc->code_pos); + BC_DBG_OUT_CR(); + case BC_CMD_POP_ARG_STACK: + cmd >>= 4; /* in this case we need the lower 4 bit */ + BC_DBG_OUT_STR("POP ARG STACK"); + cmd++; /* cmd is reused as a counter for the number of stack pops */ + BC_DBG_OUT_NUM(cmd); + do + { + bc_pop_from_arg_stack(bc); + cmd--; + } while( cmd > 0 ); + BC_DBG_OUT_CR(); + break; + case BC_CMD_PUSH_ARG_STACK: + cmd >>= 4; /* in this case we need the lower 4 bit */ + BC_DBG_OUT_STR("PUSH ARG STACK"); + cmd++; /* cmd is reused as a counter for the number of stack pops */ + BC_DBG_OUT_NUM(cmd); + do + { + bc_push_on_arg_stack(bc, 0); + cmd--; + } while( cmd > 0 ); + BC_DBG_OUT_CR(); + break; + case BC_CMD_CALL_PROCEDURE: + BC_DBG_OUT_STR("CALL PROC"); + cmd >>= 4; /* in this case we need the lower 4 bit--> number of args */ + BC_DBG_OUT_NUM(cmd); /* output number of args */ + + val = bc->code[bc->code_pos]; + bc->code_pos++; + val <<= 8; + val |= bc->code[bc->code_pos]; + bc->code_pos++; + + bc_push_on_return_stack(bc, bc->code_pos); /* return position */ + bc_push_on_return_stack(bc, bc->arg_stack_pointer - cmd -1); /* store the start pos of the return value and the args */ + bc->code_pos = val; + BC_DBG_OUT_NUM(bc->code_pos); + BC_DBG_OUT_CR(); + + break; + default: /* assume 0x0f, extended command */ + switch( cmd ) + { + case BC_CMD_LOAD_0: + BC_DBG_OUT_STR("LOAD#0"); + bc_push_on_arg_stack(bc, 0); + BC_DBG_OUT_CR(); + break; + case BC_CMD_LOAD_1: + BC_DBG_OUT_STR("LOAD#1"); + bc_push_on_arg_stack(bc, 1); + BC_DBG_OUT_CR(); + break; + case BC_CMD_LOAD_16BIT: + BC_DBG_OUT_STR("LOAD16"); + val = bc->code[bc->code_pos]; + bc->code_pos++; + val <<= 8; + val |= bc->code[bc->code_pos]; + bc->code_pos++; + bc_push_on_arg_stack(bc, val); + BC_DBG_OUT_NUM(val); + BC_DBG_OUT_CR(); + break; + case BC_CMD_RETURN_FROM_PROCEDURE: + BC_DBG_OUT_STR("RETURN to"); + if ( bc->return_stack_pointer == 0 ) + { + BC_DBG_OUT_STR("exit"); + BC_DBG_OUT_CR(); + + BC_DBG_OUT_STR("arg stack: "); + BC_DBG_OUT_NUM(bc->arg_stack_pointer); + BC_DBG_OUT_CR(); + BC_DBG_OUT_STR("return stack: "); + BC_DBG_OUT_NUM(bc->return_stack_pointer); + BC_DBG_OUT_CR(); + return; /* stop execution */ + } + //bc_push_on_arg_stack(bc, bc_pop_from_return_stack(bc)); /* copy return value on arg stack */ + bc->arg_stack_pointer = bc_pop_from_return_stack(bc) + 1; /* restore the arg stack pointer, leave return value on stack */ + bc->code_pos = bc_pop_from_return_stack(bc); + BC_DBG_OUT_NUM(bc->code_pos); + BC_DBG_OUT_CR(); + break; + case BC_CMD_JUMP_NOT_ZERO: + BC_DBG_OUT_STR("JUMP NZ"); + val = bc->code[bc->code_pos]; + bc->code_pos++; + val <<= 8; + val |= bc->code[bc->code_pos]; + bc->code_pos++; + + if ( bc_pop_from_arg_stack(bc) != 0 ) + bc->code_pos = val; + break; + BC_DBG_OUT_NUM(bc->code_pos); + BC_DBG_OUT_CR(); + case BC_CMD_JUMP_ZERO: + BC_DBG_OUT_STR("JUMP Z"); + val = bc->code[bc->code_pos]; + bc->code_pos++; + val <<= 8; + val |= bc->code[bc->code_pos]; + bc->code_pos++; + + if ( bc_pop_from_arg_stack(bc) == 0 ) + bc->code_pos = val; + BC_DBG_OUT_NUM(bc->code_pos); + BC_DBG_OUT_CR(); + break; + case BC_CMD_CALL_PROCEDURE: + BC_DBG_OUT_STR("CALL PROC"); + val = bc->code[bc->code_pos]; + bc->code_pos++; + val <<= 8; + val |= bc->code[bc->code_pos]; + bc->code_pos++; + + bc_push_on_return_stack(bc, bc->code_pos); /* return position */ + bc_push_on_return_stack(bc, 0); /* return value */ + bc->code_pos = val; + BC_DBG_OUT_NUM(bc->code_pos); + BC_DBG_OUT_CR(); + + break; +/* + case BC_CMD_POP_ARG_STACK: + BC_DBG_OUT_STR("POP ARG STACK"); + BC_DBG_OUT_CR(); + bc_pop_from_arg_stack(bc); + break; +*/ + default: + break; + } + break; + } /* switch() */ + } /* for(;;) */ + +} + + +/*======================================================*/ + +/* put top of stack into register a, reduce stack */ +//void bc_pop_a(bc_t *bc) +//{ +// bc->stack_pointer--; +// bc->a = bc->stack[bc->stack_pointer]; +//} + +/*======================================================*/ + +/* return a pointer to a variable on the arg stack within the current stack frame */ +/* pos = 0 is the return value of a user function, pos = 1... are the args for that function */ +uint16_t *bc_get_stack_frame_address(bc_t *bc, uint8_t pos) +{ + return bc->arg_stack + bc->return_stack[bc->return_stack_pointer-1] + pos ; +} + +void bc_fn_nop(bc_t *bc) +{ + bc_push_on_arg_stack(bc, 0); +} + +/* description: "return" sets the return value of a procedure. If used inside an expresion, it returns its argument */ +/* assign return value for a user defined function */ +/* identical to arg(0) */ +void bc_fn_return(bc_t *bc) +{ + bc_duplicate_arg_stack_top_value(bc); /* goal is to leave a value on the stack */ + *bc_get_stack_frame_address(bc, 0) = bc_pop_from_arg_stack(bc); + + /* + v = bc_pop_from_arg_stack(bc); + bc_push_on_arg_stack(bc, v); + bc_pop_from_return_stack(bc); + bc_push_on_return_stack(bc, v); + */ +} + + + +void bc_fn_print(bc_t *bc) +{ + bc_duplicate_arg_stack_top_value(bc); /* goal is to leave a value on the stack */ + printf("%u\n", bc_pop_from_arg_stack(bc)); +} + +/* return an argument of a user defined procedure */ +void bc_fn_arg1(bc_t *bc) +{ + bc_push_on_arg_stack(bc, *bc_get_stack_frame_address(bc, bc_pop_from_arg_stack(bc))); +} + +/* remove the top element from the stack and return the same */ +void bc_fn_arg2(bc_t *bc) +{ + uint16_t v = bc_pop_from_arg_stack(bc); /* the value, which should be assigned */ + *bc_get_stack_frame_address(bc, bc_pop_from_arg_stack(bc)) = v; + bc_push_on_arg_stack(bc, v); /* push the value back on the stack */ +} + + + +void bc_fn_add(bc_t *bc) +{ + uint16_t v; + v = bc_pop_from_arg_stack(bc); + v += bc_pop_from_arg_stack(bc); + bc_push_on_arg_stack(bc, v); +} + +#ifndef UGL_TEST +pos_t bc_pos; +#endif + +void bc_fn_setPos(bc_t *bc) +{ + uint8_t x, y; + y = bc_pop_from_arg_stack(bc); + x = bc_pop_from_arg_stack(bc); +#ifndef UGL_TEST + bc_pos.x = x; + bc_pos.y = y; +#endif + bc_push_on_arg_stack(bc, 0); +} + +void bc_fn_setItemPos(bc_t *bc) +{ + uint8_t i; + i = bc_pop_from_arg_stack(bc); +#ifndef UGL_TEST + pool_GetItem(i)->pos = bc_pos; + printf("item %d new x=%d y=%d\n", i, bc_pos.x, bc_pos.y); +#endif + bc_push_on_arg_stack(bc, i); +} + + +/*======================================================*/ +bc_buildin_fn bc_buildin_list[] = +{ + /* 0 */ bc_fn_nop, + /* 1 */ bc_fn_return, + /* 2 */ bc_fn_arg1, /* one argument */ + /* 3 */ bc_fn_arg2, /* two arguments */ + /* 4 */ bc_fn_add, + /* 5 */ bc_fn_print, + /* 6 */ bc_fn_setPos, /* two args: x & y*/ + /* 7 */ bc_fn_setItemPos, /* one args: item */ +}; + + diff --git a/sys/sdl/gm2/ugl_error.c b/sys/sdl/gm2/ugl_error.c new file mode 100644 index 00000000..ca4ecea9 --- /dev/null +++ b/sys/sdl/gm2/ugl_error.c @@ -0,0 +1,43 @@ + + +#include "ugl.h" +#include +#include + +int ugl_current_input_line; +int ugl_is_suppress_log = 0; + + +void ugl_err(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + vprintf(fmt, va); + printf("\n"); + va_end(va); + exit(1); +} + +void ugl_plog(const char *fmt, ...) +{ + va_list va; + if ( ugl_is_suppress_log != 0 ) + return; + va_start(va, fmt); + printf("%d: ", ugl_current_input_line); + vprintf(fmt, va); + printf("\n"); + va_end(va); +} + +/* generic log */ +void ugl_glog(const char *fmt, ...) +{ + va_list va; + if ( ugl_is_suppress_log != 0 ) + return; + va_start(va, fmt); + vprintf(fmt, va); + printf("\n"); + va_end(va); +} \ No newline at end of file diff --git a/sys/sdl/gm2/ugl_main.c b/sys/sdl/gm2/ugl_main.c new file mode 100644 index 00000000..1fa854ae --- /dev/null +++ b/sys/sdl/gm2/ugl_main.c @@ -0,0 +1,55 @@ + + +#include "ugl.h" +#include "ugl_bc.h" +#include + +#define UGL_MAX_INPUT_LINE_LEN 1024 +FILE *ugl_input_fp; +char ugl_input_line[UGL_MAX_INPUT_LINE_LEN]; + + +int ugl_read_fp(void) +{ + const char *s; + ugl_current_input_line = 0; + for(;;) + { + if ( fgets(ugl_input_line, UGL_MAX_INPUT_LINE_LEN, ugl_input_fp) == NULL ) + break; + ugl_current_input_line++; + s = &(ugl_input_line[0]); + if ( ugl_read_line(&s) == 0 ) + return 0; + } + return 1; +} + +int ugl_read_filename(const char *name) +{ + ugl_input_fp = fopen(name, "r"); + if ( ugl_input_fp == NULL ) + return 0; + printf("file '%s'\n", name); + if ( ugl_read_fp() == 0 ) + return fclose(ugl_input_fp), 0; + fclose(ugl_input_fp); + return 1; +} + +extern uint8_t ugl_bytecode_array[]; +void ugl_ExecBytecode(void) +{ + bc_t bc; + bc_exec(&bc, ugl_bytecode_array, 0); +} + +int main(void) +{ + ugl_InitBytecode(); + ugl_read_filename("test.ugl"); + ugl_ResolveSymbols(); + ugl_ExecBytecode(); + ugl_WriteBytecodeCArray(stdout, "code"); + +} \ No newline at end of file diff --git a/sys/sdl/gm2/ugl_parse.c b/sys/sdl/gm2/ugl_parse.c new file mode 100644 index 00000000..1a3fe699 --- /dev/null +++ b/sys/sdl/gm2/ugl_parse.c @@ -0,0 +1,528 @@ +/* + + ugl_file.c + + microcontroller game language + + bytecode + return from procedure... all procedure leave a 16 bit value on the stack + jump probably only for if/loop + pop stack and jump on zero + pop stack and jump on not zero + call buildin procedure + call bytecode procedure + call toplevel buildin procedure + call toplevel bytecode procedure + push constant 16 bit value on stack + pop constant value from stack + + + + proc Starts a new procedure. Procedures must be terminated with "endproc" + endproc End a procedure + locals Define the specified number of local variables, acces with arg(n), where n is between no_of_args+1 and no_of_args+ +*/ +#include +#include +#include "ugl.h" +#include "ugl_bc.h" + + +long ugl_current_local_variables = 0; +long ugl_current_args = 0; + + +#define UGL_MAX_INDENT 64 + +#define UGL_INDENT_TYPE_PROC 0 +#define UGL_INDENT_TYPE_IF 1 +#define UGL_INDENT_TYPE_LOOP 2 + +int ugl_indent_level; +int ugl_indent_type[UGL_MAX_INDENT]; +char ugl_indent_identifier[UGL_MAX_INDENT][UGL_MAX_IDENTIFIER_LEN+1]; + +struct ugl_buildin_cmd_struct +{ + int code; + const char *name; + int args; +}; + +struct ugl_buildin_cmd_struct ugl_buildin_cmd_list[] = { + { /* code=*/ 0, /* name=*/ "nop", /* args=*/ 0}, + { /* code=*/ 1, /* name=*/ "return", /* args=*/ 1 }, /* assign the return value of a user defined function */ + { /* code=*/ 2, /* name=*/ "a", /* args=*/ 1 }, /* return the value of the n-th argument of a user defined function */ + { /* code=*/ 3, /* name=*/ "a", /* args=*/ 2 }, /* reassign the value of the n-th argument of a user defined function */ + { /* code=*/ 4, /* name=*/ "add", /* args=*/ 2 }, + { /* code=*/ 5, /* name=*/ "print", /* args=*/ 1 }, + { /* code=*/ 6, /* name=*/ "setPos", /* args=*/ 2 }, + { /* code=*/ 7, /* name=*/ "setItemPos", /* args=*/ 1 }, +}; + + + +void ugl_IncIndent(int type) +{ + if ( ugl_indent_level > UGL_MAX_INDENT ) + ugl_err("max indent level reached"); + ugl_indent_type[ugl_indent_level] = type; + ugl_indent_level++; +} + +void ugl_DecIndent(int type) +{ + if ( ugl_indent_level == 0 ) + ugl_err("can not decrement indent level, requested type = %d", type); + ugl_indent_level--; + if (ugl_indent_type[ugl_indent_level] != type ) + ugl_err("block end mismatch, %d != %d", ugl_indent_type[ugl_indent_level] , type ); +} + +static void skip_space(const char **s) +{ + for(;;) + { + if ( **s == '#' ) + { + while( **s != '\0' ) + (*s)++; + break; + } + if ( **s == '\0' ) + break; + if ( **s > ' ' ) + break; + (*s)++; + } +} + +static long get_dec(const char **s) +{ + long v = 0; + for(;;) + { + if ( (**s) >= '0' && (**s) <= '9' ) + { + v*=10; + v+= (**s)-'0'; + (*s)++; + } + else + { + break; + } + } + skip_space(s); + return v; +} + +static long get_hex(const char **s) +{ + long v = 0; + for(;;) + { + if ( (**s) >= '0' && (**s) <= '9' ) + { + v*=16; + v+= (**s)-'0'; + (*s)++; + } + else if ( (**s) >= 'a' && (**s) <= 'f' ) + { + v*=16; + v+= (**s)-'a'+10; + (*s)++; + } + else if ( (**s) >= 'A' && (**s) <= 'F' ) + { + v*=16; + v+= (**s)-'A'+10; + (*s)++; + } + else + { + break; + } + } + skip_space(s); + return v; +} + +static long get_ascii(const char **s) +{ + long v = 0; + v = **s; + (*s)++; + skip_space(s); + return v; +} + + +static long get_num(const char **s) +{ + if ( (**s) == '$' ) + { + (*s)++; + return get_hex(s); + } + if ( (**s) == '\'' ) + { + (*s)++; + return get_ascii(s); + } + + return get_dec(s); +} + +static const char *get_identifier(const char **s) +{ + static char buf[UGL_MAX_IDENTIFIER_LEN+1]; + int c; + int i = 0; + buf[0] = '\0'; + for(;;) + { + c = **s; + if ( c < 'A' ) + break; + if ( i > UGL_MAX_IDENTIFIER_LEN ) + break; + buf[i++] = c; + buf[i] = '\0'; + (*s)++; + } + skip_space(s); + return buf; +} + +/*======================================================*/ +/* code generator sub procedures */ + +void ugl_bytecode_buildin_procedure(const char *name, int idx, int is_toplevel) +{ + ugl_plog("BC %scall buildin '%s'", is_toplevel?"toplevel ":"", name); + + if ( is_toplevel == 0 ) + { + ugl_AddBytecode(BC_CMD_CALL_BUILDIN | ((idx&0x0f00)>>4)); + ugl_AddBytecode(idx&0xff); + } + else + { + ugl_AddBytecode(BC_CMD_CALL_BUILDIN_POP_STACK | ((idx&0x0f00)>>4)); + ugl_AddBytecode(idx&0xff); + } +} + +void ugl_bytecode_call_procedure(const char *name, int is_toplevel, int arg_cnt) +{ + uint16_t idx; + + ugl_plog("BC call %sbytecode '%s' with %d arg(s)", is_toplevel?"toplevel ":"", name, arg_cnt); + idx = ugl_GetLabel(name); + + ugl_AddBytecode(BC_CMD_CALL_PROCEDURE | (arg_cnt<<4)); + + ugl_AddBytecode(idx>>8); + ugl_AddBytecode(idx&0x0ff); + + if ( is_toplevel != 0 ) + { + ugl_AddBytecode(BC_CMD_POP_ARG_STACK ); // remove the return value from the stack + } + +#ifdef NOTUSED + if ( is_toplevel != 0 ) + { + arg_cnt++; // one more element on the stack (return value) has to be removed, if this is called from top level + } + + while( arg_cnt > 16 ) + { + ugl_AddBytecode(BC_CMD_POP_ARG_STACK | 0x0f0); + arg_cnt -= 16; + } + if ( arg_cnt > 0 ) + { + arg_cnt--; + ugl_AddBytecode(BC_CMD_POP_ARG_STACK | (arg_cnt<<4)); + } +#endif +} + +void ugl_bytecode_reserve_arg_stack(int arg_cnt) +{ + while( arg_cnt > 16 ) + { + ugl_AddBytecode(BC_CMD_PUSH_ARG_STACK | 0x0f0); + arg_cnt -= 16; + } + if ( arg_cnt > 0 ) + { + arg_cnt--; + ugl_AddBytecode(BC_CMD_PUSH_ARG_STACK | (arg_cnt<<4)); + } +} + +void ugl_bytecode_remove_arg_stack(int arg_cnt) +{ + while( arg_cnt > 16 ) + { + ugl_AddBytecode(BC_CMD_POP_ARG_STACK | 0x0f0); + arg_cnt -= 16; + } + if ( arg_cnt > 0 ) + { + arg_cnt--; + ugl_AddBytecode(BC_CMD_POP_ARG_STACK | (arg_cnt<<4)); + } +} + +void ugl_bytecode_constant_value(long num) +{ + ugl_plog("BC constant value %ld", num); + + if ( num == 0 ) + { + ugl_AddBytecode(BC_CMD_LOAD_0); + } + else if ( num == 1 ) + { + ugl_AddBytecode(BC_CMD_LOAD_1); + } + else if ( num <= 0x0fff ) + { + ugl_AddBytecode(BC_CMD_LOAD_12BIT | ((num&0x0f00)>>4)); + ugl_AddBytecode(num&0xff); + } + else + { + ugl_AddBytecode(BC_CMD_LOAD_16BIT ); + ugl_AddBytecode(num>>8); + ugl_AddBytecode(num&0x0ff); + } +} + +void ugl_bytecode_return_from_procedure(void) +{ + ugl_plog("BC return from procedure"); + ugl_AddBytecode(BC_CMD_RETURN_FROM_PROCEDURE ); +} + +void ugl_bytecode_branch(const char *s) +{ + int idx; + idx = ugl_GetLabel(s); + ugl_plog("BC branch, label %s, idx=%d", s, idx); + + ugl_AddBytecode(BC_CMD_BRANCH | ((idx&0x0f00)>>4)); + ugl_AddBytecode(idx&0xff); + + +} + +void ugl_bytecode_jmp_no_zero(const char *s) +{ + int idx; + idx = ugl_GetLabel(s); + ugl_plog("BC jump on not zero, label idx=%d", idx); + + ugl_AddBytecode(BC_CMD_JUMP_NOT_ZERO ); + ugl_AddBytecode(idx>>8); + ugl_AddBytecode(idx&0x0ff); +} + +void ugl_bytecode_jmp_zero(const char *s) +{ + int idx; + idx = ugl_GetLabel(s); + ugl_plog("BC jump on zero, label idx=%d", idx); + + ugl_AddBytecode(BC_CMD_JUMP_ZERO ); + ugl_AddBytecode(idx>>8); + ugl_AddBytecode(idx&0x0ff); +} + + +/*======================================================*/ + +int ugl_is_buildin_cmd(const char *name) +{ + int i, cnt; + cnt = sizeof(ugl_buildin_cmd_list)/sizeof(*ugl_buildin_cmd_list); + for( i = 0; i < cnt; i++ ) + { + if ( strcmp(ugl_buildin_cmd_list[i].name, name) == 0 ) + return 1; + } + return 0; +} + +void ugl_call_proc(const char *name, int is_toplevel, int arg_cnt) +{ + int i, cnt; + int ii; + cnt = sizeof(ugl_buildin_cmd_list)/sizeof(*ugl_buildin_cmd_list); + ii = cnt; + for( i = 0; i < cnt; i++ ) + { + if ( strcmp(ugl_buildin_cmd_list[i].name, name) == 0 ) + ii = i; + if ( strcmp(ugl_buildin_cmd_list[i].name, name) == 0 && ugl_buildin_cmd_list[i].args == arg_cnt) + break; + } + if ( i < cnt ) + { + ugl_bytecode_buildin_procedure(name, i, is_toplevel); + } + else + { + if ( ii != cnt ) + { + ugl_err("Buildin procedure '%s' expects differnt number of args", name); + } + else + { + ugl_bytecode_call_procedure(name, is_toplevel, arg_cnt); + } + } +} + +void ugl_parse_proc(const char **s, const char *id, int is_toplevel) +{ + char procname[UGL_MAX_IDENTIFIER_LEN]; + int arg_cnt = 0; + ugl_plog("parse procedure '%s'", id); + strcpy(procname, id); + if ( ugl_is_buildin_cmd(id) == 0 ) + { + /* if this is a buildin cmd, then do nothing: buildin code takes care on the return value */ + /* for custom procedures push a value on the arg stack for the return value, but do this only if this is not a toplevel procedure */ + ugl_bytecode_constant_value(0); /* return value will be 0 by default */ + } + + if ( **s == '(' ) + { + const char *name; + for(;;) + { + (*s)++; + skip_space(s); + + if ( **s == ')' ) + break; + + if ( (**s >= '0' && **s <= '9') || **s == '$' || **s == '\'' ) + { + ugl_bytecode_constant_value(get_num(s)); + } + else + { + name = get_identifier(s); + ugl_parse_proc(s, name, 0); + } + arg_cnt++; + if ( **s != ',' ) + break; + } + if ( **s != ')' ) + ugl_err("missing ')'"); + (*s)++; + skip_space(s); + ugl_call_proc(procname, is_toplevel, arg_cnt); + } + else + { + ugl_call_proc(procname, is_toplevel, 0); + } +} + +uint16_t uglStartNamelessProc(int args) +{ + ugl_current_local_variables = 0; + ugl_current_args = args; + if ( ugl_indent_level != 0 ) + ugl_err("nested procedures not allowed"); + ugl_IncIndent(UGL_INDENT_TYPE_PROC); + return ugl_bytecode_len; +} + +int ugl_read_line(const char **s) +{ + const char *id; + + skip_space(s); + if ( **s == '\0' ) + return 1; + + + id = get_identifier(s); + + if ( strcmp(id, "proc") == 0 ) + { + const char *name = get_identifier(s); + long args = get_num(s); + + ugl_plog("start procedure '%s' (args=%ld)", name, args); + + ugl_GetLabel(name); /* create a label for the procedure name */ + ugl_SetLabelBytecodePos(name, uglStartNamelessProc(args)); /* and set the label for it */ + + + } + else if ( strcmp(id, "endproc") == 0 ) + { + //ugl_bytecode_remove_arg_stack(ugl_current_local_variables); + ugl_DecIndent(UGL_INDENT_TYPE_PROC); + ugl_bytecode_return_from_procedure(); + ugl_current_local_variables = 0; + ugl_current_args = 0; + } + else if ( strcmp(id, "locals") == 0 ) + { + long n = get_num(s); + if ( ugl_current_local_variables != 0 ) + ugl_err("only one 'locals' command allowed"); + if ( ugl_indent_level != 1 ) + ugl_err("'locals': only toplevel call allowed"); /* it must not be inside loops or ifs */ + ugl_current_local_variables = n; + ugl_bytecode_reserve_arg_stack(ugl_current_local_variables); + } + else if ( strcmp(id, "if" ) == 0 ) + { + ugl_parse_proc(s, get_identifier(s), 0); + sprintf(ugl_indent_identifier[ugl_indent_level], ".if%d", ugl_bytecode_len); /* use the current bytecode position as unique identifier */ + ugl_bytecode_jmp_zero(ugl_indent_identifier[ugl_indent_level]); + ugl_IncIndent(UGL_INDENT_TYPE_IF); + + } + else if ( strcmp(id, "else" ) == 0 ) + { + char s[UGL_MAX_IDENTIFIER_LEN+1]; + sprintf(s, ".else%d", ugl_bytecode_len); /* use the current bytecode position as unique identifier */ + ugl_bytecode_branch(s); + + ugl_SetLabelBytecodePos(ugl_indent_identifier[ugl_indent_level-1], ugl_bytecode_len); + strcpy(ugl_indent_identifier[ugl_indent_level-1], s); + } + else if ( strcmp(id, "endif" ) == 0 ) + { + ugl_DecIndent(UGL_INDENT_TYPE_IF); + ugl_SetLabelBytecodePos(ugl_indent_identifier[ugl_indent_level], ugl_bytecode_len); + } + else + { + ugl_parse_proc(s, id, 1); + } + return 1; +} + +/* returns 0 if "endproc" is found */ +int uglReadLine(const char **s) +{ + ugl_read_line(s); + if ( ugl_indent_level == 0 ) + return 0; + return 1; +} diff --git a/tools/ugl/ugl_arrays.c b/tools/ugl/ugl_arrays.c index 6a4168ef..29ad28b9 100644 --- a/tools/ugl/ugl_arrays.c +++ b/tools/ugl/ugl_arrays.c @@ -32,6 +32,7 @@ void ugl_InitBytecode(void) } /* +extern uint8_t ugl_bytecode_array[]; void ugl_ExecBytecode(void) { bc_t bc; diff --git a/tools/ugl/ugl_main.c b/tools/ugl/ugl_main.c index 8d47a0a3..1fa854ae 100644 --- a/tools/ugl/ugl_main.c +++ b/tools/ugl/ugl_main.c @@ -1,6 +1,7 @@ #include "ugl.h" +#include "ugl_bc.h" #include #define UGL_MAX_INPUT_LINE_LEN 1024 @@ -36,6 +37,13 @@ int ugl_read_filename(const char *name) return 1; } +extern uint8_t ugl_bytecode_array[]; +void ugl_ExecBytecode(void) +{ + bc_t bc; + bc_exec(&bc, ugl_bytecode_array, 0); +} + int main(void) { ugl_InitBytecode();