diff --git a/.gitignore b/.gitignore index 590bdf9..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/src/sylt/ast.c b/src/sylt/ast.c new file mode 100644 index 0000000..0fbc3e4 --- /dev/null +++ b/src/sylt/ast.c @@ -0,0 +1 @@ +#include "ast.h" \ No newline at end of file diff --git a/src/sylt/ast.h b/src/sylt/ast.h new file mode 100644 index 0000000..03f88fd --- /dev/null +++ b/src/sylt/ast.h @@ -0,0 +1,65 @@ +#ifndef AST_H +#define AST_H + +#include + +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 \ No newline at end of file diff --git a/src/sylt/exception.c b/src/sylt/exception.c new file mode 100644 index 0000000..62bbbf1 --- /dev/null +++ b/src/sylt/exception.c @@ -0,0 +1,21 @@ +#include "exception.h" +#include +#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); +} \ No newline at end of file diff --git a/src/sylt/exception.h b/src/sylt/exception.h new file mode 100644 index 0000000..5ca9c7d --- /dev/null +++ b/src/sylt/exception.h @@ -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 \ No newline at end of file diff --git a/src/sylt/parser.c b/src/sylt/parser.c new file mode 100644 index 0000000..c5f8fc0 --- /dev/null +++ b/src/sylt/parser.c @@ -0,0 +1 @@ +#include "parser.h" \ No newline at end of file diff --git a/src/sylt/parser.h b/src/sylt/parser.h new file mode 100644 index 0000000..9373363 --- /dev/null +++ b/src/sylt/parser.h @@ -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 \ No newline at end of file diff --git a/src/sylt/token.c b/src/sylt/token.c new file mode 100644 index 0000000..724a30f --- /dev/null +++ b/src/sylt/token.c @@ -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)"; + } +} \ No newline at end of file diff --git a/src/vmbl/exception.c b/src/vmbl/exception.c new file mode 100644 index 0000000..a30d0f5 --- /dev/null +++ b/src/vmbl/exception.c @@ -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; + } +} \ No newline at end of file diff --git a/src/vmbl/exception.h b/src/vmbl/exception.h new file mode 100644 index 0000000..3d979ec --- /dev/null +++ b/src/vmbl/exception.h @@ -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 \ No newline at end of file diff --git a/src/vmbl/main.c b/src/vmbl/main.c new file mode 100644 index 0000000..2e67146 --- /dev/null +++ b/src/vmbl/main.c @@ -0,0 +1,18 @@ +#include "vmbl.h" +#include + +#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; +} \ No newline at end of file diff --git a/src/vmbl/vmbl.c b/src/vmbl/vmbl.c new file mode 100644 index 0000000..a1b1ad8 --- /dev/null +++ b/src/vmbl/vmbl.c @@ -0,0 +1,260 @@ +#include "vmbl.h" +#include "../utils/file_utils.h" +#include +#include +#include + + +#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; + } +} \ No newline at end of file diff --git a/src/vmbl/vmbl.h b/src/vmbl/vmbl.h new file mode 100644 index 0000000..445b2a2 --- /dev/null +++ b/src/vmbl/vmbl.h @@ -0,0 +1,87 @@ +#ifndef VMBL_H +#define VMBL_H + +#include +#include +#include +#include +#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