3. Stack
This is a stack based VM, that will be designed in similar fashion to Runt.
The stack is a pre-allocated array of stacklets
. A
stacklet is an item that can get placed onto the stack.
A stacklet is known as a txtvm_stacklet
.
typedef struct txtvm_stacklet txtvm_stacklet;
struct txtvm_stacklet {
<<stacklet>>
};
The type flag determines the kind of item that was placed onto the stack.
int type;
Type values will be desribed in an enum.
enum {
TYPE_NONE,
<<typeflags>>
TYPE_END
};
A stacklet is initially set to be TYPE_NONE
.
s->type = TYPE_NONE;
An integer value inum
can be used to hold an integer. A
floating point value fnum
can be used to hold a floating
point value. This might be a union some day, if I actually
learn how to use those properly.
TYPE_INT,
TYPE_FLOAT,
int ival;
float fval;
s->ival = 0;
s->fval = 0;
There is also a component for a void pointer ptr
. Anything
more non-trivial than a integer or floating point number
gets stored here.
TYPE_CPTR,
void *ptr;
s->ptr = NULL;
The stack itself is mostly a fixed array of stacklets, with a few other things to keep track of position and state.
A stack is known as a txtvm_stack
:
typedef struct txtvm_stack txtvm_stack;
#ifndef TXTVM_STACKSIZE
#define TXTVM_STACKSIZE 16
#endif
struct txtvm_stack {
txtvm_stacklet s[TXTVM_STACKSIZE];
<<stack>>
};
The stack is initialized with txtvm_stack_init
.
void txtvm_stack_init(txtvm_stack *stack);
void txtvm_stack_init(txtvm_stack *stack)
{
int i;
for (i = 0; i < TXTVM_STACKSIZE; i++) {
txtvm_stacklet_init(&stack->s[i]);
}
<<stack_init>>
}
The core operations of a stack are popping and pushing. This
is kept track of using a variable keeping track of position
called pos
. A value of 0
means no items on the stack.
int pos;
stack->pos = 0;
Both the pushing and popping values return an error code. A non-zero error code indicates some sort of failure.
int txtvm_stack_pop(txtvm_stack *stack, txtvm_stacklet **s);
ERRORCODE(TXTVM_EMPTY_STACK, "empty stack.")
int txtvm_stack_pop(txtvm_stack *stack, txtvm_stacklet **s)
{
if (stack->pos == 0) return TXTVM_EMPTY_STACK;
stack->pos--;
*s = &stack->s[stack->pos];
return TXTVM_OK;
}
int txtvm_stack_push(txtvm_stack *stack, txtvm_stacklet **s);
ERRORCODE(TXTVM_STACK_OVERFLOW, "stack overflow.")
int txtvm_stack_push(txtvm_stack *stack, txtvm_stacklet **s)
{
if (stack->pos >= TXTVM_STACKSIZE) {
return TXTVM_STACK_OVERFLOW;
}
*s = &stack->s[stack->pos];
stack->pos++;
return TXTVM_OK;
}
Stacklets must be initialized and set to be certain values. Internally, the stacklet will set the correct type flag and value.
Stacklets by default are first initialized with
txtvm_stacklet_init
. This will set them to be an empty
type.
void txtvm_stacklet_init(txtvm_stacklet *s);
void txtvm_stacklet_init(txtvm_stacklet *s)
{
<<stacklet_init>>
}
Typed pops for certain types can be arranged. Floating point values and integers, for instance. In addition to the pop operation, the type flag is checked.
A integer is retrieved with txtvm_stack_pop_int
.
int txtvm_stack_pop_int(txtvm_stack *stack, int *i);
ERRORCODE(TXTVM_WRONG_TYPE, "wrong type.")
int txtvm_stack_pop_int(txtvm_stack *stack, int *i)
{
int rc;
txtvm_stacklet *s;
rc = TXTVM_OK;
rc = txtvm_stack_pop(stack, &s);
if (rc != TXTVM_OK) return rc;
if (s->type != TYPE_INT) return TXTVM_WRONG_TYPE;
/* TODO: make functions for this */
*i = s->ival;
return rc;
}
An integer value can be pushed to the stack with
txtvm_stack_push_int
.
int txtvm_stack_push_int(txtvm_stack *stack, int i);
int txtvm_stack_push_int(txtvm_stack *stack, int i)
{
txtvm_stacklet *s;
int rc;
rc = txtvm_stack_push(stack, &s);
if (txtvm_errcheck(rc)) return rc;
/* TODO: make functions for this */
s->ival = i;
s->type = TYPE_INT;
return TXTVM_OK;
}
prev | home | next