| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /*
-
- 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 },
- { /* code=*/ 8, /* name=*/ "setItemDir", /* args=*/ 2 },
- };
- 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;
- }
|