This commit is contained in:
olikraus 2017-07-02 17:00:50 +02:00
parent 3207051a75
commit 4ec5caf5dc
7 changed files with 893 additions and 0 deletions

44
tools/ugl/ugl.h Normal file
View File

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

180
tools/ugl/ugl_arrays.c Normal file
View File

@ -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];
}

156
tools/ugl/ugl_bc.c Normal file
View File

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

56
tools/ugl/ugl_bc.h Normal file
View File

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

25
tools/ugl/ugl_error.c Normal file
View File

@ -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);
}

420
tools/ugl/ugl_file.c Normal file
View File

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

12
tools/ugl/ugl_main.c Normal file
View File

@ -0,0 +1,12 @@
#include "ugl.h"
int main(void)
{
ugl_InitBytecode();
ugl_read_filename("test.ugl");
ugl_ResolveSymbols();
ugl_ExecBytecode();
}