This commit is contained in:
SpookyDervish
2025-12-27 10:17:56 +11:00
parent bd07952569
commit 9da2bb5404
13 changed files with 598 additions and 57 deletions

57
.gitignore vendored
View File

@@ -1,57 +0,0 @@
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
sasm
sylt
vmbl

1
src/sylt/ast.c Normal file
View File

@@ -0,0 +1 @@
#include "ast.h"

65
src/sylt/ast.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef AST_H
#define AST_H
#include <stdlib.h>
typedef enum {
NODE_PROGRAM,
// Statements
NODE_EXPRESSION_STATEMENT,
// Expressions
NODE_INFIX_EXPRESSION,
// Literals
NODE_INT_LITERAL,
NODE_FLOAT_LITERAL
} AST_Type;
typedef struct AST AST;
struct AST
{
AST_Type type;
char *(*to_json)(AST *node);
};
typedef struct
{
AST base;
AST **statements;
size_t statementCount;
} Program;
char *programToJSON(AST *node);
// statements
typedef struct
{
AST base;
AST *expr;
} ExpressionStatement;
char *expressionStatementToJSON(AST *node);
// expressions
typedef struct {
AST base;
AST *left;
char *operator;
AST *right;
} InfixExpression;
char *infixExpressionToJSON(AST *node);
// literals
typedef struct {
AST base;
int value;
} IntegerLiteral;
char *integerLiteralToJSON(AST *node);
typedef struct {
AST base;
double value;
} FloatLiteral;
char *floatLiteralToJSON(AST *node);
#endif // !AST_H

21
src/sylt/exception.c Normal file
View File

@@ -0,0 +1,21 @@
#include "exception.h"
#include <stdio.h>
#include "../utils/ansii.h"
char *exceptionTypeToCString(ExceptionType type) {
switch (type)
{
case EXCEPTION_MALFORMED_NUMBER:
return "MalformedNumberException";
case EXCEPTION_MEMORY_ALLOCATION_FAILURE:
return "MemoryAllocationFailException";
default:
return "UnkownException (fix me please)";
}
}
void exceptionMessage(ExceptionType type, char *message, int lineNumber, int position) {
printf(ESC_RED_FG ESC_BOLD "%s: %s" ESC_RESET "\n", exceptionTypeToCString(type), message);
}

12
src/sylt/exception.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef EXCEPTION_H
#define EXCEPTION_H
typedef enum {
EXCEPTION_MALFORMED_NUMBER,
EXCEPTION_MEMORY_ALLOCATION_FAILURE
} ExceptionType;
char *exceptionTypeToCString(ExceptionType type);
void exceptionMessage(ExceptionType type, char *message, int lineNumber, int position);
#endif // !EXCEPTION_H

1
src/sylt/parser.c Normal file
View File

@@ -0,0 +1 @@
#include "parser.h"

28
src/sylt/parser.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef PARSER_H
#define PARSER_H
#include "lexer.h"
#include "ast.h"
typedef enum {
PRECEDENCE_LOWEST = 0,
PRECEDENCE_EQUALS,
PRECEDENCE_LESSGREATER,
PRECEDENCE_SUM,
PRECEDENCE_PRODUCT,
PRECEDENCE_EXPONENT,
PRECEDENCE_PREFIX,
PRECEDENCE_CALL,
PRECEDENCE_INDEX,
} PrecedenceType;
PrecedenceType PRECEDENCES[] = {
[TOKEN_PLUS] = PRECEDENCE_SUM,
[TOKEN_MINUS] = PRECEDENCE_SUM,
[TOKEN_SLASH] = PRECEDENCE_PRODUCT,
[TOKEN_ASTERISK] = PRECEDENCE_PRODUCT,
[TOKEN_MODULUS] = PRECEDENCE_PRODUCT,
[TOKEN_POW] = PRECEDENCE_EXPONENT,
};
#endif // !PARSER_H

45
src/sylt/token.c Normal file
View File

@@ -0,0 +1,45 @@
#include "token.h"
char *tokenTypeToCString(TokenType type) {
switch (type)
{
case TOKEN_EOF:
return "TOKEN_EOF";
case TOKEN_ILLEGAL:
return "TOKEN_ILLEGAL";
case TOKEN_INT:
return "TOKEN_INT";
case TOKEN_FLOAT:
return "TOKEN_FLOAT";
case TOKEN_PLUS:
return "TOKEN_EOF";
case TOKEN_MINUS:
return "TOKEN_MINUS";
case TOKEN_ASTERISK:
return "TOKEN_ASTERISK";
case TOKEN_SLASH:
return "TOKEN_SLASH";
case TOKEN_POW:
return "TOKEN_POW";
case TOKEN_MODULUS:
return "TOKEN_MODULUS";
case TOKEN_LPAREN:
return "TOKEN_LPAREN";
case TOKEN_RPAREN:
return "TOKEN_RPAREN";
default:
return "UNKOWN (fix me please)";
}
}

39
src/vmbl/exception.c Normal file
View File

@@ -0,0 +1,39 @@
#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;
}
}

21
src/vmbl/exception.h Normal file
View File

@@ -0,0 +1,21 @@
#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

18
src/vmbl/main.c Normal file
View File

@@ -0,0 +1,18 @@
#include "vmbl.h"
#include <stdio.h>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]));
VMBL_Instruction program[] = {
MAKE_INST_JMP(0)
};
int main() {
VMBL_State vmblState = {};
VMBL_LoadExecutable(&vmblState, program, sizeof(program));
VMBL_SaveExecutable("fib.vmbl", program, sizeof(program));
VMBL_StartVM(&vmblState);
return 0;
}

260
src/vmbl/vmbl.c Normal file
View File

@@ -0,0 +1,260 @@
#include "vmbl.h"
#include "../utils/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/vmbl.h Normal file
View File

@@ -0,0 +1,87 @@
#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