starting work on assembler
This commit is contained in:
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
But uhh that's the name of the VM itself, the name of the programming language I made is Sylt, named after the German island.
|
But uhh that's the name of the VM itself, the name of the programming language I made is Sylt, named after the German island.
|
||||||
|
|
||||||
To compile for Linux: `gcc src/main.c src/vmbl.c src/exception.c src/asm/tokenize.c -o VMBL -O3`
|
To compile the VM for Linux: `gcc src/main.c src/vmbl.c src/exception.c src/file_utils.c -o vmbl -O3`
|
||||||
|
To compile SASM for Linux: `gcc src/asm/sasm.c src/asm/tokenize.c src/file_utils.c src/asm/assembler.c -o sasm -O3`
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
### Example "Hello, World!" Program
|
### Example "Hello, World!" Program
|
||||||
|
|||||||
17
src/asm/assembler.c
Normal file
17
src/asm/assembler.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include "assembler.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void assemble(Tokenizer *tokenizer) {
|
||||||
|
Token token = getCurrentToken(tokenizer);
|
||||||
|
while (token.type != TOKEN_EOF)
|
||||||
|
{
|
||||||
|
//printf("%s: %s - line %d\n", tokenTypeAsCStr(token.type), token.value, token.line);
|
||||||
|
|
||||||
|
|
||||||
|
//free(token.value);
|
||||||
|
token = getCurrentToken(tokenizer);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
free(token.value);
|
||||||
|
}
|
||||||
8
src/asm/assembler.h
Normal file
8
src/asm/assembler.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef ASSEMBLER_H
|
||||||
|
#define ASSEMBLER_H
|
||||||
|
|
||||||
|
#include "tokenize.h"
|
||||||
|
|
||||||
|
void assemble(Tokenizer *tokenizer);
|
||||||
|
|
||||||
|
#endif // !ASSEMBLER_H
|
||||||
18
src/asm/instructions.h
Normal file
18
src/asm/instructions.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef INSTRUCTIONS_H
|
||||||
|
#define INSTRUCTIONS_H
|
||||||
|
|
||||||
|
#define MAX_ARGS 3
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ARG_TYPE_INT
|
||||||
|
} ArgType;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *mnemonic,
|
||||||
|
uint8_t argCount,
|
||||||
|
ArgType args[MAX_ARGS]
|
||||||
|
} InstructionInfo;
|
||||||
|
|
||||||
|
#endif // !INSTRUCTIONS_H
|
||||||
27
src/asm/sasm.c
Normal file
27
src/asm/sasm.c
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "tokenize.h"
|
||||||
|
#include "../file_utils.h"
|
||||||
|
#include "assembler.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Usage: sasm <file_path> <output_path>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buffer = readStringFromFile(argv[1]);
|
||||||
|
|
||||||
|
//printf("%s\n", buffer);
|
||||||
|
Tokenizer tokenizer = {
|
||||||
|
.source = buffer,
|
||||||
|
.column = 1,
|
||||||
|
.line = 1,
|
||||||
|
.pos = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
assemble(&tokenizer);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,24 +1,86 @@
|
|||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns a string buffer containing the name that was parsed.
|
||||||
|
* IMPORTANT: remember to free the buffer when you're done with it!
|
||||||
|
*/
|
||||||
char *parseName(Tokenizer *tokenizer) {
|
char *parseName(Tokenizer *tokenizer) {
|
||||||
char *ptr = tokenizer->source;
|
char *ptr = tokenizer->source;
|
||||||
|
|
||||||
|
// loop over the string until we hit something that isn't a name
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (isName(*ptr++))
|
while (isName(*ptr++))
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
|
tokenizer->column++;
|
||||||
|
tokenizer->pos++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%d\n", i);
|
char *buffer = (char*)malloc(sizeof(char) * (i + 1)); // add 1 byte for null terminator
|
||||||
return "hi";
|
|
||||||
|
if (buffer == NULL) {
|
||||||
|
fprintf(stderr, "SASM: failed to allocate memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = strncpy(buffer, tokenizer->source, i);
|
||||||
|
|
||||||
|
tokenizer->source += i;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *parseNumber(Tokenizer *tokenizer) {
|
||||||
|
int i = 0;
|
||||||
|
char *ptr = tokenizer->source;
|
||||||
|
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
if (*ptr == '\n') {
|
||||||
|
//tokenizer->column = 1;
|
||||||
|
tokenizer->pos++;
|
||||||
|
//tokenizer->line++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isspace(*ptr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
tokenizer->column++;
|
||||||
|
tokenizer->pos++;
|
||||||
|
*ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buffer = (char*)malloc(sizeof(char) * (i + 1)); // add 1 byte for null terminator
|
||||||
|
if (buffer == NULL) {
|
||||||
|
fprintf(stderr, "SASM: failed to allocate memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = strncpy(buffer, tokenizer->source, i);
|
||||||
|
|
||||||
|
tokenizer->source += i;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseWhitespace(Tokenizer *tokenizer) {
|
||||||
|
tokenizer->pos++;
|
||||||
|
tokenizer->column++;
|
||||||
|
*tokenizer->source++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool isNumber(char character) {
|
bool isNumber(char character) {
|
||||||
return isalnum(character) || character == '.';
|
return isdigit(character) || character == '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isName(char character) {
|
bool isName(char character) {
|
||||||
@@ -26,17 +88,72 @@ bool isName(char character) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token getCurrentToken(Tokenizer *tokenizer) {
|
Token getCurrentToken(Tokenizer *tokenizer) {
|
||||||
Token token = (Token){};
|
Token token = (Token){
|
||||||
|
.line = tokenizer->line,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!*tokenizer->source) {
|
||||||
|
token.type = TOKEN_EOF;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
switch (*tokenizer->source)
|
switch (*tokenizer->source)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
parseWhitespace(tokenizer);
|
||||||
|
return getCurrentToken(tokenizer);
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
parseWhitespace(tokenizer);
|
||||||
|
return getCurrentToken(tokenizer);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
tokenizer->column = 1;
|
||||||
|
tokenizer->line++;
|
||||||
|
tokenizer->pos++;
|
||||||
|
*tokenizer->source++;
|
||||||
|
return getCurrentToken(tokenizer);
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
tokenizer->pos++;
|
||||||
|
*tokenizer->source++;
|
||||||
|
return getCurrentToken(tokenizer);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (isName(*tokenizer->source)) {
|
if (isalpha(*tokenizer->source)) {
|
||||||
char *tokenValue = parseName(tokenizer);
|
char *tokenValue = parseName(tokenizer);
|
||||||
|
token.value = tokenValue;
|
||||||
|
|
||||||
|
// check if the token is in the list of instruction names
|
||||||
|
token.type = TOKEN_NAME; // by default the token is a name until we find an instruction
|
||||||
|
for (int i = 0; i < sizeof(INSTRUCTION_NAMES)/sizeof(INSTRUCTION_NAMES[0]); i++) {
|
||||||
|
|
||||||
|
// if we found an instruction with the same name as the token
|
||||||
|
if (strcmp(INSTRUCTION_NAMES[i], tokenValue) == 0) {
|
||||||
|
token.type = TOKEN_INSTRUCTION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (isdigit(*tokenizer->source)) {
|
||||||
|
char *tokenValue = parseNumber(tokenizer);
|
||||||
|
token.value = tokenValue;
|
||||||
|
|
||||||
|
// TODO: floating point numbers
|
||||||
|
token.type = TOKEN_INT_LITERAL;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid token `%c` on line %d, column %d\n", *tokenizer->source, tokenizer->line, tokenizer->column);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* tokenTypeAsCStr(TokenType type) {
|
char* tokenTypeAsCStr(TokenType type) {
|
||||||
@@ -49,6 +166,14 @@ char* tokenTypeAsCStr(TokenType type) {
|
|||||||
case TOKEN_INT_LITERAL:
|
case TOKEN_INT_LITERAL:
|
||||||
return "INT_LITERAL";
|
return "INT_LITERAL";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOKEN_EOF:
|
||||||
|
return "<EOF>";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOKEN_NAME:
|
||||||
|
return "NAME";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -3,9 +3,30 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static char *INSTRUCTION_NAMES[] = {
|
||||||
|
"push",
|
||||||
|
"drop",
|
||||||
|
"add",
|
||||||
|
"sub",
|
||||||
|
"mul",
|
||||||
|
"div",
|
||||||
|
"eq",
|
||||||
|
"neq",
|
||||||
|
"gt",
|
||||||
|
"gte",
|
||||||
|
"lt",
|
||||||
|
"lte",
|
||||||
|
"dup",
|
||||||
|
"jc",
|
||||||
|
"halt",
|
||||||
|
"jump"
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
TOKEN_EOF, // just used when looping over the tokens list
|
||||||
TOKEN_INSTRUCTION,
|
TOKEN_INSTRUCTION,
|
||||||
|
TOKEN_NAME,
|
||||||
TOKEN_INT_LITERAL,
|
TOKEN_INT_LITERAL,
|
||||||
} TokenType;
|
} TokenType;
|
||||||
|
|
||||||
@@ -13,6 +34,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
TokenType type;
|
TokenType type;
|
||||||
char* value;
|
char* value;
|
||||||
|
unsigned int line;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -25,9 +47,12 @@ typedef struct
|
|||||||
|
|
||||||
bool isNumber(char character);
|
bool isNumber(char character);
|
||||||
bool isName(char character);
|
bool isName(char character);
|
||||||
|
|
||||||
Token getCurrentToken(Tokenizer *tokenizer);
|
Token getCurrentToken(Tokenizer *tokenizer);
|
||||||
char* tokenTypeAsCStr(TokenType type);
|
char* tokenTypeAsCStr(TokenType type);
|
||||||
|
|
||||||
char *parseName(Tokenizer *tokenizer);
|
char *parseName(Tokenizer *tokenizer);
|
||||||
|
char *parseNumber(Tokenizer *tokenizer);
|
||||||
|
void parseWhitespace(Tokenizer *tokenizer);
|
||||||
|
|
||||||
#endif // !TOKENIZE_H
|
#endif // !TOKENIZE_H
|
||||||
|
|||||||
46
src/file_utils.c
Normal file
46
src/file_utils.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
|
char *readStringFromFile(char* file_path) {
|
||||||
|
FILE *inputFile = fopen(file_path, "r");
|
||||||
|
if (inputFile == NULL) {
|
||||||
|
perror("SASM: failed to open file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (fseek(inputFile, 0, SEEK_END)) {
|
||||||
|
perror("SASM: failed to seek to end of file");
|
||||||
|
fclose(inputFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
long file_size = ftell(inputFile);
|
||||||
|
if (file_size == -1) {
|
||||||
|
perror("SASM: error getting file size");
|
||||||
|
fclose(inputFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(inputFile, 0, SEEK_SET) != 0) {
|
||||||
|
perror("SASM: failed to seek to start of file");
|
||||||
|
fclose(inputFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buffer = (char*)malloc(file_size + 1);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
printf("SASM: failed to allocate memory");
|
||||||
|
fclose(inputFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytesRead = fread(buffer, 1, file_size, inputFile);
|
||||||
|
if (bytesRead != file_size) {
|
||||||
|
perror("SASM: error reading file");
|
||||||
|
free(buffer);
|
||||||
|
fclose(inputFile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fclose(inputFile);
|
||||||
|
|
||||||
|
buffer[file_size+1] = '\0';
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
9
src/file_utils.h
Normal file
9
src/file_utils.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef FILE_UTILS_H
|
||||||
|
#define FILE_UTILS_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
char *readStringFromFile(char* file_path);
|
||||||
|
|
||||||
|
#endif // !FILE_UTILS_H
|
||||||
26
src/main.c
26
src/main.c
@@ -5,24 +5,20 @@
|
|||||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]));
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]));
|
||||||
|
|
||||||
VMBL_Instruction program[] = {
|
VMBL_Instruction program[] = {
|
||||||
MAKE_INST_PUSH(124),
|
MAKE_INST_PUSH(0),
|
||||||
MAKE_INST_PUSH(2),
|
MAKE_INST_PUSH(1),
|
||||||
MAKE_INST_DIV,
|
MAKE_INST_DUP(1),
|
||||||
MAKE_INST_HALT
|
MAKE_INST_DUP(1),
|
||||||
|
MAKE_INST_ADD,
|
||||||
|
MAKE_INST_JMP(2)
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
//VMBL_State vmblState = {};
|
VMBL_State vmblState = {};
|
||||||
|
|
||||||
//VMBL_LoadExecutable(&vmblState, program, sizeof(program));
|
|
||||||
//VMBL_StartVM(&vmblState);
|
|
||||||
|
|
||||||
Tokenizer tokenizer = {
|
|
||||||
"push 1224\npush 2\ndiv\nhalt"
|
|
||||||
};
|
|
||||||
Token token = getCurrentToken(&tokenizer);
|
|
||||||
|
|
||||||
printf("%s\n", tokenTypeAsCStr(token.type));
|
|
||||||
|
|
||||||
|
VMBL_LoadExecutable(&vmblState, program, sizeof(program));
|
||||||
|
//VMBL_SaveExecutable("fib.vmbl", program, sizeof(program));
|
||||||
|
VMBL_StartVM(&vmblState);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
18
src/vmbl.c
18
src/vmbl.c
@@ -1,4 +1,5 @@
|
|||||||
#include "vmbl.h"
|
#include "vmbl.h"
|
||||||
|
#include "file_utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -93,6 +94,9 @@ VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction i
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INSTRUCTION_NOP:
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE };
|
return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE };
|
||||||
break;
|
break;
|
||||||
@@ -126,7 +130,7 @@ void VMBL_StartVM(VMBL_State *vmblState) {
|
|||||||
|
|
||||||
|
|
||||||
VMBL_Instruction instruction = vmblState->program[vmblState->ip++];
|
VMBL_Instruction instruction = vmblState->program[vmblState->ip++];
|
||||||
printf("%s 0x%lx, 0x%lx, 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperands[0], instruction.opperands[1], instruction.opperands[2]);
|
//printf("%s 0x%lx, 0x%lx, 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperands[0], instruction.opperands[1], instruction.opperands[2]);
|
||||||
|
|
||||||
VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction);
|
VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction);
|
||||||
|
|
||||||
@@ -156,8 +160,8 @@ void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_
|
|||||||
vmblState->programSize = programSize;
|
vmblState->programSize = programSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) {
|
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath) {
|
||||||
FILE *file = fopen(filePath, "rb");
|
/*FILE *file = fopen(filePath, "rb");
|
||||||
|
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
perror("VMBL: Failed to open file");
|
perror("VMBL: Failed to open file");
|
||||||
@@ -170,11 +174,13 @@ void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) {
|
|||||||
|
|
||||||
size_t programSize = size / sizeof(vmblState->program[0]);
|
size_t programSize = size / sizeof(vmblState->program[0]);
|
||||||
VMBL_Instruction program[programSize];
|
VMBL_Instruction program[programSize];
|
||||||
fread(program, sizeof(program[0]), programSize, file);
|
fread(program, sizeof(program[0]), programSize, file);*/
|
||||||
|
|
||||||
VMBL_LoadExecutable(vmblState, program, programSize);
|
VMBL_Instruction *program = (VMBL_Instruction*)readStringFromFile(filePath);
|
||||||
|
|
||||||
fclose(file);
|
VMBL_LoadExecutable(vmblState, program, sizeof(program));
|
||||||
|
|
||||||
|
//fclose(file);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ typedef int64_t Word;
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
INSTRUCTION_NOP,
|
||||||
|
|
||||||
// stack operations
|
// stack operations
|
||||||
INSTRUCTION_PUSH,
|
INSTRUCTION_PUSH,
|
||||||
INSTRUCTION_ADD,
|
INSTRUCTION_ADD,
|
||||||
@@ -34,7 +36,7 @@ typedef enum
|
|||||||
INSTRUCTION_LESS_THAN,
|
INSTRUCTION_LESS_THAN,
|
||||||
INSTRUCTION_LESS_THAN_EQUAL,
|
INSTRUCTION_LESS_THAN_EQUAL,
|
||||||
INSTRUCTION_GREATER_THAN,
|
INSTRUCTION_GREATER_THAN,
|
||||||
INSTRUCTION_GREATER_THAN_EQUAL,
|
INSTRUCTION_GREATER_THAN_EQUAL
|
||||||
} InstructionType;
|
} InstructionType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -77,7 +79,7 @@ void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception);
|
|||||||
void VMBL_StartVM(VMBL_State *vmblState);
|
void VMBL_StartVM(VMBL_State *vmblState);
|
||||||
|
|
||||||
void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize);
|
void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize);
|
||||||
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath);
|
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath);
|
||||||
void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize);
|
void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize);
|
||||||
|
|
||||||
char *instructionTypeToCStr(InstructionType type);
|
char *instructionTypeToCStr(InstructionType type);
|
||||||
|
|||||||
Reference in New Issue
Block a user