Compare commits
2 Commits
d4ac0be316
...
bd07952569
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd07952569 | ||
|
|
b69a6c6eec |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -52,3 +52,6 @@ Module.symvers
|
|||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
|
sasm
|
||||||
|
sylt
|
||||||
|
vmbl
|
||||||
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.
|
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 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.
|
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;
|
|
||||||
}
|
|
||||||
102
src/sylt/lexer.c
102
src/sylt/lexer.c
@@ -1,7 +1,9 @@
|
|||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
#include "exception.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio,h>
|
#include <stdio.h>
|
||||||
|
|
||||||
Lexer initLexer(char *source) {
|
Lexer initLexer(char *source) {
|
||||||
Lexer newLexer = {
|
Lexer newLexer = {
|
||||||
@@ -11,6 +13,7 @@ Lexer initLexer(char *source) {
|
|||||||
.lineNumber = 1,
|
.lineNumber = 1,
|
||||||
.currentChar = '\0'
|
.currentChar = '\0'
|
||||||
};
|
};
|
||||||
|
readChar(&newLexer);
|
||||||
return newLexer;
|
return newLexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +28,10 @@ void readChar(Lexer *lexer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void skipWhitespace(Lexer *lexer) {
|
void skipWhitespace(Lexer *lexer) {
|
||||||
|
bool whitespace = true;
|
||||||
|
|
||||||
|
while (whitespace)
|
||||||
|
{
|
||||||
switch (lexer->currentChar)
|
switch (lexer->currentChar)
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@@ -38,50 +45,117 @@ void skipWhitespace(Lexer *lexer) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
whitespace = false;
|
||||||
break;
|
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 nextToken(Lexer *lexer) {
|
||||||
//Token tok;
|
Token tok;
|
||||||
skipWhitespace(lexer);
|
skipWhitespace(lexer);
|
||||||
|
|
||||||
switch (lexer->currentChar)
|
switch (lexer->currentChar)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
return NEW_TOKEN(lexer, PLUS, "+");
|
tok = NEW_TOKEN(lexer, TOKEN_PLUS, "+");
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
return NEW_TOKEN(lexer, MINUS, "-");
|
tok = NEW_TOKEN(lexer, TOKEN_MINUS, "-");
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
return NEW_TOKEN(lexer, ASTERISK, "*");
|
tok = NEW_TOKEN(lexer, TOKEN_ASTERISK, "*");
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
return NEW_TOKEN(lexer, SLASH, "/");
|
tok = NEW_TOKEN(lexer, TOKEN_SLASH, "/");
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
return NEW_TOKEN(lexer, MODULUS, "%");
|
tok = NEW_TOKEN(lexer, TOKEN_MODULUS, "%");
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
return NEW_TOKEN(lexer, POW, "^");
|
tok = NEW_TOKEN(lexer, TOKEN_POW, "^");
|
||||||
break;
|
break;
|
||||||
case '(':
|
case '(':
|
||||||
return NEW_TOKEN(lexer, LPAREN, "(");
|
tok = NEW_TOKEN(lexer, TOKEN_LPAREN, "(");
|
||||||
break;
|
break;
|
||||||
case ')':
|
case ')':
|
||||||
return NEW_TOKEN(lexer, RPAREN, ")");
|
tok = NEW_TOKEN(lexer, TOKEN_RPAREN, ")");
|
||||||
break;
|
break;
|
||||||
case '\0':
|
|
||||||
return NEW_TOKEN(lexer, EOF, "");
|
case '\0': // EOF
|
||||||
|
tok = NEW_TOKEN(lexer, TOKEN_EOF, "EOF");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (isdigit())
|
if (isdigit(lexer->currentChar)) {
|
||||||
|
tok = readNumber(lexer);
|
||||||
|
} else {
|
||||||
|
tok = NEW_TOKEN(lexer, TOKEN_ILLEGAL, &lexer->currentChar);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return tok;
|
readChar(lexer);
|
||||||
|
return tok;
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,6 @@ Lexer initLexer(char *source);
|
|||||||
void readChar(Lexer *lexer);
|
void readChar(Lexer *lexer);
|
||||||
void skipWhitespace(Lexer *lexer);
|
void skipWhitespace(Lexer *lexer);
|
||||||
Token nextToken(Lexer *lexer);
|
Token nextToken(Lexer *lexer);
|
||||||
char *tokenToCStr(Token token);
|
Token readNumber(Lexer *lexer);
|
||||||
|
|
||||||
#endif // !LEXER_H
|
#endif // !LEXER_H
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../file_utils.h"
|
#include "../utils/file_utils.h"
|
||||||
|
#include "../utils/ansii.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Lexer lexer = initLexer("const x, y = 1, 3\n");
|
Lexer lexer = initLexer("123 456.789 + - * / % ^ ()");
|
||||||
printf(nextToken(&lexer).literal);
|
|
||||||
|
while (lexer.currentChar != 0)
|
||||||
|
{
|
||||||
|
Token next = nextToken(&lexer);
|
||||||
|
printf("%s: %s\n", tokenTypeToCString(next.type), next.literal);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3,24 +3,24 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// Special Tokens
|
// Special Tokens
|
||||||
EOF,
|
TOKEN_EOF,
|
||||||
ILLEGAL,
|
TOKEN_ILLEGAL,
|
||||||
|
|
||||||
// Data Types
|
// Data Types
|
||||||
INT,
|
TOKEN_INT,
|
||||||
FLOAT,
|
TOKEN_FLOAT,
|
||||||
|
|
||||||
// Arithmetic Symbols
|
// Arithmetic Symbols
|
||||||
PLUS,
|
TOKEN_PLUS,
|
||||||
MINUS,
|
TOKEN_MINUS,
|
||||||
ASTERISK,
|
TOKEN_ASTERISK,
|
||||||
SLASH,
|
TOKEN_SLASH,
|
||||||
POW,
|
TOKEN_POW,
|
||||||
MODULUS,
|
TOKEN_MODULUS,
|
||||||
|
|
||||||
// Symbols
|
// Symbols
|
||||||
LPAREN,
|
TOKEN_LPAREN,
|
||||||
RPAREN
|
TOKEN_RPAREN
|
||||||
} TokenType;
|
} TokenType;
|
||||||
|
|
||||||
typedef struct
|
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) }
|
#define NEW_TOKEN(lexer, tokType, tokLiteral) (Token){ .type = (tokType), .literal = (tokLiteral), .lineNumber = (lexer->lineNumber), .position = (lexer->position) }
|
||||||
|
|
||||||
|
char *tokenTypeToCString(TokenType type);
|
||||||
|
|
||||||
#endif // !TOKEN_H
|
#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