This commit is contained in:
parent
b6d68ea357
commit
3f8715327c
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
}
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -32,6 +32,7 @@ void ugl_InitBytecode(void)
|
|||
}
|
||||
|
||||
/*
|
||||
extern uint8_t ugl_bytecode_array[];
|
||||
void ugl_ExecBytecode(void)
|
||||
{
|
||||
bc_t bc;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue