Initial commit. My implementation of Clox, the programming language constructed from the book 'Crafting Interpreters'
This commit is contained in:
commit
d6281d2f5c
|
@ -0,0 +1,82 @@
|
|||
# Detect OS
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ISWIN := 1
|
||||
endif
|
||||
|
||||
ifdef ISWIN
|
||||
CC := i686-w64-mingw32-gcc
|
||||
else
|
||||
CC := gcc
|
||||
endif
|
||||
|
||||
RM ?= rm -f
|
||||
RMDIR ?= rm -rf
|
||||
MKDIR ?= mkdir -p
|
||||
|
||||
WARFLAGS := -Wall -Wextra -pedantic
|
||||
|
||||
CFLAGS_g := $(WARFLAGS) -std=gnu11 -O2 -msse2 -ffast-math -mfpmath=sse -DNDEBUG \
|
||||
-MMD
|
||||
|
||||
LDFLAGS_g := -s
|
||||
|
||||
# object output dir
|
||||
OBJDIR_g := obj_g
|
||||
|
||||
SRCS := $(wildcard *.c)
|
||||
OBJS_g := $(SRCS:.c=.o)
|
||||
|
||||
# include dirs
|
||||
CFLAGS_g +=
|
||||
|
||||
# libs
|
||||
ifdef ISWIN
|
||||
LDFLAGS_g +=
|
||||
else
|
||||
CFLAGS_g +=
|
||||
LDFLAGS_g +=
|
||||
endif
|
||||
|
||||
# binary target
|
||||
ifdef ISWIN
|
||||
TARG_g := clox.exe
|
||||
else
|
||||
TARG_g := clox
|
||||
endif
|
||||
|
||||
game: $(TARG_g)
|
||||
@echo "*** Target '$@': '$^' is up to date!"
|
||||
|
||||
default: game
|
||||
|
||||
.PHONY: default game clean
|
||||
|
||||
# rewrite OBJS so it outputs object files to seperate dir
|
||||
|
||||
OBJS_g := $(patsubst %,$(OBJDIR_g)/%,$(OBJS_g))
|
||||
|
||||
# include the dependency rules generated by -MMD
|
||||
|
||||
-include $(OBJS_g:.o=.d)
|
||||
|
||||
clean:
|
||||
@echo "*** Removing target binary and object directory..."
|
||||
@$(RM) $(TARG_g)
|
||||
@$(RMDIR) $(OBJDIR_g)
|
||||
@echo "*** Done."
|
||||
|
||||
# Compile
|
||||
|
||||
$(OBJDIR_g)/%.o: %.c
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "*** Compiling '$<' ..."
|
||||
@$(CC) $(CFLAGS_g) -c $< -o $@
|
||||
|
||||
# Link
|
||||
|
||||
$(TARG_g): $(OBJS_g)
|
||||
@$(MKDIR) $(@D)
|
||||
@echo "\n*** Linking binary target '$@' ...\n"
|
||||
@$(CC) $(OBJS_g) -o $@ $(LDFLAGS_g)
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
#include "chunk.h"
|
||||
#include "memory.h"
|
||||
#include "value.h"
|
||||
|
||||
void initChunk( Chunk* chunk ) {
|
||||
chunk->capacity = 0;
|
||||
chunk->count = 0;
|
||||
chunk->bDebug = true;
|
||||
chunk->code = NULL;
|
||||
chunk->lines = NULL;
|
||||
initValueArray( &chunk->constants );
|
||||
}
|
||||
|
||||
void freeChunk( Chunk* chunk ) {
|
||||
FREE_ARRAY( uint8_t, chunk->code, chunk->capacity );
|
||||
FREE_ARRAY( uint16_t, chunk->lines, chunk->capacity );
|
||||
freeValueArray( &chunk->constants );
|
||||
initChunk( chunk );
|
||||
}
|
||||
|
||||
void writeChunk( Chunk* chunk, uint8_t byte, uint16_t line ) {
|
||||
if ( chunk->capacity < chunk->count + 1 ) {
|
||||
int oldCap = chunk->capacity;
|
||||
chunk->capacity = GROW_CAPACITY( oldCap );
|
||||
chunk->code = GROW_ARRAY( chunk->code, uint8_t, oldCap, chunk->capacity );
|
||||
if ( chunk->bDebug ) {
|
||||
chunk->lines = GROW_ARRAY( chunk->lines, uint16_t, oldCap, chunk->capacity );
|
||||
}
|
||||
}
|
||||
|
||||
chunk->code[chunk->count] = byte;
|
||||
if ( chunk->bDebug )
|
||||
chunk->lines[chunk->count] = line;
|
||||
chunk->count++;
|
||||
}
|
||||
|
||||
// unsigned 16bit write
|
||||
void writeChunk16( Chunk* chunk, uint16_t word, uint16_t line ) {
|
||||
writeChunk( chunk, word & 255, line );
|
||||
writeChunk( chunk, word >> 8, line );
|
||||
}
|
||||
// unsigned 16bit read
|
||||
uint16_t readChunk16( Chunk* chunk, int offset ) {
|
||||
uint16_t val = chunk->code[offset];
|
||||
return ((val) | (chunk->code[offset + 1] << 8));
|
||||
}
|
||||
|
||||
uint16_t addConstant( Chunk* chunk, Value val ) {
|
||||
writeValueArray( &chunk->constants, val );
|
||||
return chunk->constants.count - 1;
|
||||
}
|
||||
|
||||
// high level for adding and writing a chunk constant
|
||||
void writeConstant( Chunk* chunk, Value val, uint16_t line ) {
|
||||
uint16_t cont = addConstant( chunk, val );
|
||||
// more than 256 constants, use 16bit operand
|
||||
if ( cont > 255 ) {
|
||||
writeChunk( chunk, OP_CONSTANT_LONG, line );
|
||||
writeChunk16( chunk, cont, line );
|
||||
} else {
|
||||
writeChunk( chunk, OP_CONSTANT, line );
|
||||
writeChunk( chunk, cont, line );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef _CHUNK_H
|
||||
#define _CHUNK_H
|
||||
|
||||
#include "common.h"
|
||||
#include "value.h"
|
||||
|
||||
// max 256 opcodes
|
||||
typedef enum {
|
||||
OP_CONSTANT, OP_CONSTANT_LONG,
|
||||
OP_ADD, OP_SUBTRACT,
|
||||
OP_MULTIPLY, OP_DIVIDE,
|
||||
OP_NEGATE,
|
||||
OP_RETURN,
|
||||
|
||||
NUM_OP, // total number of valid opcodes
|
||||
} OpCode;
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
int capacity;
|
||||
bool bDebug; // if line numbers are kept or not
|
||||
uint8_t* code;
|
||||
uint16_t* lines; // 16bit line numbers
|
||||
ValueArray constants;
|
||||
} Chunk;
|
||||
|
||||
void initChunk( Chunk* chunk );
|
||||
void freeChunk( Chunk* chunk );
|
||||
|
||||
// write single byte to code memory
|
||||
void writeChunk( Chunk* chunk, uint8_t byte, uint16_t line );
|
||||
// u16 write / read
|
||||
void writeChunk16( Chunk* chunk, uint16_t word, uint16_t line );
|
||||
uint16_t readChunk16( Chunk* chunk, int offset );
|
||||
|
||||
// add constant val to chunk's array. return index where it was added
|
||||
uint16_t addConstant( Chunk* chunk, Value val );
|
||||
|
||||
// high level for adding and writing chunk constants
|
||||
void writeConstant( Chunk* chunk, Value val, uint16_t line );
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEBUG_TRACE_EXECUTION
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include "compiler.h"
|
||||
//#include "scanner.h"
|
||||
|
||||
void compile( VM* vm, const char* src ) {
|
||||
//initScanner( src );
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _COMPILER_H
|
||||
#define _COMPILER_H
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
void compile( VM* vm, const char* src );
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
//#include <stdio.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "value.h"
|
||||
|
||||
void disassembleChunk( Chunk* chunk, const char* name ) {
|
||||
printChunkInfo( chunk, name );
|
||||
for ( int i = 0; i < chunk->count; ) {
|
||||
i = disassembleInstruction( chunk, i );
|
||||
}
|
||||
}
|
||||
|
||||
void printChunkInfo( Chunk* chunk, const char* name ) {
|
||||
int codesz = chunk->count * sizeof(chunk->code[0]);
|
||||
int codecapsz = chunk->capacity * sizeof(chunk->code[0]);
|
||||
int concnt = chunk->constants.count;
|
||||
int concap = chunk->constants.capacity;
|
||||
int consz = concnt * sizeof(chunk->constants.values[0]);
|
||||
int concapsz = concap * sizeof(chunk->constants.values[0]);
|
||||
|
||||
int linesz = sizeof(chunk->lines[0]) * chunk->count;
|
||||
int linecapsz = sizeof(chunk->lines[0]) * chunk->capacity;
|
||||
if ( !chunk->bDebug ) {
|
||||
linesz = 0; linecapsz = 0;
|
||||
}
|
||||
|
||||
printf( "=== Chunk \"%s\" Info ===\n=== Code size: %d(%d) bytes ===\n"
|
||||
"=== Constants: %d(%d) (%d(%d) bytes) ===\n=== Debug lines size: %d(%d) bytes ===\n", name,
|
||||
codesz, codecapsz, concnt, concap, consz, concapsz, linesz,linecapsz );
|
||||
printf( "=== Total size: %d(%d) bytes ===\n", sizeof(Chunk)+codesz+consz+linesz, sizeof(Chunk)+codecapsz+concapsz+linecapsz );
|
||||
}
|
||||
|
||||
static int constantInstruction( const char* name, Chunk* chunk, int offset ) {
|
||||
uint16_t cons = 0;
|
||||
|
||||
cons = chunk->code[offset + 1];
|
||||
|
||||
if ( chunk->code[offset] == OP_CONSTANT_LONG ) {
|
||||
name = "OP_CONSTANT_LONG";
|
||||
cons = readChunk16( chunk, offset + 1 );
|
||||
}
|
||||
|
||||
printf( "%-16s %05u '", name, cons );
|
||||
Value conVal = -9001; // cons index out of range
|
||||
if ( cons < chunk->constants.count )
|
||||
conVal = chunk->constants.values[cons];
|
||||
printValue( conVal );
|
||||
printf( "'\n" );
|
||||
|
||||
return ((cons > 255) ? (offset + 3) : (offset + 2));
|
||||
}
|
||||
|
||||
static int simpleInstruction( const char* name, int offset ) {
|
||||
printf( "%s\n", name );
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
int disassembleInstruction( Chunk* chunk, int offset ) {
|
||||
printf( "0x%08x ", offset );
|
||||
if ( chunk->bDebug ) {
|
||||
if ( offset > 0 && chunk->lines[offset] == chunk->lines[offset - 1] ) {
|
||||
printf( " | " );
|
||||
} else {
|
||||
printf( "%04d ", chunk->lines[offset] );
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t instruction = chunk->code[offset];
|
||||
switch ( instruction ) {
|
||||
case OP_CONSTANT:
|
||||
case OP_CONSTANT_LONG:
|
||||
return constantInstruction( "OP_CONSTANT", chunk, offset );
|
||||
case OP_ADD:
|
||||
return simpleInstruction( "OP_ADD", offset );
|
||||
case OP_SUBTRACT:
|
||||
return simpleInstruction( "OP_SUBTRACT", offset );
|
||||
case OP_MULTIPLY:
|
||||
return simpleInstruction( "OP_MULTIPLY", offset );
|
||||
case OP_DIVIDE:
|
||||
return simpleInstruction( "OP_DIVIDE", offset );
|
||||
case OP_NEGATE:
|
||||
return simpleInstruction( "OP_NEGATE", offset );
|
||||
case OP_RETURN:
|
||||
return simpleInstruction( "OP_RETURN", offset );
|
||||
default:
|
||||
printf( "UNK OP %d\n", instruction );
|
||||
return offset + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _DEBUG_H
|
||||
#define _DEBUG_H
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
void printChunkInfo( Chunk* chunk, const char* name );
|
||||
void disassembleChunk( Chunk* chunk, const char* name );
|
||||
int disassembleInstruction( Chunk* chunk, int offset );
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#include "common.h"
|
||||
#include "chunk.h"
|
||||
#include "debug.h"
|
||||
#include "vm.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static void repl( VM* vm ) {
|
||||
char line[512];
|
||||
|
||||
for ( ; ; ) {
|
||||
printf( "> " );
|
||||
if ( !fgets( line, sizeof(line), stdin ) ) {
|
||||
printf( "\n" ); break;
|
||||
}
|
||||
interpret( vm, line );
|
||||
}
|
||||
}
|
||||
|
||||
static char* readFile( const char* path ) {
|
||||
FILE* file = fopen( path, "rb" );
|
||||
if ( file == NULL ) {
|
||||
fprintf( stderr, "Error opening file: \"%s\"\n", path );
|
||||
exit( 74 );
|
||||
}
|
||||
|
||||
fseek( file, 0, SEEK_END );
|
||||
size_t sz = ftell( file );
|
||||
rewind( file );
|
||||
|
||||
char* src = (char*)malloc( sz + 1 );
|
||||
if ( src == NULL ) {
|
||||
fprintf( stderr, "Error allocating memory for file: \"%s\"\n", path );
|
||||
exit( 74 );
|
||||
}
|
||||
size_t bread = fread( src, sizeof(char), sz, file );
|
||||
if ( bread < sz ) {
|
||||
fprintf( stderr, "Error reading file: \"%s\"\n", path );
|
||||
exit( 74 );
|
||||
}
|
||||
src[bread] = '\0';
|
||||
|
||||
fclose( file );
|
||||
return src;
|
||||
}
|
||||
|
||||
static void runFile( VM* vm, const char* path ) {
|
||||
char* source = readFile( path );
|
||||
InterpretResult res = interpret( vm, source );
|
||||
free( source );
|
||||
if ( res == INTERPRET_COMPILE_ERROR ) exit( 65 );
|
||||
if ( res == INTERPRET_RUNTIME_ERROR ) exit( 70 );
|
||||
}
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
(void)argc; (void)argv;
|
||||
srand( time( NULL ) );
|
||||
|
||||
double dfp = 22.0 / 7.0;
|
||||
printf( "DFP: %.64g\n", dfp );
|
||||
|
||||
float ffp = 22.0f / 7.0f;
|
||||
printf( "FFP: %.64f\n", ffp );
|
||||
|
||||
VM vm;
|
||||
initVM( &vm );
|
||||
|
||||
if ( argc == 1 ) {
|
||||
repl( &vm );
|
||||
} else if ( argc == 2 ) {
|
||||
runFile( &vm, argv[1] );
|
||||
} else {
|
||||
fprintf( stderr, "Usage: clox [path]\n" );
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
|
||||
/*Chunk c;
|
||||
initChunk( &c );
|
||||
//c.bDebug = false;
|
||||
|
||||
writeConstant( &c, 4.2f, 1 );
|
||||
writeConstant( &c, rand()/(float)RAND_MAX, 2 );
|
||||
|
||||
//for ( int i = 0; i < 10; ++i )
|
||||
// writeChunk( &c, rand() % NUM_OP, 5 );
|
||||
|
||||
// const overload
|
||||
for ( int i = 2; i < 6; ++i ) {
|
||||
writeConstant( &c, (float)rand()/RAND_MAX, 6 );
|
||||
}
|
||||
|
||||
writeConstant( &c, 69069, 9 );
|
||||
writeChunk( &c, OP_NEGATE, 9 );
|
||||
|
||||
writeConstant( &c, 22, 9 );
|
||||
writeChunk( &c, OP_ADD, 9 );
|
||||
|
||||
writeConstant( &c, 42, 9 );
|
||||
writeChunk( &c, OP_DIVIDE, 9 );
|
||||
|
||||
writeChunk( &c, OP_RETURN, 10 );
|
||||
|
||||
//disassembleChunk( &c, "test" );
|
||||
|
||||
interpret( &vm, &c );
|
||||
printChunkInfo( &c, "test" );
|
||||
|
||||
printf( "vm %u chunk %u valar %u\n", sizeof(VM), sizeof(Chunk), sizeof(ValueArray) );
|
||||
|
||||
freeChunk( &c );*/
|
||||
|
||||
freeVM( &vm );
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//void* malloc( size_t sz ) {}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#include "common.h"
|
||||
#include "memory.h"
|
||||
|
||||
void* reallocate( void* prev, size_t oldSz, size_t newSz ) {
|
||||
(void)oldSz;
|
||||
if ( newSz == 0 ) {
|
||||
free( prev ); prev = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return realloc( prev, newSz );
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _MEMORY_H
|
||||
#define _MEMORY_H
|
||||
|
||||
#define GROW_CAPACITY( cap ) \
|
||||
((cap) < 8 ? 8 : (cap) * 1.5f)
|
||||
|
||||
#define GROW_ARRAY( prev, type, oldCnt, newCnt ) \
|
||||
(type*)reallocate( prev, sizeof(type) * (oldCnt), sizeof(type) * (newCnt) )
|
||||
|
||||
#define FREE_ARRAY( type, ptr, oldCnt ) \
|
||||
reallocate( ptr, sizeof(type) * (oldCnt), 0 )
|
||||
|
||||
void* reallocate( void* prev, size_t oldSz, size_t newSz );
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#include "value.h"
|
||||
#include "memory.h"
|
||||
|
||||
void initValueArray( ValueArray* array ) {
|
||||
array->capacity = 0;
|
||||
array->count = 0;
|
||||
array->values = NULL;
|
||||
}
|
||||
|
||||
void writeValueArray( ValueArray* array, Value val ) {
|
||||
if ( array->capacity < array->count + 1 ) {
|
||||
int oldCap = array->capacity;
|
||||
array->capacity = GROW_CAPACITY( oldCap );
|
||||
array->values = GROW_ARRAY( array->values, Value, oldCap, array->capacity );
|
||||
}
|
||||
|
||||
array->values[array->count] = val;
|
||||
array->count++;
|
||||
}
|
||||
|
||||
void freeValueArray( ValueArray* array ) {
|
||||
FREE_ARRAY( Value, array->values, array->capacity );
|
||||
initValueArray( array );
|
||||
}
|
||||
|
||||
void printValue( Value val ) {
|
||||
printf( "%g", val );
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef _VALUE_H
|
||||
#define _VALUE_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef float Value;
|
||||
|
||||
typedef struct {
|
||||
int capacity;
|
||||
int count;
|
||||
Value* values;
|
||||
} ValueArray;
|
||||
|
||||
void initValueArray( ValueArray* array );
|
||||
void writeValueArray( ValueArray* array, Value val );
|
||||
void freeValueArray( ValueArray* array );
|
||||
void printValue( Value val );
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#include "common.h"
|
||||
#include "vm.h"
|
||||
#include "compiler.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void resetStack( VM* vm ) {
|
||||
vm->sp = vm->stack;
|
||||
}
|
||||
|
||||
void initVM( VM* vm ) {
|
||||
resetStack( vm );
|
||||
}
|
||||
|
||||
void freeVM( VM* vm ) {
|
||||
(void)vm;
|
||||
}
|
||||
|
||||
void push( VM* vm, Value val ) {
|
||||
if ( vm->sp - vm->stack >= MAX_STACK ) {
|
||||
printf( "VM Error: Stack is full.\n" );
|
||||
resetStack( vm );
|
||||
}
|
||||
*(vm->sp) = val;
|
||||
vm->sp++;
|
||||
}
|
||||
|
||||
Value pop( VM* vm ) {
|
||||
vm->sp--;
|
||||
return *(vm->sp);
|
||||
}
|
||||
|
||||
static InterpretResult run( VM* vm ) {
|
||||
#define READ_BYTE() (*(vm->ip++))
|
||||
#define READ_CONSTANT( ix ) (vm->chunk->constants.values[ix])
|
||||
#define BINARY_OP( op ) do { Value b = pop( vm ), a = pop( vm ); \
|
||||
push( vm, a op b ); } while ( false )
|
||||
|
||||
uint8_t instruction = 0;
|
||||
|
||||
for ( ; ; ) {
|
||||
#ifdef DEBUG_TRACE_EXECUTION
|
||||
printf( "\t" );
|
||||
for ( Value* v = vm->stack; v < vm->sp; v++ ) {
|
||||
printf( "[ " );
|
||||
printValue( *v );
|
||||
printf( " ]" );
|
||||
}
|
||||
printf( "\n" );
|
||||
disassembleInstruction( vm->chunk, (int)(vm->ip - vm->chunk->code) );
|
||||
#endif
|
||||
|
||||
switch ( instruction = READ_BYTE() ) {
|
||||
case OP_CONSTANT:
|
||||
case OP_CONSTANT_LONG: {
|
||||
uint16_t cons = READ_BYTE();
|
||||
if ( instruction == OP_CONSTANT_LONG )
|
||||
cons |= (READ_BYTE() << 8);
|
||||
Value constant = READ_CONSTANT( cons );
|
||||
push( vm, constant );
|
||||
break;
|
||||
}
|
||||
case OP_ADD: BINARY_OP( + ); break;
|
||||
case OP_SUBTRACT: BINARY_OP( - ); break;
|
||||
case OP_MULTIPLY: BINARY_OP( * ); break;
|
||||
case OP_DIVIDE: BINARY_OP( / ); break;
|
||||
case OP_NEGATE: push( vm, -pop( vm ) ); break;
|
||||
case OP_RETURN:
|
||||
printValue( pop( vm ) );
|
||||
printf( "\n" );
|
||||
return INTERPRET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#undef BINARY_OP
|
||||
#undef READ_CONSTANT
|
||||
#undef READ_BYTE
|
||||
}
|
||||
|
||||
InterpretResult interpret( VM* vm, const char* src ) {
|
||||
/*vm->chunk = chunk;
|
||||
vm->ip = vm->chunk->code;
|
||||
return run( vm );*/
|
||||
compile( vm, src );
|
||||
return INTERPRET_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef _VM_H
|
||||
#define _VM_H
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
#define MAX_STACK 256
|
||||
|
||||
typedef struct {
|
||||
Chunk* chunk;
|
||||
uint8_t* ip;
|
||||
Value stack[MAX_STACK];
|
||||
Value* sp;
|
||||
} VM;
|
||||
|
||||
typedef enum {
|
||||
INTERPRET_OK,
|
||||
INTERPRET_COMPILE_ERROR,
|
||||
INTERPRET_RUNTIME_ERROR
|
||||
} InterpretResult;
|
||||
|
||||
void initVM( VM* vm );
|
||||
void freeVM( VM* vm );
|
||||
InterpretResult interpret( VM* vm, const char* src );
|
||||
void push( VM* vm, Value val );
|
||||
Value pop( VM* vm );
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue