Initial commit :3

This commit is contained in:
Aer Iz 2024-02-09 07:08:45 +02:00
commit 015ec69720
13 changed files with 1014 additions and 0 deletions

192
.clang-format Normal file
View File

@ -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
...

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.trash/
.dev/
spec.md
default.nix
lbr
std/

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
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.

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
CC=clang
all:
$(CC) -o lbr -O2 -Wall -Wextra -Wpedantic src/*.c
test:
./lbr tests/test.lb

1
README.md Normal file
View File

@ -0,0 +1 @@
Learning c and having fun

9
src/config.h Normal file
View File

@ -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

572
src/execute.c Normal file
View File

@ -0,0 +1,572 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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 <uint16>
{
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 <uint16>
{
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 <uint16>
{
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 <uint16>
{
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 <uint16>
{
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 <uint16>
{
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 <string>
{
printf("%s\n", ARG);
continue;
}
if (!strcmp(NAME, "#println")) // arg <string>
{
printf("%s\n", ARG);
continue;
}
if (!strcmp(NAME, "$print")) // arg <string>
{
printf("%s", ARG);
continue;
}
if (!strcmp(NAME, "#print")) // arg <const>
{
printf("%s", ARG);
continue;
}
// Modules
if (!strcmp(NAME, "args")) // arg <uint16>
{
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 <const>
{
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 <const>
{
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 <const>
{
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

3
src/execute.h Normal file
View File

@ -0,0 +1,3 @@
#include "stack.h"
void execute(Stack *stack, Stack *originstack, char *modname);

34
src/main.c Normal file
View File

@ -0,0 +1,34 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

100
src/stack.c Normal file
View File

@ -0,0 +1,100 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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};
}
}

35
src/stack.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#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);

25
tests/calc.lb Normal file
View File

@ -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

16
tests/helloworld.lb Normal file
View File

@ -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