This commit is contained in:
olikraus 2017-07-18 20:14:25 +02:00
parent b6d68ea357
commit 3f8715327c
9 changed files with 1329 additions and 7 deletions

View File

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

22
sys/sdl/gm2/test.ugl Normal file
View File

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

247
sys/sdl/gm2/ugl_arrays.c Normal file
View File

@ -0,0 +1,247 @@
#include "ugl.h"
#include "ugl_bc.h"
#include <string.h>
#include <stdio.h>
/* 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");
}

414
sys/sdl/gm2/ugl_bc.c Normal file
View File

@ -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 <stdio.h>
#include <assert.h>
#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 */
};

43
sys/sdl/gm2/ugl_error.c Normal file
View File

@ -0,0 +1,43 @@
#include "ugl.h"
#include <stdio.h>
#include <stdlib.h>
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);
}

55
sys/sdl/gm2/ugl_main.c Normal file
View File

@ -0,0 +1,55 @@
#include "ugl.h"
#include "ugl_bc.h"
#include <stdio.h>
#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");
}

528
sys/sdl/gm2/ugl_parse.c Normal file
View File

@ -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 <name> Starts a new procedure. Procedures must be terminated with "endproc"
endproc End a procedure
locals <num> Define the specified number of local variables, acces with arg(n), where n is between no_of_args+1 and no_of_args+<num>
*/
#include <stdio.h>
#include <string.h>
#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;
}

View File

@ -32,6 +32,7 @@ void ugl_InitBytecode(void)
}
/*
extern uint8_t ugl_bytecode_array[];
void ugl_ExecBytecode(void)
{
bc_t bc;

View File

@ -1,6 +1,7 @@
#include "ugl.h"
#include "ugl_bc.h"
#include <stdio.h>
#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();