From 015ec69720769e0fb2b80dbe79bf0afb9bb77893 Mon Sep 17 00:00:00 2001 From: Aer Iz Date: Fri, 9 Feb 2024 07:08:45 +0200 Subject: [PATCH] Initial commit :3 --- .clang-format | 192 +++++++++++++++ .gitignore | 9 + LICENSE | 11 + Makefile | 7 + README.md | 1 + src/config.h | 9 + src/execute.c | 572 ++++++++++++++++++++++++++++++++++++++++++++ src/execute.h | 3 + src/main.c | 34 +++ src/stack.c | 100 ++++++++ src/stack.h | 35 +++ tests/calc.lb | 25 ++ tests/helloworld.lb | 16 ++ 13 files changed, 1014 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 src/config.h create mode 100644 src/execute.c create mode 100644 src/execute.h create mode 100644 src/main.c create mode 100644 src/stack.c create mode 100644 src/stack.h create mode 100644 tests/calc.lb create mode 100644 tests/helloworld.lb diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..d23cc24 --- /dev/null +++ b/.clang-format @@ -0,0 +1,192 @@ +--- +Language: Cpp +# BasedOnStyle: Microsoft +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: false + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f52d1c --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.trash/ +.dev/ + +spec.md +default.nix + +lbr + +std/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a3094a --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1de7fbc --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +CC=clang + +all: + $(CC) -o lbr -O2 -Wall -Wextra -Wpedantic src/*.c + +test: + ./lbr tests/test.lb \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..29da32d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Learning c and having fun diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..e5277c1 --- /dev/null +++ b/src/config.h @@ -0,0 +1,9 @@ +#pragma once + +#define STACK_SIZE 65535 +#define PROGRAM_MAXSIZE 65535 +#define MAX_LABELS 256 +#define MAX_MODULES 256 +#define MAX_BF_LOOPS 256 + +#define DEBUG_MODE 0 diff --git a/src/execute.c b/src/execute.c new file mode 100644 index 0000000..e01786c --- /dev/null +++ b/src/execute.c @@ -0,0 +1,572 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "execute.h" +#include "stack.h" + +#define NAME stack->program[stack->program_counter].name +#define DATA stack->program[stack->program_counter].data +#define ARG stack->program[stack->program_counter].arg + +typedef enum +{ + MPUSH = '>', + MDROP = '$', + MDUP = ':', + MSWAP = '\\', + MINC = '+', + MDEC = '-', + + PPIPE = '|', + PREFLECT = '^' +} OP; + +static void prefix_operator(Stack *stack, char op) +{ + if (NAME[0] != '@' && (NAME[1] == '\0' || NAME[1] == '\n')) + { + printf("%c\n", op); + kms(stack, "Invalid usage of prefix operators"); + } + + switch (op) + { + case PPIPE: + NAME++; + + DATA = stack_pop(stack); + + break; + + case PREFLECT: + NAME++; + + if (NAME[0] != '#' && NAME[0] != '$') + printf("%s %i", NAME, DATA); + + else if (!strcmp(ARG, "\n")) + printf("%s", NAME); + + else + printf("%s %s", NAME, ARG); + + break; + } +} + +static void expression(Stack *stack, char *code) +{ + uint16_t ax, ax2; + + for (uint16_t i = 0; code[i] != '\0'; i++) + { + switch (code[i]) + { + case MPUSH: + stack_push(stack, 0); + break; + + case MDROP: + stack_pop(stack); + break; + + case MDUP: + stack_push(stack, stack_peek(stack)); + break; + + case MSWAP: + ax = stack_pop(stack); + ax2 = stack_pop(stack); + stack_push(stack, ax); + stack_push(stack, ax2); + break; + + case MINC: + ax = stack_pop(stack); + stack_push(stack, ax + 1); + break; + + case MDEC: + ax = stack_pop(stack); + stack_push(stack, ax - 1); + break; + + default: + printf("INVALID EXPRESSION: UNKNOWN OPERATOR '%c'\n", code[i]); + kms(stack, "INVALID EXPRESSION"); + break; + } + } +} + +static void find_labels(Stack *stack) +{ + for (; stack->program_counter < stack->program_size; stack->program_counter++) + { + if (NAME[0] == '@') + { + if (DATA > MAX_LABELS) + { + printf("INVALID LABEL: %i\n", DATA); + kms(stack, "INVALID LABEL"); + } + + if (stack->labels[DATA] != -1) + { + printf("LABEL ALREADY DEFINED: %i\n", DATA); + kms(stack, "LABEL ALREADY DEFINED"); + } + + if (DATA == 0) + { + stack->labels[0] = stack->program_counter; + continue; + } + + stack->labels[DATA] = stack->program_counter; + } + } + if (stack->labels[0] != -1) + stack->program_counter = stack->labels[0]; + else + stack->program_counter = 0; +} + +void execute(Stack *stack, Stack *originstack, char *modname) +{ + find_labels(stack); + + for (; stack->program_counter < stack->program_size; stack->program_counter++) + { + prefix_operator(stack, NAME[0]); + + if (NAME[0] == '@') + continue; + + // Stack operations + + if (!strcmp(NAME, "push")) // arg + { + stack_push(stack, DATA); + continue; + } + + if (!strcmp(NAME, "pop")) + { + stack_pop(stack); + continue; + } + + if (!strcmp(NAME, "dup")) + { + stack_push(stack, stack_peek(stack)); + continue; + } + + if (!strcmp(NAME, "swap")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a); + stack_push(stack, b); + continue; + } + + if (!strcmp(NAME, "pick")) + { + uint16_t arg = stack_pop(stack); + + if (arg >= stack->pointer) + kms(stack, "ATTEMPTED TO PICK BELOW STACK"); + + stack_push(stack, stack->memory[stack->pointer - arg - 1]); + continue; + } + + // Math + + if (!strcmp(NAME, "add")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, b + a); + continue; + } + + if (!strcmp(NAME, "sub")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, b - a); + continue; + } + + if (!strcmp(NAME, "mul")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, b * a); + continue; + } + + if (!strcmp(NAME, "div")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, b / a); + continue; + } + + if (!strcmp(NAME, "mod")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, b % a); + continue; + } + + // Logic + + if (!strcmp(NAME, "and")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a && b); + continue; + } + + if (!strcmp(NAME, "or")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a || b); + continue; + } + + if (!strcmp(NAME, "xor")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, !a != !b); + continue; + } + + if (!strcmp(NAME, "nand")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, !(a && b)); + continue; + } + + if (!strcmp(NAME, "not")) + { + stack_push(stack, !stack_pop(stack)); + continue; + } + + // Bitwise + + if (!strcmp(NAME, "band")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a & b); + continue; + } + + if (!strcmp(NAME, "bor")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a | b); + continue; + } + + if (!strcmp(NAME, "bxor")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, a ^ b); + continue; + } + + if (!strcmp(NAME, "bnand")) + { + uint16_t a = stack_pop(stack); + uint16_t b = stack_pop(stack); + stack_push(stack, ~(a & b)); + continue; + } + + if (!strcmp(NAME, "bnot")) + { + stack_push(stack, ~stack_pop(stack)); + continue; + } + + // Flow control + + if (!strcmp(NAME, "jmp")) // arg + { + if (stack->labels[DATA] == -1) + { + printf("UNKNOWN LABEL: %i\n", DATA); + kms(stack, "UNKNOWN LABEL"); + } + + stack->program_counter = stack->labels[DATA]; + continue; + } + + if (!strcmp(NAME, "jnz")) // arg + { + if (stack->labels[DATA] == -1) + { + printf("UNKNOWN LABEL: %i\n", DATA); + kms(stack, "UNKNOWN LABEL"); + } + + if (stack_pop(stack) != 0) + stack->program_counter = stack->labels[DATA]; + continue; + } + + if (!strcmp(NAME, "jz")) // arg + { + if (stack->labels[DATA] == -1) + { + printf("UNKNOWN LABEL: %i\n", DATA); + kms(stack, "UNKNOWN LABEL"); + } + + if (stack_pop(stack) == 0) + stack->program_counter = stack->labels[DATA]; + continue; + } + + if (!strcmp(NAME, "kjnz")) // arg + { + if (stack->labels[DATA] == -1) + { + printf("UNKNOWN LABEL: %i\n", DATA); + kms(stack, "UNKNOWN LABEL"); + } + + if (stack_peek(stack) != 0) + stack->program_counter = stack->labels[DATA]; + continue; + } + + if (!strcmp(NAME, "kjz")) // arg + { + if (stack->labels[DATA] == -1) + { + printf("UNKNOWN LABEL: %i\n", DATA); + kms(stack, "UNKNOWN LABEL"); + } + + if (stack_peek(stack) == 0) + stack->program_counter = stack->labels[DATA]; + continue; + } + + // I/O + + if (!strcmp(NAME, "putc")) + { + putchar(stack_pop(stack)); + continue; + } + + if (!strcmp(NAME, "getc")) + { + stack_push(stack, getchar()); + continue; + } + + if (!strcmp(NAME, "scan")) + { + uint16_t num; + scanf("%hu", &num); + stack_push(stack, num); + continue; + } + + if (!strcmp(NAME, "meow")) + { + printf("%i\n", stack_pop(stack)); + continue; + } + + if (!strcmp(NAME, "$println")) // arg + { + printf("%s\n", ARG); + continue; + } + + if (!strcmp(NAME, "#println")) // arg + { + printf("%s\n", ARG); + continue; + } + + if (!strcmp(NAME, "$print")) // arg + { + printf("%s", ARG); + continue; + } + + if (!strcmp(NAME, "#print")) // arg + { + printf("%s", ARG); + continue; + } + + // Modules + + if (!strcmp(NAME, "args")) // arg + { + if (!originstack) + kms(stack, "ATTEMPTED TO USE ARGS IN THE MAIN MODULE"); + + if (DATA > STACK_SIZE) + kms(stack, "ATTEMPTED TO POP MORE THAN STACK_SIZE ARGUMENTS"); + + if (DATA == 0) + DATA = stack_pop(originstack); + + uint16_t ddata = DATA; + + while (ddata != 0) + { + stack_push(stack, stack_pop(originstack)); + ddata--; + } + continue; + } + + if (!strcmp(NAME, "#exec")) // arg + { + + if (!strcmp(ARG, modname)) + { + printf("MODULE %s: CAN'T EXECUTE ITSELF\n", ARG); + kms(stack, "CAN'T EXECUTE ITSELF"); + } + + FILE *file = fopen(ARG, "r"); + if (!file) + { + printf("ERROR OPENING MODULE: %s\n", ARG); + kms(stack, "ERROR OPENING MODULE"); + } + + DATA = DATA ? DATA : STACK_SIZE; + + Stack *tempstack = program_init(DATA); + + parse_and_process(tempstack, file); + + fclose(file); + + execute(tempstack, stack, ARG); + + for (int i = 0; i < tempstack->pointer; i++) + stack_push(stack, tempstack->memory[i]); + + free(tempstack); + + continue; + } + + // Self-modifying + + if (!strcmp(NAME, "#insert")) // arg + { + if (ARG[0] == '#' || ARG[0] == '$') + kms(stack, "ATTEMPTED TO INSERT A HASH/STRING-INSTRUCTION"); + + if (ARG[0] == '\n') + kms(stack, "ATTEMPTED TO INSERT AN EMPTY CONSTANT"); + + if (ARG[0] == '@' && ARG[1] == ' ') + kms(stack, "ATTEMPTED TO INSERT A LABEL"); + + stack->program[stack->program_size++] = (Instruction){ARG, "\n", DATA}; + + continue; + } + + // Special + + if (!strcmp(NAME, "dump")) + { + for (int i = 0; i < stack->pointer; i++) + printf("%d: %d\n", i, stack->memory[i]); + continue; + } + + if (!strcmp(NAME, "size")) + { + int i = 0; + while (i < stack->pointer) + i++; + + stack_push(stack, i); + continue; + } + + if (!strcmp(NAME, "maxsize")) + { + stack_push(stack, stack->stacksize); + continue; + } + + if (!strcmp(NAME, "#expr")) // arg + { + expression(stack, ARG); + continue; + } + + if (!strcmp(NAME, "nop")) + { + continue; + } + + if (!strcmp(NAME, "quit")) + { + break; + } + + if (!strcmp(NAME, "exit")) + { + exit(stack_pop(stack)); + } + + // Platform-specific + +#ifdef __unix__ + + if (!strcmp(NAME, "_unix_random")) + { + srand(getc(fopen("/dev/urandom", "r"))); + stack_push(stack, rand() % stack_pop(stack)); + continue; + } + +#endif + + // LBR-SPECIFIC + printf("UNKNOWN INSTRUCTION: %s\n", NAME); + kms(stack, "UNKNOWN INSTRUCTION"); + } +} + +#undef NAME +#undef ARG +#undef DATA diff --git a/src/execute.h b/src/execute.h new file mode 100644 index 0000000..b9fdc3c --- /dev/null +++ b/src/execute.h @@ -0,0 +1,3 @@ +#include "stack.h" + +void execute(Stack *stack, Stack *originstack, char *modname); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..40d22cc --- /dev/null +++ b/src/main.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include "config.h" +#include "execute.h" +#include "stack.h" + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + fprintf(stderr, "Usage: %s [FILE]\n", argv[0]); + return 1; + } + + Stack *stack = program_init(STACK_SIZE); + + FILE *file = fopen(argv[1], "r"); + if (!file) + { + perror("fopen()"); + return 1; + } + + parse_and_process(stack, file); + + fclose(file); + + execute(stack, (void *)0, argv[1]); + + return 0; +} diff --git a/src/stack.c b/src/stack.c new file mode 100644 index 0000000..a3aa456 --- /dev/null +++ b/src/stack.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +#include "config.h" +#include "stack.h" + +Stack *program_init(uint16_t stacksize) +{ + Stack *stack = malloc(sizeof(&stack) + sizeof(Instruction) * PROGRAM_MAXSIZE + sizeof(int16_t) * MAX_LABELS + + sizeof(uint16_t) * stacksize); + + stack->stacksize = stacksize; + + for (unsigned int i = 0; i < MAX_LABELS; i++) + stack->labels[i] = -1; // костыль ебанный + + return stack; +} + +void stack_push(Stack *stack, uint16_t data) +{ + if (stack->pointer > STACK_SIZE) + kms(stack, "STACK OVERFLOW"); + stack->memory[stack->pointer++] = data; +} + +uint16_t stack_pop(Stack *stack) +{ + if (stack->pointer <= 0) + kms(stack, "STACK UNDERFLOW"); + return stack->memory[--stack->pointer]; +} + +uint16_t stack_peek(Stack *stack) +{ + return stack->memory[stack->pointer - 1]; +} + +void kms(Stack *stack, const char *err) +{ + if (DEBUG_MODE) + for (int i = 0; i < stack->pointer; i++) + printf("%d: %d\n", i, stack->memory[i]); + + fprintf(stderr, "%s", err); + free(stack); + exit(1); +} + +void parse_and_process(Stack *stack, FILE *file) +{ + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, file) != -1) + { + if (line[0] == ';') + continue; + + line[strcspn(line, "\n")] = 0; + unsigned long com = strcspn(line, ";"); + if (com) + line[com] = '\0'; // шоб пропустил комментарий + + Instruction inst; + memset(&inst, 0, sizeof(inst)); // обнуляем структуру на всякий если + // вернутся старые значения + + inst.name = strtok(line, " "); + if (!inst.name) + continue; + + if (inst.name[0] == 9) + { + printf("Tabs are not allowed!\n"); + exit(1); + } + + char *data = strtok(NULL, ""); + + if (!data) + data = 0; + else if (inst.name[0] == '#' || inst.name[1] == '#') + inst.arg = strtok(data, " "); + else if (inst.name[0] == '$' || inst.name[1] == '$') + inst.arg = data; + else + inst.data = strtol(data, NULL, 10); + + char *duppedname = strdup(inst.name); + + if (!inst.arg) + inst.arg = "\n"; + char *duppedarg = strdup(inst.arg); + + stack->program[stack->program_size++] = (Instruction){duppedname, duppedarg, inst.data}; + } +} diff --git a/src/stack.h b/src/stack.h new file mode 100644 index 0000000..f958bcf --- /dev/null +++ b/src/stack.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include + +#include "config.h" + +typedef struct +{ + char *name; + char *arg; + uint16_t data; +} Instruction; + +typedef struct +{ + Instruction program[PROGRAM_MAXSIZE]; + uint16_t program_size, program_counter, stacksize; + int pointer; + int16_t labels[MAX_LABELS]; + uint16_t memory[]; +} Stack; + +Stack *program_init(uint16_t stacksize); + +void stack_push(Stack *stack, uint16_t data); + +uint16_t stack_pop(Stack *stack); + +uint16_t stack_peek(Stack *stack); + +void kms(Stack *stack, const char *err); + +void parse_and_process(Stack *stack, FILE *file); + +void repl(Stack *stack); diff --git a/tests/calc.lb b/tests/calc.lb new file mode 100644 index 0000000..70ccd94 --- /dev/null +++ b/tests/calc.lb @@ -0,0 +1,25 @@ +@ 0 + scan + scan + scan + |jmp 0 + +@ 1 + add + meow + quit + +@ 2 + sub + meow + quit + +@ 3 + mul + meow + quit + +@ 4 + div + meow + quit \ No newline at end of file diff --git a/tests/helloworld.lb b/tests/helloworld.lb new file mode 100644 index 0000000..95b656f --- /dev/null +++ b/tests/helloworld.lb @@ -0,0 +1,16 @@ +PUSH 76 ; L +PUTC +PUSH 97 ; a +PUTC +PUSH 98 ; b +PUTC +PUSH 97 ; a +PUTC +PUSH 115 ; s +PUTC +PUSH 104 ; h +PUTC +PUSH 107 ; k +PUTC +PUSH 105 ; i +PUTC \ No newline at end of file