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.

<<typedefs>>=
typedef struct txtvm_stacklet txtvm_stacklet;
<<structs>>=
struct txtvm_stacklet {
<<stacklet>>
};

The type flag determines the kind of item that was placed onto the stack.

<<stacklet>>=
int type;

Type values will be desribed in an enum.

<<macros>>=
enum {
    TYPE_NONE,
<<typeflags>>
    TYPE_END
};

A stacklet is initially set to be TYPE_NONE.

<<stacklet_init>>=
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.

<<typeflags>>=
TYPE_INT,
TYPE_FLOAT,
<<stacklet>>=
int ival;
float fval;
<<stacklet_init>>=
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.

<<typeflags>>=
TYPE_CPTR,
<<stacklet>>=
void *ptr;
<<stacklet_init>>=
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:

<<typedefs>>=
typedef struct txtvm_stack txtvm_stack;
<<structs>>=
#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.

<<funcdefs>>=
void txtvm_stack_init(txtvm_stack *stack);
<<funcs>>=
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.

<<stack>>=
int pos;
<<stack_init>>=
stack->pos = 0;

Both the pushing and popping values return an error code. A non-zero error code indicates some sort of failure.

<<funcdefs>>=
int txtvm_stack_pop(txtvm_stack *stack, txtvm_stacklet **s);
<<errorlist>>=
ERRORCODE(TXTVM_EMPTY_STACK, "empty stack.")
<<funcs>>=
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;
}
<<funcdefs>>=
int txtvm_stack_push(txtvm_stack *stack, txtvm_stacklet **s);
<<errorlist>>=
ERRORCODE(TXTVM_STACK_OVERFLOW, "stack overflow.")
<<funcs>>=
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.

<<funcdefs>>=
void txtvm_stacklet_init(txtvm_stacklet *s);
<<funcs>>=
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.

<<funcdefs>>=
int txtvm_stack_pop_int(txtvm_stack *stack, int *i);
<<errorlist>>=
ERRORCODE(TXTVM_WRONG_TYPE, "wrong type.")
<<funcs>>=
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.

<<funcdefs>>=
int txtvm_stack_push_int(txtvm_stack *stack, int i);
<<funcs>>=
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