new example 'stack machine' with typed frames
parent
bb68f6cdfa
commit
25be3d41bc
12
build.sh
12
build.sh
|
|
@ -1,12 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
code=$PWD
|
|
||||||
opts=-g
|
|
||||||
inc="-I$code/symbol_set"
|
|
||||||
|
|
||||||
mkdir -p build
|
|
||||||
cd build
|
|
||||||
|
|
||||||
clang -c $code/examples/example1.c $opts $inc
|
|
||||||
./symbol_set.ld_meta example1.o
|
|
||||||
clang -o example1 $code/examples/example1.c $opts $inc -T sy.ld
|
|
||||||
|
|
@ -2,8 +2,15 @@
|
||||||
|
|
||||||
set code=%cd%
|
set code=%cd%
|
||||||
set opts=-FC -GR- -EHa- -nologo -Zi -std:c11 -wd5105
|
set opts=-FC -GR- -EHa- -nologo -Zi -std:c11 -wd5105
|
||||||
|
set linkopts=-link -INCREMENTAL:NO
|
||||||
set inc=-I%code%\symbol_set
|
set inc=-I%code%\symbol_set
|
||||||
|
|
||||||
if not exist "build" ( mkdir build )
|
if not exist "build" ( mkdir build )
|
||||||
pushd build
|
pushd build
|
||||||
cl -Feexample1 %code%\examples\example1.c %opts% %inc% -link -INCREMENTAL:NO
|
if "%1" == "" (
|
||||||
|
cl -Feexample1 %code%\examples\example1.c %opts% %inc% %linkopts%
|
||||||
|
)
|
||||||
|
if "%1" == "stack_machine" (
|
||||||
|
cl -Festack_machine %code%\examples\stack_machine.c %opts% %inc% %linkopts%
|
||||||
|
)
|
||||||
popd
|
popd
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,18 @@
|
||||||
|
|
||||||
set code=%cd%
|
set code=%cd%
|
||||||
set opts=-g
|
set opts=-g
|
||||||
|
set linkopts=-Xlinkker -INCREMENTAL:NO
|
||||||
set inc=-I%code%\symbol_set
|
set inc=-I%code%\symbol_set
|
||||||
|
|
||||||
|
if not exist "build" ( mkdir build )
|
||||||
pushd build
|
pushd build
|
||||||
clang -o example1 %code%\examples\example1.c %opts% %inc% -Xlinker -INCREMENTAL:NO
|
|
||||||
|
if "%1" == "" (
|
||||||
|
clang -o example1 %code%\examples\example1.c %opts% %inc% %linkopts%
|
||||||
|
)
|
||||||
|
if "%1" == "stack_machine" (
|
||||||
|
clang -o stack_machine %code%\examples\stack_machine.c %opts% %inc% %linkopts%
|
||||||
|
)
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
code=$PWD
|
||||||
|
opts=-g
|
||||||
|
inc="-I$code/symbol_set"
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
if [[ "$1" == "" ]]; then
|
||||||
|
clang -c $code/examples/example1.c $opts $inc
|
||||||
|
./symbol_set.ld_meta example1.o
|
||||||
|
clang -o example1 $code/examples/example1.c $opts $inc -T sy.ld
|
||||||
|
elif [[ "$1" == "stack_machine" ]]; then
|
||||||
|
clang -c $code/examples/stack_machine.c $opts $inc
|
||||||
|
./symbol_set.ld_meta stack_machine.o
|
||||||
|
clang -o stack_machine $code/examples/stack_machine.c $opts $inc -T sy.ld
|
||||||
|
fi
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define EXAMPLE1_H
|
#define EXAMPLE1_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Example 1 Header
|
// Little Base Layer
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
typedef int8_t S8;
|
typedef int8_t S8;
|
||||||
|
|
@ -25,6 +25,9 @@ typedef struct String8{
|
||||||
U64 size;
|
U64 size;
|
||||||
} String8;
|
} String8;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Example Specifics
|
||||||
|
|
||||||
typedef struct EX1_Ctx{
|
typedef struct EX1_Ctx{
|
||||||
S64 foo;
|
S64 foo;
|
||||||
} EX1_Ctx;
|
} EX1_Ctx;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,525 @@
|
||||||
|
/*
|
||||||
|
** C Scripting - Stack Machine
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SY__MAIN 1
|
||||||
|
#include "symbol_set.h"
|
||||||
|
#include "symbol_set.init.h"
|
||||||
|
|
||||||
|
#include "stack_machine.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Little Base Layer
|
||||||
|
|
||||||
|
static Arena
|
||||||
|
arena_alloc(U64 cap){
|
||||||
|
Arena arena = {0};
|
||||||
|
arena.memory = malloc(cap);
|
||||||
|
arena.cap = cap;
|
||||||
|
return(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
arena_push(Arena *arena, U64 size){
|
||||||
|
void *result = 0;
|
||||||
|
if (arena->pos + size <= arena->cap){
|
||||||
|
result = (U8*)arena->memory + arena->pos;
|
||||||
|
arena->pos += size;
|
||||||
|
arena->pos = (arena->pos + 7)&~7; // "round up to multiple of 8"
|
||||||
|
memset(result, 0, size);
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
arena_pop_to(Arena *arena, U64 pos){
|
||||||
|
if (pos < arena->pos){
|
||||||
|
arena->pos = (pos + 7)&~7; // "round up to multiple of 8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static U64
|
||||||
|
arena_pos(Arena *arena){
|
||||||
|
return(arena->pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Stack Machine
|
||||||
|
|
||||||
|
//// TICTACTOE Data ////
|
||||||
|
|
||||||
|
struct TICTACTOE_Line{ U32 idx[3]; };
|
||||||
|
static struct TICTACTOE_Line tictactoe_lines[8] = {
|
||||||
|
{.idx = { 0, 1, 2 }},
|
||||||
|
{.idx = { 3, 4, 5 }},
|
||||||
|
{.idx = { 6, 7, 8 }},
|
||||||
|
{.idx = { 0, 3, 6 }},
|
||||||
|
{.idx = { 1, 4, 7 }},
|
||||||
|
{.idx = { 2, 5, 8 }},
|
||||||
|
{.idx = { 0, 4, 8 }},
|
||||||
|
{.idx = { 2, 4, 6 }},
|
||||||
|
};
|
||||||
|
|
||||||
|
//// Symbol Definitions ////
|
||||||
|
|
||||||
|
SM_FRAME_STRUCT(TicTacToe){
|
||||||
|
B8 turn;
|
||||||
|
U8 board[9];
|
||||||
|
};
|
||||||
|
|
||||||
|
SM_FRAME_RETURN_TYPE_DEF(TicTacToe, B32);
|
||||||
|
|
||||||
|
SM_FRAME(TicTacToe);
|
||||||
|
|
||||||
|
SM_STATE_DECL(TicTacToe, P1Turn);
|
||||||
|
SM_STATE_DECL(TicTacToe, P2Turn);
|
||||||
|
SM_STATE_DECL(TicTacToe, BoardCheck);
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, Init){
|
||||||
|
memset(frame->board, ' ', 9);
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_P1Turn));
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, P1Turn){
|
||||||
|
printf("BOARD:\n");
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[0], frame->board[1], frame->board[2]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[3], frame->board[4], frame->board[5]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[6], frame->board[7], frame->board[8]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
|
||||||
|
printf("YOUR MOVE: ");
|
||||||
|
U32 x = 0;
|
||||||
|
U32 y = 0;
|
||||||
|
scanf("%u %u", &x, &y);
|
||||||
|
|
||||||
|
frame->board[y*3 + x] = 'X';
|
||||||
|
|
||||||
|
frame->turn = 1;
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_BoardCheck));
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, P2Turn){
|
||||||
|
U32 x = 0;
|
||||||
|
U32 y = 0;
|
||||||
|
|
||||||
|
struct TICTACTOE_Line *lines = tictactoe_lines;
|
||||||
|
|
||||||
|
// if you can win, then win
|
||||||
|
for (U32 i = 0; i < 8; i += 1){
|
||||||
|
U32 count_mine = 0;
|
||||||
|
U32 blank_spot = ~0;
|
||||||
|
for (U32 j = 0; j < 3; j += 1){
|
||||||
|
U32 idx = lines[i].idx[j];
|
||||||
|
U8 c = frame->board[idx];
|
||||||
|
if (c == 'O'){
|
||||||
|
count_mine += 1;
|
||||||
|
}
|
||||||
|
else if (c == ' '){
|
||||||
|
blank_spot = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blank_spot != ~0 && count_mine == 2){
|
||||||
|
x = blank_spot%3;
|
||||||
|
y = blank_spot/3;
|
||||||
|
goto play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if you need to block, then block
|
||||||
|
for (U32 i = 0; i < 8; i += 1){
|
||||||
|
U32 count_other = 0;
|
||||||
|
U32 blank_spot = ~0;
|
||||||
|
for (U32 j = 0; j < 3; j += 1){
|
||||||
|
U32 idx = lines[i].idx[j];
|
||||||
|
U8 c = frame->board[idx];
|
||||||
|
if (c == 'X'){
|
||||||
|
count_other += 1;
|
||||||
|
}
|
||||||
|
else if (c == ' '){
|
||||||
|
blank_spot = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blank_spot != ~0 && count_other == 2){
|
||||||
|
x = blank_spot%3;
|
||||||
|
y = blank_spot/3;
|
||||||
|
goto play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise just random
|
||||||
|
{
|
||||||
|
U32 potentials[9];
|
||||||
|
U32 count = 0;
|
||||||
|
for (U32 i = 0; i < 9; i += 1){
|
||||||
|
if (frame->board[i] == ' '){
|
||||||
|
potentials[count] = i;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0){
|
||||||
|
U32 idx = rand()%count;
|
||||||
|
x = potentials[idx]%3;
|
||||||
|
y = potentials[idx]/3;
|
||||||
|
goto play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
play:
|
||||||
|
printf("OPPONENT PLAYED AT: %u %u\n", x, y);
|
||||||
|
frame->board[y*3 + x] = 'O';
|
||||||
|
|
||||||
|
frame->turn = 0;
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_BoardCheck));
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, P1Win){
|
||||||
|
printf("You won!\n");
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[0], frame->board[1], frame->board[2]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[3], frame->board[4], frame->board[5]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[6], frame->board[7], frame->board[8]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
|
||||||
|
sm_state_pop(ctx, &(B32){1});
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, P1Lose){
|
||||||
|
printf("You lost!\n");
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[0], frame->board[1], frame->board[2]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[3], frame->board[4], frame->board[5]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[6], frame->board[7], frame->board[8]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
|
||||||
|
sm_state_pop(ctx, &(B32){0});
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, Tie){
|
||||||
|
printf("You tied!\n");
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[0], frame->board[1], frame->board[2]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[3], frame->board[4], frame->board[5]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
printf("|%c|%c|%c|\n", frame->board[6], frame->board[7], frame->board[8]);
|
||||||
|
printf("+-+-+-+\n");
|
||||||
|
|
||||||
|
sm_state_pop(ctx, &(B32){0});
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(TicTacToe, BoardCheck){
|
||||||
|
U32 winner = 0;
|
||||||
|
for (U32 i = 0; i < 8; i += 1){
|
||||||
|
U32 count[2] = {0};
|
||||||
|
for (U32 j = 0; j < 3; j += 1){
|
||||||
|
U32 idx = tictactoe_lines[i].idx[j];
|
||||||
|
U8 c = frame->board[idx];
|
||||||
|
if (c == 'X'){
|
||||||
|
count[0] += 1;
|
||||||
|
}
|
||||||
|
else if (c == 'O'){
|
||||||
|
count[1] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (U32 k = 0; k < 2; k += 1){
|
||||||
|
if (count[k] == 3){
|
||||||
|
winner = k + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B32 tie = 0;
|
||||||
|
if (winner == 0){
|
||||||
|
tie = 1;
|
||||||
|
for (U32 i = 0; i < 9; i += 1){
|
||||||
|
if (frame->board[i] == ' '){
|
||||||
|
tie = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end states
|
||||||
|
if (tie){
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_Tie));
|
||||||
|
}
|
||||||
|
else if (winner == 1){
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_P1Win));
|
||||||
|
}
|
||||||
|
else if (winner == 2){
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_P1Lose));
|
||||||
|
}
|
||||||
|
// next turn
|
||||||
|
else{
|
||||||
|
if (frame->turn == 0){
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_P1Turn));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, TicTacToe_P2Turn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_FRAME_STRUCT(RockPaperScissors){
|
||||||
|
S32 score;
|
||||||
|
};
|
||||||
|
|
||||||
|
SM_FRAME_RETURN_TYPE_DEF(RockPaperScissors, B32);
|
||||||
|
|
||||||
|
SM_FRAME(RockPaperScissors);
|
||||||
|
|
||||||
|
SM_STATE(RockPaperScissors, Play){
|
||||||
|
printf("YOUR SCORE: %d\n", frame->score);
|
||||||
|
printf("[1] ROCK [2] PAPER [3] SCISSORS SHOOT: ");
|
||||||
|
U32 m = 0;
|
||||||
|
scanf("%u", &m);
|
||||||
|
m = m%3;
|
||||||
|
|
||||||
|
U32 o = rand()%3;
|
||||||
|
switch (o){
|
||||||
|
case 1: printf("YOUR OPPONENT THROWS ROCK.\n"); break;
|
||||||
|
case 2: printf("YOUR OPPONENT THROWS PAPER.\n"); break;
|
||||||
|
case 0: printf("YOUR OPPONENT THROWS SCISSORS.\n"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p1 wins
|
||||||
|
if ((m + 2)%3 == o){
|
||||||
|
frame->score += 1;
|
||||||
|
if (frame->score < 3){
|
||||||
|
printf("YOU WON THIS ROUND!\n");
|
||||||
|
sm_state_stationary(ctx);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
printf("YOU WIN!\n");
|
||||||
|
sm_state_pop(ctx, &(B32){1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// p2 wins
|
||||||
|
else if ((o + 2)%3 == m){
|
||||||
|
frame->score -= 1;
|
||||||
|
if (frame->score > -3){
|
||||||
|
printf("YOU LOST THIS ROUND!\n");
|
||||||
|
sm_state_stationary(ctx);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
printf("YOU LOST!\n");
|
||||||
|
sm_state_pop(ctx, &(B32){0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no winner
|
||||||
|
else{
|
||||||
|
sm_state_stationary(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_FRAME_STRUCT(Menu){
|
||||||
|
U32 wins[2];
|
||||||
|
U32 last_played_game;
|
||||||
|
};
|
||||||
|
SM_FRAME_RETURN_TYPE_DEF(Menu, void);
|
||||||
|
|
||||||
|
SM_FRAME(Menu);
|
||||||
|
|
||||||
|
SM_STATE_DECL(Menu, RecordWin);
|
||||||
|
|
||||||
|
SM_STATE(Menu, Play){
|
||||||
|
B32 has_win = 0;
|
||||||
|
for (U32 i = 0; i < sizeof(frame->wins)/sizeof(*frame->wins); i += 1){
|
||||||
|
if (frame->wins[i]){
|
||||||
|
has_win = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_win){
|
||||||
|
printf("Your wins:\n");
|
||||||
|
printf("Tic-Tac-Toe %u\n", frame->wins[0]);
|
||||||
|
printf("Rock-Paper-Scissors %u\n", frame->wins[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Choose a game:\n");
|
||||||
|
printf("[1] Tic-Tac-Toe\n");
|
||||||
|
printf("[2] Rock-Paper-Scissors\n");
|
||||||
|
printf("[3] Quit\n");
|
||||||
|
|
||||||
|
U32 x = 0;
|
||||||
|
scanf("%u", &x);
|
||||||
|
switch (x){
|
||||||
|
case 1: {
|
||||||
|
frame->last_played_game = 1;
|
||||||
|
sm_state_next_push(ctx, SyID(SM_STATE, Menu_RecordWin),
|
||||||
|
SyID(SM_STATE, TicTacToe_Init));
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case 2: {
|
||||||
|
frame->last_played_game = 2;
|
||||||
|
sm_state_next_push(ctx, SyID(SM_STATE, Menu_RecordWin),
|
||||||
|
SyID(SM_STATE, RockPaperScissors_Play));
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case 3: sm_state_pop(ctx, 0); break;
|
||||||
|
default: sm_state_stationary(ctx); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SM_STATE(Menu, RecordWin){
|
||||||
|
B32 *win = sm_ctx_get_prev_return(ctx);
|
||||||
|
if (win != 0 && *win &&
|
||||||
|
1 <= frame->last_played_game &&
|
||||||
|
frame->last_played_game <= sizeof(frame->wins)/sizeof(*frame->wins)){
|
||||||
|
frame->wins[frame->last_played_game - 1] += 1;
|
||||||
|
}
|
||||||
|
sm_state_next(ctx, SyID(SM_STATE, Menu_Play));
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Function Definitions ////
|
||||||
|
|
||||||
|
static SM_Ctx
|
||||||
|
sm_ctx_new(U32 initial_state_id){
|
||||||
|
SM_Ctx ctx = {0};
|
||||||
|
ctx.stack_arena = arena_alloc((10 << 20));
|
||||||
|
sm__stack_push(&ctx, initial_state_id);
|
||||||
|
return(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32
|
||||||
|
sm_ctx_get_top_state(SM_Ctx *ctx){
|
||||||
|
U32 result = 0;
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
result = ctx->stack->state_id;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
sm_ctx_get_top_frame(SM_Ctx *ctx){
|
||||||
|
void *result = 0;
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
result = ctx->stack->frame;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static B32
|
||||||
|
sm_ctx_stack_empty(SM_Ctx *ctx){
|
||||||
|
B32 result = (ctx->stack == 0);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
sm_ctx_get_prev_return(SM_Ctx *ctx){
|
||||||
|
void *prev_return = ctx->prev_return;
|
||||||
|
return(prev_return);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_state_stationary(SM_Ctx *ctx){
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_state_next(SM_Ctx *ctx, U32 state_id){
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
ctx->stack->state_id = state_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_state_stationary_push(SM_Ctx *ctx, U32 push_state_id){
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
// push
|
||||||
|
sm__stack_push(ctx, push_state_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_state_next_push(SM_Ctx *ctx, U32 next_state_id, U32 push_state_id){
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
// next
|
||||||
|
ctx->stack->state_id = next_state_id;
|
||||||
|
// push
|
||||||
|
sm__stack_push(ctx, push_state_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_state_pop(SM_Ctx *ctx, void *return_data){
|
||||||
|
if (ctx->stack != 0){
|
||||||
|
// save return
|
||||||
|
if (return_data != 0){
|
||||||
|
SM_State *state = SyAddressFromID(SM_STATE, ctx->stack->state_id);
|
||||||
|
SM_Frame *frame = SyAddressFromID(SM_FRAME, state->frame_id);
|
||||||
|
ctx->new_return = push_array(ctx->run_arena, U8, frame->return_size);
|
||||||
|
memcpy(ctx->new_return, return_data, frame->return_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack pops
|
||||||
|
U64 pos = ctx->stack->pop_pos;
|
||||||
|
SLLStackPop(ctx->stack);
|
||||||
|
arena_pop_to(&ctx->stack_arena, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm__stack_push(SM_Ctx *ctx, U32 state_id){
|
||||||
|
SM_State *state = SyAddressFromID(SM_STATE, state_id);
|
||||||
|
SM_Frame *frame = SyAddressFromID(SM_FRAME, state->frame_id);
|
||||||
|
|
||||||
|
U64 pos = arena_pos(&ctx->stack_arena);
|
||||||
|
SM_StackNode *new_node = push_array(&ctx->stack_arena, SM_StackNode, 1);
|
||||||
|
new_node->pop_pos = pos;
|
||||||
|
new_node->frame = push_array(&ctx->stack_arena, U8, frame->size);
|
||||||
|
new_node->state_id = state_id;
|
||||||
|
SLLStackPush(ctx->stack, new_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Entry Point ////
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
sy__run_init();
|
||||||
|
|
||||||
|
Arena run_arenas[2] = {0};
|
||||||
|
for (U32 i = 0; i < 2; i += 1){
|
||||||
|
run_arenas[i] = arena_alloc((1 << 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 counter = 0;
|
||||||
|
|
||||||
|
SM_Ctx ctx = sm_ctx_new(SyID(SM_STATE, Menu_Play));
|
||||||
|
ctx.diagnostics = 1;
|
||||||
|
for (;!sm_ctx_stack_empty(&ctx); counter += 1){
|
||||||
|
ctx.run_arena = &run_arenas[counter&1];
|
||||||
|
arena_pop_to(ctx.run_arena, 0);
|
||||||
|
ctx.new_return = 0;
|
||||||
|
|
||||||
|
U32 state_id = sm_ctx_get_top_state(&ctx);
|
||||||
|
SM_State *state = SyAddressFromID(SM_STATE, state_id);
|
||||||
|
if (state == 0){
|
||||||
|
printf("ERROR\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ctx.diagnostics){
|
||||||
|
String8 name = state->name;
|
||||||
|
printf("DIAGNOSTICS: STATE %.*s\n", (int)name.size, name.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *frame = sm_ctx_get_top_frame(&ctx);
|
||||||
|
state->func(&ctx, frame);
|
||||||
|
|
||||||
|
ctx.prev_return = ctx.new_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,208 @@
|
||||||
|
#ifndef STACK_MACHINE_H
|
||||||
|
#define STACK_MACHINE_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Little Base Layer
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int8_t S8;
|
||||||
|
typedef int16_t S16;
|
||||||
|
typedef int32_t S32;
|
||||||
|
typedef int64_t S64;
|
||||||
|
typedef uint8_t U8;
|
||||||
|
typedef uint16_t U16;
|
||||||
|
typedef uint32_t U32;
|
||||||
|
typedef uint64_t U64;
|
||||||
|
typedef S8 B8;
|
||||||
|
typedef S16 B16;
|
||||||
|
typedef S32 B32;
|
||||||
|
typedef S64 B64;
|
||||||
|
typedef float F32;
|
||||||
|
typedef double F64;
|
||||||
|
|
||||||
|
typedef struct String8{
|
||||||
|
U8 *str;
|
||||||
|
U64 size;
|
||||||
|
} String8;
|
||||||
|
|
||||||
|
#define str8_const(S) {(U8*)(S), (U64)(sizeof(S) - 1)}
|
||||||
|
|
||||||
|
typedef struct Arena{
|
||||||
|
void *memory;
|
||||||
|
U64 pos;
|
||||||
|
U64 cap;
|
||||||
|
} Arena;
|
||||||
|
|
||||||
|
static Arena arena_alloc(U64 cap);
|
||||||
|
static void* arena_push(Arena *arena, U64 size);
|
||||||
|
static void arena_pop_to(Arena *arena, U64 pos);
|
||||||
|
static U64 arena_pos(Arena *arena);
|
||||||
|
|
||||||
|
#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Macros: Linked Lists
|
||||||
|
|
||||||
|
#define DLLPushBack_NPZ(f,l,n,next,prev,nil)\
|
||||||
|
(((f) == (nil))?\
|
||||||
|
((f)=(l)=(n),(n)->next=(n)->prev=(nil)):\
|
||||||
|
((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=(nil)))
|
||||||
|
|
||||||
|
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(f,l,n,next,prev,0)
|
||||||
|
#define DLLPushFront(f,l,n) DLLPushBack_NPZ(l,f,n,prev,next,0)
|
||||||
|
|
||||||
|
#define DLLInsert_NPZ(f,l,p,n,next,prev,nil) \
|
||||||
|
(((p) != (l))?\
|
||||||
|
((n)->next = (p)->next,\
|
||||||
|
(n)->prev = (p),\
|
||||||
|
(p)->next->prev = (n),\
|
||||||
|
(p)->next = (n))\
|
||||||
|
:((n)->next = (nil),\
|
||||||
|
(n)->prev = (l),\
|
||||||
|
(l)->next = (n),\
|
||||||
|
(l) = (n)))
|
||||||
|
|
||||||
|
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(f,l,p,n,next,prev,0)
|
||||||
|
|
||||||
|
#define DLLRemove_NPZ(f,l,n,next,prev,nil)\
|
||||||
|
((f)==(n)?\
|
||||||
|
((f)==(l)?\
|
||||||
|
((f)=(l)=(nil)):\
|
||||||
|
((f)=(f)->next,(f)->prev=(nil))):\
|
||||||
|
(l)==(n)?\
|
||||||
|
((l)=(l)->prev,(l)->next=(nil)):\
|
||||||
|
((n)->next->prev=(n)->prev,\
|
||||||
|
(n)->prev->next=(n)->next))
|
||||||
|
|
||||||
|
#define DLLRemove(f,l,n) DLLRemove_NPZ(f,l,n,next,prev,0)
|
||||||
|
|
||||||
|
#define SLLQueuePush_NZ(f,l,n,next,nil) (((f)==(nil)?\
|
||||||
|
(f)=(l)=(n):\
|
||||||
|
((l)->next=(n),(l)=(n))),\
|
||||||
|
(n)->next=(nil))
|
||||||
|
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(f,l,n,next,0)
|
||||||
|
|
||||||
|
#define SLLQueuePushFront_NZ(f,l,n,next,nil) ((f)==(nil)?\
|
||||||
|
((f)=(l)=(n),(n)->next=(nil)):\
|
||||||
|
((n)->next=(f),(f)=(n)))
|
||||||
|
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(f,l,n,next,0)
|
||||||
|
|
||||||
|
#define SLLQueuePop_NZ(f,l,next,nil) ((f)==(l)?\
|
||||||
|
(f)=(l)=(nil):\
|
||||||
|
((f)=(f)->next))
|
||||||
|
#define SLLQueuePop(f,l) SLLQueuePop_NZ(f,l,next,0)
|
||||||
|
|
||||||
|
#define SLLStackPush_N(f,n,next) ((n)->next=(f),(f)=(n))
|
||||||
|
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
||||||
|
|
||||||
|
#define SLLStackPop_NZ(f,next,nil) ((f)==(nil)?(nil):\
|
||||||
|
((f)=(f)->next))
|
||||||
|
#define SLLStackPop(f) SLLStackPop_NZ(f,next,0)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Stack Machine
|
||||||
|
|
||||||
|
typedef struct SM_Ctx SM_Ctx;
|
||||||
|
|
||||||
|
//// SM_FRAME ////
|
||||||
|
|
||||||
|
typedef struct SM_Frame{
|
||||||
|
String8 name;
|
||||||
|
U64 size;
|
||||||
|
U64 return_size;
|
||||||
|
} SM_Frame;
|
||||||
|
|
||||||
|
#define SYMBOL_SET_DEFINE SM_FRAME
|
||||||
|
#define SM_FRAME_Type SM_Frame
|
||||||
|
#define SM_FRAME_elf_section ".sy.frame"
|
||||||
|
#define SM_FRAME_coff_a_section ".sy$frame_a"
|
||||||
|
#define SM_FRAME_coff_m_section ".sy$frame_m"
|
||||||
|
#define SM_FRAME_coff_z_section ".sy$frame_z"
|
||||||
|
#define SM_FRAME_marker frame
|
||||||
|
#include "symbol_set.define.h"
|
||||||
|
|
||||||
|
#define SM_FRAME_STRUCT(F) typedef struct SM_Frame_##F SM_Frame_##F; \
|
||||||
|
struct SM_Frame_##F
|
||||||
|
|
||||||
|
#define SM_FRAME_TYPE_DEF(F,T) typedef T SM_Frame_##F
|
||||||
|
|
||||||
|
#define SM_FRAME_RETURN_STRUCT(F) typedef struct SM_FrameReturn_##F SM_FrameReturn_##F; \
|
||||||
|
struct SM_FrameReturn_##F
|
||||||
|
|
||||||
|
#define SM_FRAME_RETURN_TYPE_DEF(F,T) typedef T SM_FrameReturn_##F
|
||||||
|
|
||||||
|
#define SM_FRAME(F) \
|
||||||
|
SyDefine(SM_FRAME, F) = { str8_const(#F), sizeof(SM_Frame_##F), sizeof(SM_FrameReturn_##F) }
|
||||||
|
|
||||||
|
//// SM_STATE ////
|
||||||
|
|
||||||
|
typedef void SM_StateFunc(SM_Ctx *ctx, void *frame);
|
||||||
|
|
||||||
|
typedef struct SM_State{
|
||||||
|
String8 name;
|
||||||
|
SM_StateFunc *func;
|
||||||
|
SY__UAddr frame_id;
|
||||||
|
} SM_State;
|
||||||
|
|
||||||
|
#define SYMBOL_SET_DEFINE SM_STATE
|
||||||
|
#define SM_STATE_Type SM_State
|
||||||
|
#define SM_STATE_elf_section ".sy.state"
|
||||||
|
#define SM_STATE_coff_a_section ".sy$state_a"
|
||||||
|
#define SM_STATE_coff_m_section ".sy$state_m"
|
||||||
|
#define SM_STATE_coff_z_section ".sy$state_z"
|
||||||
|
#define SM_STATE_marker state
|
||||||
|
#include "symbol_set.define.h"
|
||||||
|
|
||||||
|
#define SM_STATE_DECL(F,N) SyDeclare(SM_STATE, F##_##N)
|
||||||
|
|
||||||
|
#define SM_STATE(F,N) \
|
||||||
|
static void sm_statefunc__##F##_##N(SM_Ctx *ctx, SM_Frame_##F *frame); \
|
||||||
|
SyDefine(SM_STATE, F##_##N) = { \
|
||||||
|
.name = str8_const(#F "." #N), \
|
||||||
|
.func = (SM_StateFunc*)sm_statefunc__##F##_##N, \
|
||||||
|
.frame_id = SyRaw(SM_FRAME, F) }; \
|
||||||
|
static void sm_statefunc__##F##_##N(SM_Ctx *ctx, SM_Frame_##F *frame)
|
||||||
|
|
||||||
|
#if SY__MAIN
|
||||||
|
SY_INIT(SM_STATE){
|
||||||
|
for (SyEach(SM_STATE, state)){
|
||||||
|
state->frame_id = SyIDFromRaw(SM_FRAME, state->frame_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//// Context ////
|
||||||
|
|
||||||
|
typedef struct SM_StackNode{
|
||||||
|
struct SM_StackNode *next;
|
||||||
|
U64 pop_pos;
|
||||||
|
void *frame;
|
||||||
|
U32 state_id;
|
||||||
|
} SM_StackNode;
|
||||||
|
|
||||||
|
struct SM_Ctx{
|
||||||
|
Arena *run_arena;
|
||||||
|
Arena stack_arena;
|
||||||
|
SM_StackNode *stack;
|
||||||
|
|
||||||
|
void *prev_return;
|
||||||
|
void *new_return;
|
||||||
|
|
||||||
|
B32 diagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SM_Ctx sm_ctx_new(U32 initial_state_id);
|
||||||
|
static U32 sm_ctx_get_top_state(SM_Ctx *ctx);
|
||||||
|
static void* sm_ctx_get_top_frame(SM_Ctx *ctx);
|
||||||
|
static B32 sm_ctx_stack_empty(SM_Ctx *ctx);
|
||||||
|
static void* sm_ctx_get_prev_return(SM_Ctx *ctx);
|
||||||
|
|
||||||
|
static void sm_state_stationary(SM_Ctx *ctx);
|
||||||
|
static void sm_state_next(SM_Ctx *ctx, U32 state_id);
|
||||||
|
static void sm_state_stationary_push(SM_Ctx *ctx, U32 push_state_id);
|
||||||
|
static void sm_state_next_push(SM_Ctx *ctx, U32 next_state_id, U32 push_state_id);
|
||||||
|
static void sm_state_pop(SM_Ctx *ctx, void *return_data);
|
||||||
|
|
||||||
|
static void sm__stack_push(SM_Ctx *ctx, U32 state_id);
|
||||||
|
|
||||||
|
#endif //STACK_MACHINE_H
|
||||||
|
|
@ -12,7 +12,8 @@ load_paths = {
|
||||||
commands = {
|
commands = {
|
||||||
.build_with_clang = { .out = "*compilation*",
|
.build_with_clang = { .out = "*compilation*",
|
||||||
.footer_panel = true, .save_dirty_files = true,
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
.win = "build_with_clang.bat", .linux = "./build.sh", .mac = "./build.sh"
|
.win = "build_with_clang.bat", .linux = "./build_with_clang.sh stack_machine",
|
||||||
|
.mac = "./build_with_clang.sh"
|
||||||
},
|
},
|
||||||
.build_with_cl = { .out = "*compilation*",
|
.build_with_cl = { .out = "*compilation*",
|
||||||
.footer_panel = true, .save_dirty_files = true,
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
|
|
@ -22,12 +23,12 @@ commands = {
|
||||||
.footer_panel = true, .save_dirty_files = true,
|
.footer_panel = true, .save_dirty_files = true,
|
||||||
.linux = "./build_ld_meta.sh", .mac = "./build_ld_meta.sh"
|
.linux = "./build_ld_meta.sh", .mac = "./build_ld_meta.sh"
|
||||||
},
|
},
|
||||||
.run = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
|
.run_example1 = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
|
||||||
.win = "build\\example1", .linux = "build/example1", .mac = "build/example1"
|
.win = "build\\example1", .linux = "build/example1", .mac = "build/example1"
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command = {
|
fkey_command = {
|
||||||
.F1 = "build_with_cl",
|
.F1 = "build_with_clang",
|
||||||
.F2 = "run",
|
.F2 = "run_example1",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,24 @@
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
~~~~~~~~~~~~~~~~~~~ SY Init Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
~~~~~~~~~~~~~~~~~~~ SY Init Definitions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
typedef void SY_InitFunc(void*);
|
typedef void SY_InitFunc(void);
|
||||||
typedef struct SY_InitRecord{
|
typedef struct SY_InitRecord{
|
||||||
SY_InitFunc *func;
|
SY_InitFunc *func;
|
||||||
} SY_InitRecord;
|
} SY_InitRecord;
|
||||||
|
|
||||||
#define SYMBOL_SET_DEFINE SY_INIT
|
#define SYMBOL_SET_DEFINE SY_INIT
|
||||||
#define SY_INIT_Type SY_InitRecord
|
#define SY_INIT_Type SY_InitRecord
|
||||||
#define SY_INIT_section ".sy.init"
|
#define SY_INIT_elf_section ".sy.init"
|
||||||
|
#define SY_INIT_coff_a_section ".sy$init_a"
|
||||||
|
#define SY_INIT_coff_m_section ".sy$init_m"
|
||||||
|
#define SY_INIT_coff_z_section ".sy$init_z"
|
||||||
#define SY_INIT_marker init
|
#define SY_INIT_marker init
|
||||||
#include "mr4th_symbol_set.define.h"
|
#include "symbol_set.define.h"
|
||||||
|
|
||||||
#define SY_INIT_DEF(N,T) \
|
#define SY_INIT(N) \
|
||||||
static void syinit__##N(T*); \
|
static void syinit__##N(void); \
|
||||||
SyDefine(SY_INIT, N) = { syinit__##N }; \
|
SyDefine(SY_INIT, N) = { syinit__##N }; \
|
||||||
static void syinit__##N(T*ptr)
|
static void syinit__##N(void)
|
||||||
|
|
||||||
void sy__run_init(void);
|
void sy__run_init(void);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue