mirror of https://github.com/egormanga/Slang.git
218 lines
4.7 KiB
C
218 lines
4.7 KiB
C
// SBC
|
|
|
|
#define _GNU_SOURCE
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "builtins.c"
|
|
#include "stack.c"
|
|
|
|
typedef uint8_t code_t;
|
|
|
|
enum {
|
|
// Standalone
|
|
NOP = 0x00,
|
|
END = 0x01,
|
|
POP = 0x02,
|
|
RET = 0x03,
|
|
BLTIN = 0x04,
|
|
CODE = 0x05,
|
|
|
|
// Unary
|
|
POS = 0x10,
|
|
NEG = 0x11,
|
|
NOT = 0x12,
|
|
INV = 0x13,
|
|
ATOI = 0x14,
|
|
ITOA = 0x15,
|
|
ITOF = 0x16,
|
|
CEIL = 0x17,
|
|
FLR = 0x18,
|
|
RND = 0x19,
|
|
CTOS = 0x1A,
|
|
|
|
// Binary
|
|
ADD = 0x20,
|
|
SUB = 0x21,
|
|
MUL = 0x22,
|
|
DIV = 0x23,
|
|
IDIV = 0x24,
|
|
MOD = 0x25,
|
|
POW = 0x26,
|
|
SHL = 0x27,
|
|
SHR = 0x28,
|
|
AND = 0x29,
|
|
OR = 0x2A,
|
|
XOR = 0x2B,
|
|
|
|
// Comparisons
|
|
EQ = 0x30,
|
|
NE = 0x31,
|
|
LT = 0x32,
|
|
GT = 0x33,
|
|
LE = 0x34,
|
|
GE = 0x35,
|
|
IS = 0x36,
|
|
ISNOT = 0x37,
|
|
|
|
// Flow control
|
|
IF = 0x40,
|
|
ELSE = 0x41,
|
|
EXEC = 0x42,
|
|
|
|
// With argument
|
|
ALLOC = 0xA0,
|
|
EXTEND = 0xA1,
|
|
CONST = 0xA2,
|
|
JUMPF = 0xA3,
|
|
JUMPB = 0xA4,
|
|
SCPGET = 0xA5,
|
|
SCPSET = 0xA6,
|
|
CALL = 0xA7,
|
|
|
|
HASARG = 0xA0,
|
|
};
|
|
|
|
atom_t exec(code_t* code, uint32_t codesize) { // TODO: freeing
|
|
stack_t* st = stack();
|
|
atom_t scp[255]; // TODO
|
|
code_t* cb[255]; // TODO
|
|
uint32_t cbi = 0;
|
|
|
|
uint32_t cp = 0;
|
|
while (cp < codesize) {
|
|
code_t opcode = code[cp++];
|
|
uint32_t ocp = cp;
|
|
|
|
switch (opcode) {
|
|
// Standalone
|
|
case NOP: break;
|
|
case END: break;
|
|
case POP: stack_pop(st); break;
|
|
case RET: return st->top->data;
|
|
case BLTIN: {
|
|
char name[256];
|
|
strncpy(name, (char*)code+cp, 255);
|
|
while (code[cp++] != '\0');
|
|
stack_push(st, (atom_t){.data = get_builtin(name)});
|
|
}; break;
|
|
case CODE: {
|
|
code_t* code_block = malloc(codesize);
|
|
static uint32_t cbp = 0;
|
|
uint32_t blocklvl = 1;
|
|
while (cp < codesize) {
|
|
code_t c = code[cp++];
|
|
if (c == CODE ||
|
|
c == IF ||
|
|
c == ELSE) blocklvl++;
|
|
else if (c == END) blocklvl--;
|
|
if (blocklvl <= 0) break;
|
|
code_block[cbp++] = c;
|
|
if (c > HASARG) code_block[cbp++] = code[cp++];
|
|
if (c == CONST)
|
|
for (uint8_t i = code_block[cbp-1]; i > 0; i--)
|
|
code_block[cbp++] = code[cp++];
|
|
else if (c == BLTIN)
|
|
do code_block[cbp++] = code[cp++];
|
|
while (code[cp-1] != '\0');
|
|
}
|
|
cb[cbi++] = realloc(code_block, cbp);
|
|
free(code_block);
|
|
stack_push(st, (atom_t){u32, .u32 = &cbp});
|
|
stack_push(st, (atom_t){.data = &cb[cbi-1]});
|
|
}; break;
|
|
|
|
// Unary
|
|
case POS: *st->top->data.i32 = abs(*st->top->data.i32); break;
|
|
case ITOA: {
|
|
char s[12];
|
|
fprintf(stderr, "-- %x\n", *st->top->data.i32);
|
|
snprintf(s, sizeof(s)/sizeof(*s), "%d", *st->top->data.i32);
|
|
st->top->data.data = strdup(s);
|
|
}; break;
|
|
|
|
// Binary (TODO)
|
|
case ADD: *st->top->data.i32 += *stack_pop(st).i32; break;
|
|
case SUB: *st->top->data.i32 -= *stack_pop(st).i32; break;
|
|
|
|
// Comparisons
|
|
case LT: *st->top->data.b = *stack_pop(st).i32 > *st->top->data.i32; break;
|
|
|
|
// Flow control
|
|
case EXEC: {
|
|
uint32_t exec_codesize = *stack_pop(st).u32;
|
|
code_t* exec_code = stack_pop(st).data;
|
|
stack_push(st, exec(exec_code, exec_codesize));
|
|
}; break;
|
|
|
|
// With argument
|
|
case CONST: {
|
|
uint8_t len = code[cp++];
|
|
stack_push(st, (atom_t){.data = memcpy(malloc(len), code+cp, len)});
|
|
fprintf(stderr, "-- l=%02x: %x\n", len, *st->top->data.i32);
|
|
cp += len;
|
|
}; break;
|
|
case SCPGET: {
|
|
uint8_t cell = code[cp++];
|
|
stack_push(st, scp[cell]);
|
|
}; break;
|
|
case SCPSET: {
|
|
uint8_t cell = code[cp++];
|
|
scp[cell] = stack_pop(st);
|
|
fprintf(stderr, "-- c%d = %d\n", cell, *scp[cell].i32);
|
|
}; break;
|
|
case CALL: {
|
|
uint8_t nargs = code[cp++];
|
|
fprintf(stderr, "-- nargs=%d\n", nargs);
|
|
builtin_function func = stack_pop(st).data;
|
|
atom_t args[nargs];
|
|
for (uint8_t i = 0; i < nargs; i++)
|
|
args[i] = stack_pop(st);
|
|
stack_push(st, func(nargs, args));
|
|
}; break;
|
|
|
|
default: fprintf(stderr, "Not Implemented opcode: 0x%02x\n", opcode); exit(3);
|
|
}
|
|
|
|
fprintf(stderr, "[%02x", opcode);
|
|
if (opcode > HASARG) fprintf(stderr, "(%d|0x%02x)", code[ocp], code[ocp++]);
|
|
fputc(':', stderr);
|
|
do fprintf(stderr, " %02x", code[ocp++]);
|
|
while (ocp < cp && ocp < codesize);
|
|
if (st->top != NULL) {
|
|
fprintf(stderr, ", TOS = %u(0x%02x)", *st->top->data.i32, *st->top->data.i32);
|
|
if (isprint(*(char*)st->top->data.data)) {
|
|
fprintf(stderr, " | ");
|
|
for (char* p = st->top->data.data; *p != '\0'; p++)
|
|
fputc(isprint(*p)?*p:'.', stderr);
|
|
}
|
|
}
|
|
fprintf(stderr, "]\n");
|
|
}
|
|
|
|
return (atom_t){.data = NULL};
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
if (argc != 2) {
|
|
fprintf(stderr, "Usage: %s <file.sbc>\n", basename(argv[0]));
|
|
exit(1);
|
|
}
|
|
|
|
FILE* fd = fopen(argv[1], "rb");
|
|
fseek(fd, 0, SEEK_END);
|
|
long fsize = ftell(fd);
|
|
fseek(fd, 0, SEEK_SET);
|
|
|
|
code_t code[fsize];
|
|
fread(code, sizeof(*code), fsize, fd);
|
|
fclose(fd);
|
|
|
|
exec(code, fsize);
|
|
}
|
|
|
|
// by Sdore, 2020
|