make file added
This commit is contained in:
24
Makefile
Normal file
24
Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
CC=gcc
|
||||
CFLAGS=-O3 -Wall
|
||||
|
||||
SRC=src
|
||||
BIN=bin
|
||||
|
||||
VMBL_FILES=$(wildcard $(SRC)/vmbl/*.c)
|
||||
SYLT_FILES=$(wildcard $(SRC)/sylt/*.c)
|
||||
UTIL_FILES=$(wildcard $(SRC)/utils/*.c)
|
||||
|
||||
all: vmbl sylt
|
||||
|
||||
$(BIN)/vmbl: $(VMBL_FILES)
|
||||
mkdir -p $(BIN)
|
||||
$(CC) $(CFLAGS) $(UTIL_FILES) $(VMBL_FILES) -o $(BIN)/vmbl
|
||||
vmbl: $(BIN)/vmbl
|
||||
|
||||
$(BIN)/sylt: $(SYLT_FILES)
|
||||
mkdir -p $(BIN)
|
||||
$(CC) $(CFLAGS) $(UTIL_FILES) $(SYLT_FILES) -o $(BIN)/sylt
|
||||
sylt: $(BIN)/sylt
|
||||
|
||||
clean:
|
||||
rm -r $(BIN)
|
||||
@@ -9,7 +9,7 @@
|
||||
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 the VM for Linux: `gcc src/main.c src/vmbl.c src/exception.c src/file_utils.c -o vmbl -O3`
|
||||
To compile the SYLT compiler for Linux: `gcc src/sylt/main.c src/file_utils.c src/sylt/lexer.c -o sylt -O3`
|
||||
To compile the SYLT compiler for Linux: `gcc src/sylt/main.c src/sylt/exception.c src/sylt/token.c src/file_utils.c src/sylt/lexer.c -o sylt -O3`
|
||||
|
||||
SASM and Sylt are written in Python for now as I'm too mentally challenged to write C code rn.
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "exception.h"
|
||||
|
||||
char* exceptionAsCString(VMBL_Exception exception)
|
||||
{
|
||||
switch (exception.type)
|
||||
{
|
||||
case EXCEPTION_NONE:
|
||||
return "EXCEPTION_NONE";
|
||||
break;
|
||||
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return "EXCEPTION_STACK_OVERFLOW";
|
||||
break;
|
||||
|
||||
case EXCEPTION_STACK_UNDERFLOW:
|
||||
return "EXCEPTION_STACK_UNDERFLOW";
|
||||
break;
|
||||
|
||||
case EXCEPTION_INVALID_OPCODE:
|
||||
return "EXCEPTION_INVALID_OPCODE";
|
||||
break;
|
||||
|
||||
case EXCEPTION_INVALID_OPPERAND:
|
||||
return "EXCEPTION_INVALID_OPPERAND";
|
||||
break;
|
||||
|
||||
case EXCEPTION_INVALID_INSTRUCTION_ACCESS:
|
||||
return "EXCEPTION_INVALID_INSTRUCTION_ACCESS";
|
||||
break;
|
||||
|
||||
case EXCEPTION_DIVIDE_BY_ZERO:
|
||||
return "EXCEPTION_DIVIDE_BY_ZERO";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "EXCEPTION_UNKOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef EXCEPTION_H
|
||||
#define EXCEPTION_H
|
||||
|
||||
typedef enum {
|
||||
EXCEPTION_NONE,
|
||||
EXCEPTION_STACK_OVERFLOW,
|
||||
EXCEPTION_STACK_UNDERFLOW,
|
||||
EXCEPTION_INVALID_OPCODE,
|
||||
EXCEPTION_INVALID_OPPERAND,
|
||||
EXCEPTION_INVALID_INSTRUCTION_ACCESS,
|
||||
EXCEPTION_DIVIDE_BY_ZERO
|
||||
} VMBL_ExceptionType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
VMBL_ExceptionType type;
|
||||
} VMBL_Exception;
|
||||
|
||||
char* exceptionAsCString(VMBL_Exception exception);
|
||||
|
||||
#endif
|
||||
23
src/main.c
23
src/main.c
@@ -1,23 +0,0 @@
|
||||
#include "vmbl.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]));
|
||||
|
||||
VMBL_Instruction program[] = {
|
||||
MAKE_INST_PUSH(0),
|
||||
MAKE_INST_PUSH(1),
|
||||
MAKE_INST_DUP(1),
|
||||
MAKE_INST_DUP(1),
|
||||
MAKE_INST_ADD,
|
||||
MAKE_INST_JMP(2)
|
||||
};
|
||||
|
||||
int main() {
|
||||
VMBL_State vmblState = {};
|
||||
|
||||
VMBL_LoadExecutable(&vmblState, program, sizeof(program));
|
||||
VMBL_SaveExecutable("fib.vmbl", program, sizeof(program));
|
||||
VMBL_StartVM(&vmblState);
|
||||
|
||||
return 0;
|
||||
}
|
||||
128
src/sylt/lexer.c
128
src/sylt/lexer.c
@@ -1,7 +1,9 @@
|
||||
#include "lexer.h"
|
||||
#include "exception.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio,h>
|
||||
#include <stdio.h>
|
||||
|
||||
Lexer initLexer(char *source) {
|
||||
Lexer newLexer = {
|
||||
@@ -11,6 +13,7 @@ Lexer initLexer(char *source) {
|
||||
.lineNumber = 1,
|
||||
.currentChar = '\0'
|
||||
};
|
||||
readChar(&newLexer);
|
||||
return newLexer;
|
||||
}
|
||||
|
||||
@@ -25,63 +28,134 @@ void readChar(Lexer *lexer) {
|
||||
}
|
||||
|
||||
void skipWhitespace(Lexer *lexer) {
|
||||
switch (lexer->currentChar)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
if (lexer->currentChar == '\n')
|
||||
lexer->lineNumber++;
|
||||
bool whitespace = true;
|
||||
|
||||
readChar(lexer);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
while (whitespace)
|
||||
{
|
||||
switch (lexer->currentChar)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
if (lexer->currentChar == '\n')
|
||||
lexer->lineNumber++;
|
||||
|
||||
readChar(lexer);
|
||||
break;
|
||||
|
||||
default:
|
||||
whitespace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Token readNumber(Lexer *lexer) {
|
||||
int startPos = lexer->position;
|
||||
int dotCount = 0;
|
||||
int strLength = 0;
|
||||
|
||||
size_t outputCap = 8;
|
||||
char *output = malloc(outputCap);
|
||||
|
||||
if (!output) {
|
||||
exceptionMessage(EXCEPTION_MEMORY_ALLOCATION_FAILURE, "Lexer failed to allocate memory.", lexer->lineNumber, lexer->position);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (isdigit(lexer->currentChar) || lexer->currentChar == '.')
|
||||
{
|
||||
if (lexer->currentChar == '.') {
|
||||
dotCount++;
|
||||
|
||||
if (dotCount > 1) {
|
||||
exceptionMessage(EXCEPTION_MALFORMED_NUMBER, "Too many dots in decimal.", lexer->lineNumber, lexer->position);
|
||||
|
||||
char buffer[strLength+1];
|
||||
strncpy(buffer, lexer->source + startPos, strLength+1);
|
||||
buffer[strLength+1] = 0;
|
||||
|
||||
return NEW_TOKEN(lexer, TOKEN_ILLEGAL, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate more memory if we reach the end of our buffer
|
||||
if (strLength + 1 >= outputCap) {
|
||||
char *temp = realloc(output, outputCap*=2);
|
||||
|
||||
if (!temp) {
|
||||
exceptionMessage(EXCEPTION_MEMORY_ALLOCATION_FAILURE, "Lexer failed to allocate memory.", lexer->lineNumber, lexer->position);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
output = temp;
|
||||
}
|
||||
|
||||
output[strLength] = lexer->source[lexer->position];
|
||||
strLength++;
|
||||
readChar(lexer);
|
||||
|
||||
if (lexer->currentChar == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
output[strLength] = 0;
|
||||
|
||||
if (dotCount == 0)
|
||||
return NEW_TOKEN(lexer, TOKEN_INT, output);
|
||||
else
|
||||
return NEW_TOKEN(lexer, TOKEN_FLOAT, output);
|
||||
}
|
||||
|
||||
Token nextToken(Lexer *lexer) {
|
||||
//Token tok;
|
||||
Token tok;
|
||||
skipWhitespace(lexer);
|
||||
|
||||
switch (lexer->currentChar)
|
||||
{
|
||||
case '+':
|
||||
return NEW_TOKEN(lexer, PLUS, "+");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_PLUS, "+");
|
||||
break;
|
||||
case '-':
|
||||
return NEW_TOKEN(lexer, MINUS, "-");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_MINUS, "-");
|
||||
break;
|
||||
case '*':
|
||||
return NEW_TOKEN(lexer, ASTERISK, "*");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_ASTERISK, "*");
|
||||
break;
|
||||
case '/':
|
||||
return NEW_TOKEN(lexer, SLASH, "/");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_SLASH, "/");
|
||||
break;
|
||||
case '%':
|
||||
return NEW_TOKEN(lexer, MODULUS, "%");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_MODULUS, "%");
|
||||
break;
|
||||
case '^':
|
||||
return NEW_TOKEN(lexer, POW, "^");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_POW, "^");
|
||||
break;
|
||||
case '(':
|
||||
return NEW_TOKEN(lexer, LPAREN, "(");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_LPAREN, "(");
|
||||
break;
|
||||
case ')':
|
||||
return NEW_TOKEN(lexer, RPAREN, ")");
|
||||
tok = NEW_TOKEN(lexer, TOKEN_RPAREN, ")");
|
||||
break;
|
||||
case '\0':
|
||||
return NEW_TOKEN(lexer, EOF, "");
|
||||
|
||||
case '\0': // EOF
|
||||
tok = NEW_TOKEN(lexer, TOKEN_EOF, "EOF");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit())
|
||||
if (isdigit(lexer->currentChar)) {
|
||||
tok = readNumber(lexer);
|
||||
} else {
|
||||
tok = NEW_TOKEN(lexer, TOKEN_ILLEGAL, &lexer->currentChar);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//return tok;
|
||||
readChar(lexer);
|
||||
return tok;
|
||||
}
|
||||
@@ -17,6 +17,6 @@ Lexer initLexer(char *source);
|
||||
void readChar(Lexer *lexer);
|
||||
void skipWhitespace(Lexer *lexer);
|
||||
Token nextToken(Lexer *lexer);
|
||||
char *tokenToCStr(Token token);
|
||||
Token readNumber(Lexer *lexer);
|
||||
|
||||
#endif // !LEXER_H
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include "lexer.h"
|
||||
#include <stdio.h>
|
||||
#include "../file_utils.h"
|
||||
#include "../utils/file_utils.h"
|
||||
#include "../utils/ansii.h"
|
||||
|
||||
int main() {
|
||||
Lexer lexer = initLexer("const x, y = 1, 3\n");
|
||||
printf(nextToken(&lexer).literal);
|
||||
Lexer lexer = initLexer("123 456.789 + - * / % ^ ()");
|
||||
|
||||
while (lexer.currentChar != 0)
|
||||
{
|
||||
Token next = nextToken(&lexer);
|
||||
printf("%s: %s\n", tokenTypeToCString(next.type), next.literal);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,24 +3,24 @@
|
||||
|
||||
typedef enum {
|
||||
// Special Tokens
|
||||
EOF,
|
||||
ILLEGAL,
|
||||
TOKEN_EOF,
|
||||
TOKEN_ILLEGAL,
|
||||
|
||||
// Data Types
|
||||
INT,
|
||||
FLOAT,
|
||||
TOKEN_INT,
|
||||
TOKEN_FLOAT,
|
||||
|
||||
// Arithmetic Symbols
|
||||
PLUS,
|
||||
MINUS,
|
||||
ASTERISK,
|
||||
SLASH,
|
||||
POW,
|
||||
MODULUS,
|
||||
TOKEN_PLUS,
|
||||
TOKEN_MINUS,
|
||||
TOKEN_ASTERISK,
|
||||
TOKEN_SLASH,
|
||||
TOKEN_POW,
|
||||
TOKEN_MODULUS,
|
||||
|
||||
// Symbols
|
||||
LPAREN,
|
||||
RPAREN
|
||||
TOKEN_LPAREN,
|
||||
TOKEN_RPAREN
|
||||
} TokenType;
|
||||
|
||||
typedef struct
|
||||
@@ -33,4 +33,6 @@ typedef struct
|
||||
|
||||
#define NEW_TOKEN(lexer, tokType, tokLiteral) (Token){ .type = (tokType), .literal = (tokLiteral), .lineNumber = (lexer->lineNumber), .position = (lexer->position) }
|
||||
|
||||
char *tokenTypeToCString(TokenType type);
|
||||
|
||||
#endif // !TOKEN_H
|
||||
67
src/utils/ansii.h
Normal file
67
src/utils/ansii.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// ansii.h - made by SpookyDervish
|
||||
// version 1.0.0
|
||||
// do with this whatever you want
|
||||
//
|
||||
// example usage with printf: printf(ESC_BOLD ESC_RED_FG "hi\n");
|
||||
|
||||
#ifndef ANSII_H
|
||||
#define ANSII_H
|
||||
|
||||
#define ESC_RESET "\x1b[0m"
|
||||
#define ESC_BOLD "\x1b[1m"
|
||||
#define ESC_DIM "\x1b[2m"
|
||||
#define ESC_ITALIC "\x1b[3m"
|
||||
#define ESC_UNDERLINE "\x1b[4m"
|
||||
#define ESC_BLINKING "\x1b[5m"
|
||||
#define ESC_REVERSE "\x1b[7m"
|
||||
#define ESC_HIDDEN "\x1b[8m"
|
||||
#define ESC_STRIKETHROUGH "\x1b[8m"
|
||||
|
||||
#define ESC_TERMINAL_BELL "\a"
|
||||
|
||||
#define ESC_BLACK_FG "\x1b[30m"
|
||||
#define ESC_RED_FG "\x1b[31m"
|
||||
#define ESC_GREEN_FG "\x1b[32m"
|
||||
#define ESC_YELLOW_FG "\x1b[33m"
|
||||
#define ESC_BLUE_FG "\x1b[34m"
|
||||
#define ESC_MAGENTA_FG "\x1b[35m"
|
||||
#define ESC_CYAN_FG "\x1b[36m"
|
||||
#define ESC_WHITE_FG "\x1b[37m"
|
||||
|
||||
#define ESC_BLACK_FG "\x1b[30m"
|
||||
#define ESC_RED_FG "\x1b[31m"
|
||||
#define ESC_GREEN_FG "\x1b[32m"
|
||||
#define ESC_YELLOW_FG "\x1b[33m"
|
||||
#define ESC_BLUE_FG "\x1b[34m"
|
||||
#define ESC_MAGENTA_FG "\x1b[35m"
|
||||
#define ESC_CYAN_FG "\x1b[36m"
|
||||
#define ESC_WHITE_FG "\x1b[37m"
|
||||
#define ESC_BRIGHT_BLACK_FG "\x1b[90m"
|
||||
#define ESC_BRIGHT_RED_FG "\x1b[91m"
|
||||
#define ESC_BRIGHT_GREEN_FG "\x1b[92m"
|
||||
#define ESC_BRIGHT_YELLOW_FG "\x1b[93m"
|
||||
#define ESC_BRIGHT_BLUE_FG "\x1b[94m"
|
||||
#define ESC_BRIGHT_MAGENTA_FG "\x1b[95m"
|
||||
#define ESC_BRIGHT_CYAN_FG "\x1b[96m"
|
||||
#define ESC_BRIGHT_WHITE_FG "\x1b[97m"
|
||||
|
||||
#define ESC_BLACK_BG "\x1b[40m"
|
||||
#define ESC_RED_BG "\x1b[41m"
|
||||
#define ESC_GREEN_BG "\x1b[42m"
|
||||
#define ESC_YELLOW_BG "\x1b[43m"
|
||||
#define ESC_BLUE_BG "\x1b[44m"
|
||||
#define ESC_MAGENTA_BG "\x1b[45m"
|
||||
#define ESC_CYAN_BG "\x1b[46m"
|
||||
#define ESC_WHITE_BG "\x1b[47m"
|
||||
#define ESC_BRIGHT_BLACK_BG "\x1b[100m"
|
||||
#define ESC_BRIGHT_RED_BG "\x1b[101m"
|
||||
#define ESC_BRIGHT_GREEN_BG "\x1b[102m"
|
||||
#define ESC_BRIGHT_YELLOW_BG "\x1b[103m"
|
||||
#define ESC_BRIGHT_BLUE_BG "\x1b[104m"
|
||||
#define ESC_BRIGHT_MAGENTA_BG "\x1b[105m"
|
||||
#define ESC_BRIGHT_CYAN_BG "\x1b[106m"
|
||||
#define ESC_BRIGHT_WHITE_BG "\x1b[107m"
|
||||
|
||||
#define ESC_DEFAULT_FG "\x1b[39m"
|
||||
|
||||
#endif // !ANSII_H
|
||||
260
src/vmbl.c
260
src/vmbl.c
@@ -1,260 +0,0 @@
|
||||
#include "vmbl.h"
|
||||
#include "file_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define MATH_OP(vmblState, operation) \
|
||||
do { \
|
||||
if ((vmblState)->stackSize < 2) { \
|
||||
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW }; \
|
||||
} \
|
||||
(vmblState)->stack[(vmblState)->stackSize - 2] = (vmblState)->stack[(vmblState)->stackSize - 2] operation (vmblState)->stack[(vmblState)->stackSize - 1]; \
|
||||
(vmblState)->stackSize--; \
|
||||
} while (0);
|
||||
|
||||
|
||||
|
||||
VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction instruction) {
|
||||
switch (instruction.type)
|
||||
{
|
||||
case INSTRUCTION_PUSH:
|
||||
if (vmblState->stackSize >= VMBL_STACK_SIZE) {
|
||||
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
|
||||
}
|
||||
|
||||
vmblState->stack[vmblState->stackSize++] = instruction.opperands[0];
|
||||
break;
|
||||
|
||||
case INSTRUCTION_ADD:
|
||||
MATH_OP(vmblState, +);
|
||||
break;
|
||||
case INSTRUCTION_SUB:
|
||||
MATH_OP(vmblState, -);
|
||||
break;
|
||||
case INSTRUCTION_MUL:
|
||||
MATH_OP(vmblState, *);
|
||||
break;
|
||||
case INSTRUCTION_DIV:
|
||||
if (vmblState->stack[vmblState->stackSize-1] == 0) {
|
||||
return (VMBL_Exception){ EXCEPTION_DIVIDE_BY_ZERO };
|
||||
}
|
||||
|
||||
MATH_OP(vmblState, /);
|
||||
break;
|
||||
|
||||
case INSTRUCTION_DUPLICATE:
|
||||
if (vmblState->stackSize - instruction.opperands[0] <= 0) {
|
||||
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
|
||||
}
|
||||
|
||||
if (vmblState->stackSize >= VMBL_STACK_SIZE) {
|
||||
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
|
||||
}
|
||||
|
||||
if (instruction.opperands[0] < 0) {
|
||||
return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND };
|
||||
}
|
||||
|
||||
vmblState->stack[vmblState->stackSize++] = vmblState->stack[vmblState->stackSize - 1 - instruction.opperands[0]];
|
||||
|
||||
break;
|
||||
|
||||
case INSTRUCTION_JUMP:
|
||||
|
||||
vmblState->ip = instruction.opperands[0];
|
||||
|
||||
break;
|
||||
|
||||
case INSTRUCTION_HALT:
|
||||
vmblState->halted = true;
|
||||
break;
|
||||
|
||||
case INSTRUCTION_EQUAL:
|
||||
MATH_OP(vmblState, ==);
|
||||
break;
|
||||
|
||||
case INSTRUCTION_JUMP_CONDITIONAL:
|
||||
if (instruction.opperands[0] < 0) {
|
||||
return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND };
|
||||
}
|
||||
|
||||
if (vmblState->stack[vmblState->stackSize--]) {
|
||||
vmblState->ip = instruction.opperands[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case INSTRUCTION_DROP:
|
||||
if (vmblState->stackSize <= 0) {
|
||||
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
|
||||
}
|
||||
|
||||
vmblState->stackSize--;
|
||||
|
||||
break;
|
||||
|
||||
case INSTRUCTION_NOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE };
|
||||
break;
|
||||
}
|
||||
|
||||
return (VMBL_Exception) { EXCEPTION_NONE };
|
||||
}
|
||||
|
||||
void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception) {
|
||||
fprintf(stderr, "EXCEPTION: %s\n\n", exceptionAsCString(exception));
|
||||
fprintf(stderr, "Stack:\n");
|
||||
|
||||
if (vmblState.stackSize > 0) {
|
||||
for (size_t i = 0; i < vmblState.stackSize; i++) {
|
||||
fprintf(stderr, " 0x%lX: %ld\n", i, vmblState.stack[i]);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, " [empty]\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void VMBL_StartVM(VMBL_State *vmblState) {
|
||||
for (;;)
|
||||
{
|
||||
// fetch next instruction
|
||||
if (vmblState->ip >= VMBL_PROGRAM_SIZE) {
|
||||
VMBL_Dump(*vmblState, (VMBL_Exception){ EXCEPTION_INVALID_INSTRUCTION_ACCESS});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
|
||||
VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction);
|
||||
|
||||
if (exception.type != EXCEPTION_NONE) {
|
||||
VMBL_Dump(*vmblState, exception);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vmblState->halted) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// executable operations
|
||||
void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize) {
|
||||
if (programSize > VMBL_PROGRAM_SIZE) {
|
||||
fprintf(stderr, "VMBL: failed to load program from memory because it is %ld words in size, while the max size is %d.", programSize, VMBL_PROGRAM_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(&vmblState->program, program, programSize);
|
||||
|
||||
vmblState->programSize = programSize;
|
||||
}
|
||||
|
||||
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath) {
|
||||
/*FILE *file = fopen(filePath, "rb");
|
||||
|
||||
if (file == NULL) {
|
||||
perror("VMBL: Failed to open file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
size_t programSize = size / sizeof(vmblState->program[0]);
|
||||
VMBL_Instruction program[programSize];
|
||||
fread(program, sizeof(program[0]), programSize, file);*/
|
||||
|
||||
VMBL_Instruction *program = (VMBL_Instruction*)readStringFromFile(filePath);
|
||||
|
||||
VMBL_LoadExecutable(vmblState, program, sizeof(program));
|
||||
|
||||
//fclose(file);
|
||||
|
||||
}
|
||||
|
||||
void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize) {
|
||||
FILE *file = fopen(filePath, "wb");
|
||||
|
||||
if (file == NULL) {
|
||||
perror("VMBL: Failed to open file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fwrite(program, sizeof(program), programSize, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
char *instructionTypeToCStr(InstructionType type) {
|
||||
printf("%x\n", type);
|
||||
switch (type)
|
||||
{
|
||||
|
||||
case INSTRUCTION_PUSH:
|
||||
return "PUSH";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_ADD:
|
||||
return "ADD ";
|
||||
break;
|
||||
case INSTRUCTION_SUB:
|
||||
return "SUB ";
|
||||
break;
|
||||
case INSTRUCTION_MUL:
|
||||
return "MUL ";
|
||||
break;
|
||||
case INSTRUCTION_DIV:
|
||||
return "DIV ";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_DUPLICATE:
|
||||
return "DUP ";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_JUMP:
|
||||
return "JMP ";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_HALT:
|
||||
return "HALT";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_EQUAL:
|
||||
return "EQ ";
|
||||
break;
|
||||
case INSTRUCTION_NOT_EQUAL:
|
||||
return "NEQ ";
|
||||
break;
|
||||
case INSTRUCTION_GREATER_THAN:
|
||||
return "GT ";
|
||||
break;
|
||||
case INSTRUCTION_GREATER_THAN_EQUAL:
|
||||
return "GTE ";
|
||||
break;
|
||||
case INSTRUCTION_LESS_THAN:
|
||||
return "LT ";
|
||||
break;
|
||||
case INSTRUCTION_LESS_THAN_EQUAL:
|
||||
return "LTE ";
|
||||
break;
|
||||
|
||||
case INSTRUCTION_JUMP_CONDITIONAL:
|
||||
return "JC ";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "??? ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
87
src/vmbl.h
87
src/vmbl.h
@@ -1,87 +0,0 @@
|
||||
#ifndef VMBL_H
|
||||
#define VMBL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "exception.h"
|
||||
|
||||
#define VMBL_STACK_SIZE 1024
|
||||
#define VMBL_PROGRAM_SIZE 1024
|
||||
|
||||
typedef int64_t Word;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INSTRUCTION_NOP,
|
||||
|
||||
// stack operations
|
||||
INSTRUCTION_PUSH,
|
||||
INSTRUCTION_ADD,
|
||||
INSTRUCTION_SUB,
|
||||
INSTRUCTION_MUL,
|
||||
INSTRUCTION_DIV,
|
||||
INSTRUCTION_DUPLICATE,
|
||||
INSTRUCTION_DROP,
|
||||
|
||||
// instruction pointer operations
|
||||
INSTRUCTION_HALT,
|
||||
INSTRUCTION_JUMP,
|
||||
INSTRUCTION_JUMP_CONDITIONAL,
|
||||
|
||||
// conditional operations
|
||||
INSTRUCTION_NOT_EQUAL,
|
||||
INSTRUCTION_EQUAL,
|
||||
INSTRUCTION_LESS_THAN,
|
||||
INSTRUCTION_LESS_THAN_EQUAL,
|
||||
INSTRUCTION_GREATER_THAN,
|
||||
INSTRUCTION_GREATER_THAN_EQUAL
|
||||
} InstructionType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
InstructionType type;
|
||||
Word opperands[3];
|
||||
} VMBL_Instruction;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Word stack[VMBL_STACK_SIZE];
|
||||
size_t stackSize;
|
||||
|
||||
VMBL_Instruction program[VMBL_PROGRAM_SIZE];
|
||||
size_t programSize;
|
||||
|
||||
long ip;
|
||||
bool halted;
|
||||
} VMBL_State;
|
||||
|
||||
#define MAKE_INST_PUSH(value) (VMBL_Instruction) { .type = INSTRUCTION_PUSH, .opperands[0] = (value) }
|
||||
#define MAKE_INST_DROP (VMBL_Instruction) { .type = INSTRUCTION_POP }
|
||||
#define MAKE_INST_ADD (VMBL_Instruction) { .type = INSTRUCTION_ADD }
|
||||
#define MAKE_INST_SUB (VMBL_Instruction) { .type = INSTRUCTION_SUB }
|
||||
#define MAKE_INST_MUL (VMBL_Instruction) { .type = INSTRUCTION_MUL }
|
||||
#define MAKE_INST_DIV (VMBL_Instruction) { .type = INSTRUCTION_DIV }
|
||||
#define MAKE_INST_DUP(value) (VMBL_Instruction) { .type = INSTRUCTION_DUPLICATE, .opperands[0] = (value) }
|
||||
#define MAKE_INST_JMP(value) (VMBL_Instruction) { .type = INSTRUCTION_JUMP, .opperands[0] = (value) }
|
||||
#define MAKE_INST_HALT (VMBL_Instruction) { .type = INSTRUCTION_HALT }
|
||||
#define MAKE_INST_EQUAL (VMBL_Instruction) { .type = INSTRUCTION_EQUAL }
|
||||
#define MAKE_INST_NOT_EQUAL (VMBL_Instruction) { .type = INSTRUCTION_NOT_EQUAL }
|
||||
#define MAKE_INST_LESS (VMBL_Instruction) { .type = INSTRUCTION_LESS_THAN }
|
||||
#define MAKE_INST_LESS_EQUAL (VMBL_Instruction) { .type = INSTRUCTION_LESS_THAN_EQUAL }
|
||||
#define MAKE_INST_GREATER (VMBL_Instruction) { .type = INSTRUCTION_GREATER_THAN }
|
||||
#define MAKE_INST_GREATER_EQUAL (VMBL_Instruction) { .type = INSTRUCTION_GREATER_THAN_EQUAL }
|
||||
#define MAKE_INST_JUMP_CONDITIONAL(value) (VMBL_Instruction) { .type = INSTRUCTION_JUMP_CONDITIONAL, .opperands[0] = (value) }
|
||||
|
||||
VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction instruction);
|
||||
void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception);
|
||||
void VMBL_StartVM(VMBL_State *vmblState);
|
||||
|
||||
void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize);
|
||||
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath);
|
||||
void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize);
|
||||
|
||||
char *instructionTypeToCStr(InstructionType type);
|
||||
|
||||
#endif // !VMBL_H
|
||||
Reference in New Issue
Block a user