ugl
This commit is contained in:
parent
3207051a75
commit
4ec5caf5dc
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
|
||||
proc <name>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _UGL_H
|
||||
#define _UGL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
#define UGL_MAX_IDENTIFIER_LEN 63
|
||||
|
||||
|
||||
/* ugl_error.c */
|
||||
void ugl_err(const char *fmt, ...) __attribute__ ((noreturn));
|
||||
void ugl_plog(const char *fmt, ...);
|
||||
|
||||
|
||||
|
||||
/* ugl_arrays.c */
|
||||
extern uint16_t ugl_bytecode_len;
|
||||
|
||||
void ugl_InitBytecode(void);
|
||||
void ugl_AddBytecode(uint8_t x);
|
||||
void ugl_ExecBytecode(void);
|
||||
void ugl_ResolveSymbols(void);
|
||||
|
||||
int ugl_GetLabel(const char *name);
|
||||
void ugl_SetLabelBytecodePos(const char *name, uint16_t bytecode_pos);
|
||||
uint16_t ugl_GetLabelBytecodePos(int idx);
|
||||
|
||||
|
||||
/* ugl_file.c */
|
||||
extern int ugl_current_input_line;
|
||||
|
||||
int ugl_read_filename(const char *name);
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,180 @@
|
|||
|
||||
|
||||
#include "ugl.h"
|
||||
#include "ugl_bc.h"
|
||||
#include <string.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_InitBytecode(void)
|
||||
{
|
||||
ugl_bytecode_len = 0;
|
||||
}
|
||||
|
||||
void ugl_AddBytecode(uint8_t x)
|
||||
{
|
||||
ugl_bytecode_array[ugl_bytecode_len] = x;
|
||||
ugl_bytecode_len++;
|
||||
}
|
||||
|
||||
void ugl_ExecBytecode(void)
|
||||
{
|
||||
bc_t bc;
|
||||
bc_exec(&bc, ugl_bytecode_array);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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_plog("Resolve start=%p, end=%p", code, dest);
|
||||
ugl_plog("Resolve bytecode len=%d", ugl_bytecode_len);
|
||||
|
||||
while( code < dest )
|
||||
{
|
||||
cmd = *code;
|
||||
ugl_plog("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_plog("Resolve BRANCH '%s' (idx=%d)", ugl_label_name[val], val);
|
||||
val = ugl_GetLabelBytecodePos(val);
|
||||
val = (val - (uint16_t)(code - ugl_bytecode_array));
|
||||
ugl_plog("Resolve BRANCH delta=0x%03x", val);
|
||||
*(code-2) &= 0x0f;
|
||||
*(code-2) |= (val >> 4) & 0x0f0;
|
||||
*(code-1) = val & 255;
|
||||
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_plog("Resolve JUMP '%s'", ugl_label_name[val]);
|
||||
|
||||
val = ugl_GetLabelBytecodePos(val);
|
||||
|
||||
*code = val>>8;
|
||||
code++;
|
||||
*code = val&255;
|
||||
code++;
|
||||
|
||||
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];
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
|
||||
ugl_bc.c
|
||||
|
||||
*/
|
||||
|
||||
#include "ugl_bc.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void bc_push_on_stack(bc_t *bc, uint16_t val)
|
||||
{
|
||||
bc->stack[bc->stack_pointer] = val;
|
||||
bc->stack_pointer++;
|
||||
}
|
||||
|
||||
uint16_t bc_pop_from_stack(bc_t *bc)
|
||||
{
|
||||
bc->stack_pointer--;
|
||||
return bc->stack[bc->stack_pointer] ;
|
||||
}
|
||||
|
||||
void bc_duplicate_stack_top_value(bc_t *bc)
|
||||
{
|
||||
bc->stack[bc->stack_pointer] = bc->stack[bc->stack_pointer-1];
|
||||
bc->stack_pointer++;
|
||||
}
|
||||
|
||||
void bc_exec(bc_t *bc, uint8_t *code)
|
||||
{
|
||||
uint16_t val;
|
||||
uint8_t cmd;
|
||||
bc->stack_pointer = 0;
|
||||
bc->code = code;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cmd = *code;
|
||||
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:
|
||||
val |= *code;
|
||||
code++;
|
||||
bc_push_on_stack(bc, val);
|
||||
break;
|
||||
case BC_CMD_CALL_BUILDIN:
|
||||
val |= *code;
|
||||
code++;
|
||||
bc_buildin_list[val](bc);
|
||||
break;
|
||||
case BC_CMD_CALL_BUILDIN_POP_STACK:
|
||||
val |= *code;
|
||||
code++;
|
||||
bc_buildin_list[val](bc);
|
||||
bc_pop_from_stack(bc);
|
||||
break;
|
||||
case BC_CMD_BRANCH:
|
||||
val |= *code;
|
||||
code++;
|
||||
if ( val < 0x0800 )
|
||||
{
|
||||
code += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = 0x1000 - val;
|
||||
code -= val;
|
||||
}
|
||||
|
||||
default: /* assume 0x0f, extended command */
|
||||
switch( cmd )
|
||||
{
|
||||
case BC_CMD_LOAD_0:
|
||||
bc_push_on_stack(bc, 0);
|
||||
break;
|
||||
case BC_CMD_LOAD_1:
|
||||
bc_push_on_stack(bc, 1);
|
||||
break;
|
||||
case BC_CMD_LOAD_16BIT:
|
||||
val = *code;
|
||||
code++;
|
||||
val <<= 8;
|
||||
val |= *code;
|
||||
code++;
|
||||
bc_push_on_stack(bc, val);
|
||||
break;
|
||||
case BC_CMD_RETURN_FROM_PROCEDURE:
|
||||
if ( bc->stack_pointer == 0 )
|
||||
return; /* stop execution */
|
||||
code = bc->code+bc_pop_from_stack(bc);
|
||||
break;
|
||||
case BC_CMD_JUMP_NOT_ZERO:
|
||||
val = *code;
|
||||
code++;
|
||||
val <<= 8;
|
||||
val |= *code;
|
||||
code++;
|
||||
|
||||
if ( bc_pop_from_stack(bc) != 0 )
|
||||
code = bc->code+val;
|
||||
break;
|
||||
|
||||
|
||||
case BC_CMD_JUMP_ZERO:
|
||||
val = *code;
|
||||
code++;
|
||||
val <<= 8;
|
||||
val |= *code;
|
||||
code++;
|
||||
|
||||
if ( bc_pop_from_stack(bc) == 0 )
|
||||
code = bc->code+val;
|
||||
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];
|
||||
//}
|
||||
|
||||
/*======================================================*/
|
||||
|
||||
|
||||
void bc_fn_nop(bc_t *bc)
|
||||
{
|
||||
bc_push_on_stack(bc, 0);
|
||||
}
|
||||
|
||||
void bc_fn_print(bc_t *bc)
|
||||
{
|
||||
bc_duplicate_stack_top_value(bc); /* goal is to leave a value on the stack */
|
||||
printf("%u\n", bc_pop_from_stack(bc));
|
||||
}
|
||||
|
||||
/*======================================================*/
|
||||
bc_buildin_fn bc_buildin_list[] =
|
||||
{
|
||||
/* 0 */ bc_fn_nop,
|
||||
/* 1 */ bc_fn_print
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
|
||||
ugl_bc.h
|
||||
|
||||
bytecode interpreter
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _UGL_BC_H
|
||||
#define _UGL_BC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BC_STACK_SIZE 64
|
||||
|
||||
struct bc_struct
|
||||
{
|
||||
uint8_t *code;
|
||||
uint8_t stack_pointer; /* starts at 0 and grows */
|
||||
uint16_t stack[BC_STACK_SIZE];
|
||||
};
|
||||
typedef struct bc_struct bc_t;
|
||||
|
||||
typedef void (*bc_buildin_fn)(bc_t *bc);
|
||||
extern bc_buildin_fn bc_buildin_list[];
|
||||
|
||||
/* lower 4 bit: 0, upper 4 bit + next byte --> 12 bit value */
|
||||
#define BC_CMD_LOAD_12BIT (0x00)
|
||||
|
||||
/* lower 4 bit: 1, upper 4 bit + next byte --> 12 bit value */
|
||||
#define BC_CMD_CALL_BUILDIN (0x01)
|
||||
|
||||
/* lower 4 bit: 2, upper 4 bit + next byte --> 12 bit value */
|
||||
#define BC_CMD_CALL_BUILDIN_POP_STACK (0x02)
|
||||
|
||||
/* lower 4 bit: 2, upper 4 bit + next byte --> 12 bit relative adr */
|
||||
#define BC_CMD_BRANCH (0x03)
|
||||
|
||||
/* lower 4 bit: 15, upper 4 bit: 0 --> put 0 on stack */
|
||||
#define BC_CMD_LOAD_0 (0x0f)
|
||||
/* lower 4 bit: 15, upper 4 bit: 1 --> put 1 on stack */
|
||||
#define BC_CMD_LOAD_1 (0x1f)
|
||||
/* lower 4 bit: 15, upper 4 bit: 2 --> but 16 bit value on stack, order: high byte, low byte */
|
||||
#define BC_CMD_LOAD_16BIT (0x2f)
|
||||
/* lower 4 bit: 15, upper 4 bit: 3 */
|
||||
#define BC_CMD_RETURN_FROM_PROCEDURE (0x3f)
|
||||
/* lower 4 bit: 15, upper 4 bit: 4 --> adr are next 16 bit*/
|
||||
#define BC_CMD_JUMP_NOT_ZERO (0x4f)
|
||||
/* lower 4 bit: 15, upper 4 bit: 5 --> adr are next 16 bit*/
|
||||
#define BC_CMD_JUMP_ZERO (0x05f)
|
||||
|
||||
void bc_exec(bc_t *bc, uint8_t *code);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
#include "ugl.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
va_start(va, fmt);
|
||||
printf("%d: ", ugl_current_input_line);
|
||||
vprintf(fmt, va);
|
||||
printf("\n");
|
||||
va_end(va);
|
||||
}
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
|
||||
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
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ugl.h"
|
||||
#include "ugl_bc.h"
|
||||
|
||||
|
||||
#define UGL_MAX_INPUT_LINE_LEN 1024
|
||||
FILE *ugl_input_fp;
|
||||
int ugl_current_input_line;
|
||||
char ugl_input_line[UGL_MAX_INPUT_LINE_LEN];
|
||||
|
||||
|
||||
#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=*/ "print", /* 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;
|
||||
}
|
||||
|
||||
/*======================================================*/
|
||||
|
||||
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)
|
||||
{
|
||||
ugl_plog("BC call %sbytecode '%s'", is_toplevel?"toplevel ":"", name);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*======================================================*/
|
||||
|
||||
void ugl_call_proc(const char *name, int is_toplevel)
|
||||
{
|
||||
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 )
|
||||
break;
|
||||
}
|
||||
if ( i < cnt )
|
||||
{
|
||||
ugl_bytecode_buildin_procedure(name, i, is_toplevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
ugl_bytecode_call_procedure(name, is_toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
void ugl_parse_proc(const char **s, const char *id, int is_toplevel)
|
||||
{
|
||||
char procname[UGL_MAX_IDENTIFIER_LEN];
|
||||
ugl_plog("parse procedure '%s'", id);
|
||||
strcpy(procname, id);
|
||||
if ( **s == '(' )
|
||||
{
|
||||
const char *name;
|
||||
for(;;)
|
||||
{
|
||||
(*s)++;
|
||||
skip_space(s);
|
||||
|
||||
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);
|
||||
}
|
||||
if ( **s != ',' )
|
||||
break;
|
||||
}
|
||||
if ( **s != ')' )
|
||||
ugl_err("missing ')'");
|
||||
(*s)++;
|
||||
skip_space(s);
|
||||
ugl_call_proc(procname, is_toplevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
ugl_call_proc(procname, is_toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ugl_plog("start procedure '%s'", name);
|
||||
if ( ugl_indent_level != 0 )
|
||||
ugl_err("nested procedures not allowed");
|
||||
ugl_GetLabel(name); /* just create a label for the procedure name */
|
||||
ugl_IncIndent(UGL_INDENT_TYPE_PROC);
|
||||
}
|
||||
else if ( strcmp(id, "endproc") == 0 )
|
||||
{
|
||||
ugl_DecIndent(UGL_INDENT_TYPE_PROC);
|
||||
ugl_bytecode_return_from_procedure();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
|
||||
#include "ugl.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ugl_InitBytecode();
|
||||
ugl_read_filename("test.ugl");
|
||||
ugl_ResolveSymbols();
|
||||
ugl_ExecBytecode();
|
||||
|
||||
}
|
Loading…
Reference in New Issue