diff --git a/benchmarks/main.c b/benchmarks/main.c index 0de2352..0a31a77 100644 --- a/benchmarks/main.c +++ b/benchmarks/main.c @@ -8,10 +8,17 @@ #include #include -#include "../src/lexer/lexer.h" +#include "../src/compiler/compiler.h" +#include "../src/compiler/structs.h" +#include "../src/compiler/pe/pe.h" + +#include "../src/ir/ir.h" +#include "../src/ir/instructions.h" +#include "../src/ir/structs.h" + #include "../src/parser/parser.h" +#include "../src/parser/structs/tree.h" #include "../src/parser/ast.h" -#include "../src/compiler/compiler.h" #include "../src/utils/logging.c" // Benchmark Settings @@ -91,18 +98,18 @@ void main(int argc, char* argv[]) { runs = atoi(argv[2]); } - char* c[5] = {"File IO (Open)", "Lexer", "Parser", "Compiler", "File IO (Close)"}; + char* c[6] = {"File IO (Open)", "Lexer", "AST", "IR", "Compiler", "Artifact Generator"}; categories = c; - for(int i = 0; i < 5; ++i) { - stats[i].total = 0; - stats[i].max = 0; - stats[i].low = 1000000; - stats[i].runs = malloc(sizeof(double) * runs); + for(int i = 0; i < 6; ++i) { + stats[i].total = 0; + stats[i].max = 0; + stats[i].low = 1000000; + stats[i].runs = malloc(sizeof(double) * runs); - for(int ii = 0; ii < runs; ++ii) { - stats[i].runs[ii] = 0; - } + for(int ii = 0; ii < runs; ++ii) { + stats[i].runs[ii] = 0; + } } for(int i = 0; i < runs; ++i) { @@ -117,7 +124,7 @@ void main(int argc, char* argv[]) { char* buff = (char*)malloc(size + 1); fread(buff, 1, size, fptr); - buff[size] = '\0'; + buff[size] = '\0'; fclose(fptr); endTimer(i, 0); @@ -125,68 +132,77 @@ void main(int argc, char* argv[]) { LEXER_RESULT result = runLexer(buff, size); - free(buff); + free(buff); endTimer(i, 1); startTimer(); - AST_NODE* node = parseNodes(result, 0, AST_ROOT); + void* node = parseRoot(result, 0, AST_TYPE_ROOT); endTimer(i, 2); startTimer(); - fptr = fopen("output.txt", "w"); + IR_OUTPUT* out = parseIR((AST_TREE_BRANCH*)node); - IR_CTX* ctx = makeContext(node); - compile(ctx, fptr); + endTimer(i, 3); + startTimer(); - fclose(fptr); + BYTECODE_BUFFER* b = compile(out); - endTimer(i, 3); + endTimer(i, 4); + startTimer(); + + fptr = fopen("output.exe", "w"); + compilePE(fptr, b); + + fclose(fptr); + + endTimer(i, 5); } printf("========= Benchmarking Results =========\n"); printf("Total time taken: %.3f micros, Average time per run: %.3f\n micros\n\n", totalTimeTaken, totalTimeTaken / runs); - for(int i = 0; i < 5; ++i) { - printf("Benchmarking Results of %s:\n", categories[i]); - printf(" Total time duration: %s%.2fus%s (%s%.1f%%%s over total running time)\n", TEXT_HCYAN, stats[i].total, RESET, TEXT_CYAN, (stats[i].total / totalTimeTaken) * 100, RESET); - printf(" Average: %s%.2fus%s\n", TEXT_HCYAN, stats[i].total / runs, RESET); - printf(" Range (%sFastest%s, %sLowest%s): %s%0.fus%s ... %s%.2fus%s\n\n", TEXT_HGREEN, RESET, TEXT_HRED, RESET, TEXT_HGREEN, stats[i].low, RESET, TEXT_HRED, stats[i].max, RESET); + + for(int i = 0; i < 6; ++i) { + printf("Benchmarking Results of %s:\n", categories[i]); + printf(" Total time duration: %s%.2fus%s (%s%.1f%%%s over total running time)\n", TEXT_HCYAN, stats[i].total, RESET, TEXT_CYAN, (stats[i].total / totalTimeTaken) * 100, RESET); + printf(" Average: %s%.2fus%s\n", TEXT_HCYAN, stats[i].total / runs, RESET); + printf(" Range (%sFastest%s, %sLowest%s): %s%0.fus%s ... %s%.2fus%s\n\n", TEXT_HGREEN, RESET, TEXT_HRED, RESET, TEXT_HGREEN, stats[i].low, RESET, TEXT_HRED, stats[i].max, RESET); - double averages[10]; - double highestAverage = 0; + double averages[10]; + double highestAverage = 0; - for(int ii = 0; ii < 10; ++ii) { - averages[ii] = 0; - } + for(int ii = 0; ii < 10; ++ii) { + averages[ii] = 0; + } - for(int ii = 0; ii < runs; ++ii) { - averages[ii / 10] += stats[i].runs[ii] / 10; - } + for(int ii = 0; ii < runs; ++ii) { + averages[ii / 10] += stats[i].runs[ii] / 10; + } - for(int ii = 0; ii < 10; ++ii) { - if(averages[ii] > highestAverage) highestAverage = averages[ii]; - } + for(int ii = 0; ii < 10; ++ii) { + if(averages[ii] > highestAverage) highestAverage = averages[ii]; + } - char spacing[3]; + char spacing[3]; - for(int ii = 0; ii < 10; ++ii) { - spacing[0] = '\0'; - if(ii == 0) strcat(spacing, " \0"); - else if(ii != 9) strcat(spacing, " \0"); + for(int ii = 0; ii < 10; ++ii) { + spacing[0] = '\0'; + if(ii == 0) strcat(spacing, " \0"); + else if(ii != 9) strcat(spacing, " \0"); - int clean = (averages[ii] / highestAverage) * BENCH_BAR_LENGTH; + int clean = (averages[ii] / highestAverage) * BENCH_BAR_LENGTH; - printf(" %d%% to %d%% Percentile:%s%s ", ii * 10, (ii + 1) * 10, spacing, TEXT_GRAY); - for(int c = 0; c < clean; ++c) { - printf("#"); - } - printf("%s (%s%.2fus%s average)\n", RESET, TEXT_HCYAN, averages[ii], RESET); - } + printf(" %d%% to %d%% Percentile:%s%s ", ii * 10, (ii + 1) * 10, spacing, TEXT_GRAY); + for(int c = 0; c < clean; ++c) { + printf("#"); + } + printf("%s (%s%.2fus%s average)\n", RESET, TEXT_HCYAN, averages[ii], RESET); + } - double timeWithoutHighest = stats[i].total - highestAverage * 10; - printf("\n Total time duration without highest avg: %s%.1fus%s (%s%.1f%%%s over total running time)", TEXT_HCYAN, timeWithoutHighest, RESET, TEXT_CYAN, (timeWithoutHighest / totalTimeTaken) * 100, RESET); - printf("\n Average without highest avg: %s%.2fus%s\n\n", TEXT_HCYAN, (timeWithoutHighest / runs), RESET); + double timeWithoutHighest = stats[i].total - highestAverage * 10; + printf("\n Total time duration without highest avg: %s%.1fus%s (%s%.1f%%%s over total running time)", TEXT_HCYAN, timeWithoutHighest, RESET, TEXT_CYAN, (timeWithoutHighest / totalTimeTaken) * 100, RESET); + printf("\n Average without highest avg: %s%.2fus%s\n\n", TEXT_HCYAN, (timeWithoutHighest / runs), RESET); } } diff --git a/src/cli/main.c b/src/cli/main.c index 301e54c..3ad8067 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -24,6 +24,8 @@ #include "../qasm/writer/writer.h" +#include "../compiler/structs.h" + #include "../utils/logging.c" // Version @@ -128,8 +130,12 @@ int main(int argc, char* argv[]) { fptr = fopen(outputFile, "w"); - writeQASM(fptr, irOut); // experimental: ir -> QASM - + BYTECODE_BUFFER* buffer = compile(irOut); + + compilePE(fptr, buffer); + + fclose(fptr); + break; case 'v': if(strlen(argv[1]) > 1 && strcmp(argv[1], "version") != 0) { diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 0ffd2b5..5d6991e 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -6,14 +6,40 @@ #include #include +#include "../ir/ir.h" +#include "../ir/instructions.h" + #include "./compiler.h" +#include "./win64.h" + #include "./pe/pe.h" /** - * Compiles the Context tree to an executable named the provided file name. - * @param ctx the IR context. - * @param out the output file. + * Compiles the IR into actual bytecode. + * @param out the IR output. */ -void compile(FILE* out) { -} +BYTECODE_BUFFER* compile(IR_OUTPUT* out) { + BYTECODE_BUFFER* buff = malloc(sizeof(BYTECODE_BUFFER)); + + buff->allocSize = 1024; + buff->size = 0; + buff->buff = malloc(sizeof(uint8_t) * 1024); + + COMPILER_CONTEXT* ctx = malloc(sizeof(COMPILER_CONTEXT)); + ctx->stackSize = 0; + ctx->currStack = 0; + ctx->map = createHashmap(200,512); + + ctx->blockOffsets = malloc(sizeof(int) * out->blockCount); + + for(int blockIndex = 0; blockIndex < out->blockCount; ++blockIndex) { + ctx->blockOffsets[blockIndex] = buff->size; + + for(int i = 0; i < out->blocks[blockIndex]->instructionCount; ++i) { + compileInstruction(buff, ctx, out->blocks[blockIndex]->instructions[i]); + } + } + + return buff; +} \ No newline at end of file diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h index c0e36ea..526ccb6 100644 --- a/src/compiler/compiler.h +++ b/src/compiler/compiler.h @@ -2,14 +2,17 @@ * The compiler of Quickfall. */ +#include "../ir/structs.h" + +#include "./structs.h" + #ifndef COMPILER_H #define COMPILER_H /** - * Compiles the Context tree to an executable named the provided name. - * @param ctx the IR context. - * @param char the output file. + * Compiles the IR into actual bytecode. + * @param out the IR output. */ -void compile(FILE* outputFileName); +BYTECODE_BUFFER* compile(IR_OUTPUT* out); #endif diff --git a/src/compiler/pe/pe.c b/src/compiler/pe/pe.c index a9f3b33..8a80bcf 100644 --- a/src/compiler/pe/pe.c +++ b/src/compiler/pe/pe.c @@ -7,11 +7,12 @@ #include #include "./format.h" +#include "../structs.h" /** * Compiles into PE format. */ -void compilePE(FILE* fptr, uint8_t program[], int programSize) { +void compilePE(FILE* fptr, BYTECODE_BUFFER* buff) { PE_DOS_HEADER dos_header = {0}; dos_header.e_magic = 0x5A4D; // "MZ" dos_header.e_lfanew = sizeof(PE_DOS_HEADER); @@ -55,7 +56,7 @@ void compilePE(FILE* fptr, uint8_t program[], int programSize) { memcpy(section_header.Name, ".text", 5); section_header.Misc.VirtualSize = 0x1000; section_header.VirtualAddress = 0x1000; - section_header.SizeOfRawData = programSize; + section_header.SizeOfRawData = buff->size; section_header.PointerToRawData = 0x200; section_header.Characteristics = 0x60000020; // Code | Execute | Read @@ -65,7 +66,7 @@ void compilePE(FILE* fptr, uint8_t program[], int programSize) { uint8_t padding[256] = {0}; fwrite(padding, 1, 0x200 - (sizeof(PE_DOS_HEADER) + sizeof(PE_NT_HEADERS) + sizeof(PE_OPTIONAL_HEADER) + sizeof(PE_SECTION_HEADER)), fptr); - fwrite(program, 1, programSize, fptr); + fwrite(buff->buff, 1, buff->size, fptr); fclose(fptr); } diff --git a/src/compiler/pe/pe.h b/src/compiler/pe/pe.h index a94aa18..a1e2cc3 100644 --- a/src/compiler/pe/pe.h +++ b/src/compiler/pe/pe.h @@ -5,12 +5,14 @@ #include #include +#include "../structs.h" + #ifndef COMPILER_PE #define COMPILER_PE /** * Compiles into PE format. */ -void compilePE(FILE* fptr, uint8_t program[], int programSize); +void compilePE(FILE* fptr, BYTECODE_BUFFER* buff); #endif diff --git a/src/compiler/structs.h b/src/compiler/structs.h new file mode 100644 index 0000000..d90b1d6 --- /dev/null +++ b/src/compiler/structs.h @@ -0,0 +1,38 @@ +/** + * Structures used by the Quickfall compiler. + */ + +#include "../utils/hashmap.h" + +#include + +#ifndef COMPILER_STRUCTS_H +#define COMPILER_STRUCTS_H + +/** + * A bytecode buffer, is used to transmit byte codes around. + */ +typedef struct BYTECODE_BUFFER { + + uint8_t* buff; + int size; + int allocSize; + +} BYTECODE_BUFFER; + +/** + * A structure holding all of the necessary information during the compiling process. + * For example, value pointers + */ +typedef struct COMPILER_CONTEXT { + + struct Hashmap* map; + int stackSize; + int currStack; + + int* blockOffsets; + +} COMPILER_CONTEXT; + + +#endif \ No newline at end of file diff --git a/src/compiler/win64.c b/src/compiler/win64.c new file mode 100644 index 0000000..06df782 --- /dev/null +++ b/src/compiler/win64.c @@ -0,0 +1,217 @@ +/** + * The Win-x64 support for the Quickfall compiler. + */ + +#include +#include + +#include "../ir/structs.h" +#include "../ir/instructions.h" + +#include "./structs.h" + +#include "../utils/hashmap.h" +#include "../utils/hash.h" + +/** + * Compiles an QAsm / IR instruction to the Win-x64 bytecode. + * @param buff the bytecode buffer. + * @param ctx the compiler context. + * @param instruction the instruction to convert. + */ +void compileInstruction(BYTECODE_BUFFER* buff, COMPILER_CONTEXT* ctx, IR_INSTRUCTION* instruction) { + + switch(instruction->opCode) { + case RET: + buff->buff[buff->size] = 0xC3; + buff->size++; + break; + + case STACK_SAVE: + buff->buff[buff->size] = 0x55; + + buff->buff[buff->size + 1] = 0x48; + buff->buff[buff->size + 2] = 0x89; + buff->buff[buff->size + 3] = 0xE5; + + buff->size += 4; + break; + + case STACK_LOAD: + buff->buff[buff->size] = 0x5D; + buff->size++; + break; + + case S_ALLOC: + buff->buff[buff->size] = 0x48; + buff->buff[buff->size + 1] = 0x83; + buff->buff[buff->size + 2] = 0xEC; + + int i = (((unsigned char*)instruction->params[0])[0] << 24) | (((unsigned char*)instruction->params[0])[1] << 16) | (((unsigned char*)instruction->params[0])[2] << 8) | ((unsigned char*)instruction->params[0])[3]; + + ctx->currStack += i; + ctx->stackSize += i; + + int* ptr = malloc(sizeof(int)); + *ptr = ctx->stackSize; + + hashPut(ctx->map, hashstr(instruction->params[1]), ptr); + + buff->buff[buff->size + 3] = i; + + buff->size += 4; + break; + + case PTR_SET: + buff->buff[buff->size] = 0xC6; + buff->buff[buff->size + 1] = 0x45; + + int* ii = hashGet(ctx->map, hashstr(instruction->params[0])); + + buff->buff[buff->size + 2] = (uint8_t) *ii; + + buff->buff[buff->size + 3] = ((unsigned char*)instruction->params[1])[0]; + + buff->size += 4; + break; + + case DUO_SET: + buff->buff[buff->size] = 0x66; + buff->buff[buff->size + 1] = 0x45; + + ii = hashGet(ctx->map, hashstr(instruction->params[0])); + + buff->buff[buff->size + 2] = (uint8_t) *ii; + + buff->buff[buff->size + 3] = ((unsigned char*)instruction->params[1])[3]; + buff->buff[buff->size + 4] = ((unsigned char*)instruction->params[1])[2]; + + buff->size += 5; + + case QUAD_SET: //dword + buff->buff[buff->size] = 0xC7; + buff->buff[buff->size + 1] = 0x45; + + ii = hashGet(ctx->map, hashstr(instruction->params[0])); + + buff->buff[buff->size + 2] = (uint8_t) *ii; + + buff->buff[buff->size + 3] = ((unsigned char*)instruction->params[1])[3]; + buff->buff[buff->size + 4] = ((unsigned char*)instruction->params[1])[2]; + buff->buff[buff->size + 5] = ((unsigned char*)instruction->params[1])[1]; + buff->buff[buff->size + 6] = ((unsigned char*)instruction->params[1])[0]; + + buff->size += 7; + break; + + case OCT_SET: //qword + buff->buff[buff->size] = 0x48; + buff->buff[buff->size + 1] = 0xC7; + buff->buff[buff->size + 2] = 0x45; + + ii = hashGet(ctx->map, hashstr(instruction->params[0])); + + buff->buff[buff->size + 3] = (uint8_t) *ii; + + buff->buff[buff->size + 4] = ((unsigned char*)instruction->params[1])[7]; + buff->buff[buff->size + 5] = ((unsigned char*)instruction->params[1])[6]; + buff->buff[buff->size + 6] = ((unsigned char*)instruction->params[1])[5]; + buff->buff[buff->size + 7] = ((unsigned char*)instruction->params[1])[4]; + buff->buff[buff->size + 8] = ((unsigned char*)instruction->params[1])[3]; + buff->buff[buff->size + 9] = ((unsigned char*)instruction->params[1])[2]; + buff->buff[buff->size + 10] = ((unsigned char*)instruction->params[1])[1]; + buff->buff[buff->size + 11] = ((unsigned char*)instruction->params[1])[0]; + + buff->size += 12; + break; + + case STACK_FREE_FUNC: + buff->buff[buff->size] = 0x48; + buff->buff[buff->size + 1] = 0x83; + buff->buff[buff->size + 2] = 0xC4; + + buff->buff[buff->size + 3] = (uint8_t) ctx->currStack; + + buff->size += 4; + break; + + case PTR_DEC: + ii = malloc(sizeof(int)); + *ii = (((unsigned char*)instruction->params[1])[0] << 24) | (((unsigned char*)instruction->params[1])[1] << 16) | (((unsigned char*)instruction->params[1])[2] << 8) | ((unsigned char*)instruction->params[1])[3]; + + hashPut(ctx->map, hashstr(instruction->params[0]), ii); + break; + + case PTR_DEC_OFF: + ii = malloc(sizeof(int)); + *ii = (((unsigned char*)instruction->params[2])[0] << 24) | (((unsigned char*)instruction->params[2])[1] << 16) | (((unsigned char*)instruction->params[2])[2] << 8) | ((unsigned char*)instruction->params[2])[3]; + + int* o = hashGet(ctx->map, hashstr(instruction->params[1])); + + *ii += *o; + + hashPut(ctx->map, hashstr(instruction->params[0]), ii); + break; + + case BLOCK_SWAP: + buff->buff[buff->size] = 0xE9; + + i = (((unsigned char*)instruction->params[0])[0] << 24) | (((unsigned char*)instruction->params[0])[1] << 16) | (((unsigned char*)instruction->params[0])[2] << 8) | ((unsigned char*)instruction->params[0])[3]; + + int off = ctx->blockOffsets[i] - buff->size; + + buff->buff[buff->size + 1] = off & 0xFF; + buff->buff[buff->size + 2] = (off >> 8) & 0xFF; + buff->buff[buff->size + 3] = (off >> 16) & 0xFF; + buff->buff[buff->size + 4] = (off >> 24) & 0xFF; + + buff->size += 5; + break; + + case COND_BLOCK_SWAP: + buff->buff[buff->size] = 0x80; + buff->buff[buff->size + 1] = 0x7d; + + i = (((unsigned char*)instruction->params[0])[0] << 24) | (((unsigned char*)instruction->params[0])[1] << 16) | (((unsigned char*)instruction->params[0])[2] << 8) | ((unsigned char*)instruction->params[0])[3]; + + off = ctx->blockOffsets[i] - buff->size; + + ii = hashGet(ctx->map, hashstr(instruction->params[1])); + + + buff->buff[buff->size + 2] = *ii & 0xFF; + buff->buff[buff->size + 3] = 0x01; + + buff->buff[buff->size + 4] = 0x74; + buff->buff[buff->size + 5] = off & 0xFF; + + buff->size += 6; + break; + case LOGICAL_BLOCK_SWAP: + int trueBlockId = (((unsigned char*)instruction->params[0])[0] << 24) | (((unsigned char*)instruction->params[0])[1] << 16) | (((unsigned char*)instruction->params[0])[2] << 8) | ((unsigned char*)instruction->params[0])[3]; + int falseBlockId = (((unsigned char*)instruction->params[1])[0] << 24) | (((unsigned char*)instruction->params[1])[1] << 16) | (((unsigned char*)instruction->params[1])[2] << 8) | ((unsigned char*)instruction->params[1])[3]; + + // Instead of doing if else, just jump to the block if true and continue if not + + ii = hashGet(ctx->map, hashstr(instruction->params[2])); + + buff->buff[buff->size] = 0x80; + buff->buff[buff->size + 1] = 0x7d; + + buff->buff[buff->size + 2] = *ii & 0xFF; + buff->buff[buff->size + 3] = 0x01; + + buff->buff[buff->size + 4] = 0x74; + buff->buff[buff->size + 5] = (ctx->blockOffsets[trueBlockId] - buff->size) & 0xFF; + + // else + off = ctx->blockOffsets[falseBlockId] - buff->size; + + buff->buff[buff->size + 6] = off & 0xFF; + buff->buff[buff->size + 7] = (off >> 8) & 0xFF; + buff->buff[buff->size + 8] = (off >> 16) & 0xFF; + buff->buff[buff->size + 9] = (off >> 24) & 0xFF; + + buff->size += 10; + } +} \ No newline at end of file diff --git a/src/compiler/win64.h b/src/compiler/win64.h new file mode 100644 index 0000000..9cf00a4 --- /dev/null +++ b/src/compiler/win64.h @@ -0,0 +1,23 @@ +/** + * The Win-x64 support for the Quickfall compiler. + */ + +#include + +#include "../ir/structs.h" +#include "../ir/instructions.h" + +#include "./structs.h" + +#ifndef COMPILER_WIN_64_H +#define COMPILER_WIN_64_H + +/** + * Compiles an QAsm / IR instruction to the Win-x64 bytecode. + * @param buff the bytecode buffer. + * @param ctx the compiler context. + * @param instruction the instruction to convert. + */ +void compileInstruction(BYTECODE_BUFFER* buff, COMPILER_CONTEXT* ctx, IR_INSTRUCTION* instruction); + +#endif \ No newline at end of file diff --git a/src/ir/instructions.h b/src/ir/instructions.h index 0286b9d..6991056 100644 --- a/src/ir/instructions.h +++ b/src/ir/instructions.h @@ -38,13 +38,6 @@ typedef enum IR_INSTRUCTION_CODE { */ S_ALLOC, - /** - * Sets the value of the pointer's address to the provided element. - * @param val the new value (an integer for now). - * @param ptr the pointer containing the target address. - */ - PTR_SET, - /** * Loads the values of a specific address into a variable. * @param var the output variable. @@ -131,7 +124,68 @@ typedef enum IR_INSTRUCTION_CODE { /** * Returns from a function. */ - RET + RET, + + /** + * Saves the stack. + */ + STACK_SAVE, + + + /** + * Loads the stack back. + */ + STACK_LOAD, + + /** + * Frees all of the stack used by the function. + */ + STACK_FREE_FUNC, + + + /** + * Sets the byte located at the pointer. + * @param ptr the pointer containing the target address. + * @param val the new value (an integer for now). + */ + PTR_SET, + + /** + * Sets 32 bits located at the pointer. + * @param ptr the pointer containing the target address. + * @param val the new integer value. + */ + QUAD_SET, + + /** + * Sets 16 bits located at the pointer. + * @param ptr the pointer containing the target address. + * @param val the new integer value. + */ + DUO_SET, + + /** + * Sets 64 bits located at the pointer. + * @param ptr the pointer containing the target address. + * @param val the new integer value. + */ + OCT_SET, + + + /** + * Declares a pointer at the specified address. + * @param ptr the new pointer. + * @param addr the address + */ + PTR_DEC, + + /** + * Declares a pointer that is an offset of another pointer. + * @param ptr the new pointer. + * @param p the old pointer. + * @param off the offset. + */ + PTR_DEC_OFF } IR_INSTRUCTION_CODE; diff --git a/src/ir/irs/functions.c b/src/ir/irs/functions.c index 1a98b3b..dab3f69 100644 --- a/src/ir/irs/functions.c +++ b/src/ir/irs/functions.c @@ -62,6 +62,13 @@ void parseFunction(IR_OUTPUT* out, AST_FUNCTION_DEC* node) { break; } } + + appendInstruction(out->blocks[out->blockCount], STACK_FREE_FUNC, NULL, 0); + appendInstruction(out->blocks[out->blockCount], STACK_LOAD, NULL, 0); + + appendInstruction(out->blocks[out->blockCount], RET, NULL, 0); + + out->blockCount++; } /** @@ -81,6 +88,9 @@ void parseASMFunction(IR_OUTPUT* out, AST_ASM_FUNCTION_DEC* node) { out->blocks[out->blockCount] = malloc(sizeof(IR_BASIC_BLOCK)); out->blocks[out->blockCount]->instructions = NULL; out->blocks[out->blockCount]->instructionCount = 0; + out->blocks[out->blockCount]->allocatedSize = 0; parseQAsmInstructions(out->blocks[out->blockCount], node->buff, node->buffIndex); + + out->blockCount++; } \ No newline at end of file diff --git a/src/ir/irs/values.c b/src/ir/irs/values.c index 950ad58..58ea9fb 100644 --- a/src/ir/irs/values.c +++ b/src/ir/irs/values.c @@ -3,6 +3,7 @@ */ #include +#include #include "../../parser/ast.h" @@ -61,6 +62,34 @@ void parseValue(void** buff, int index, void* value) { } } +/** + * Gets the byte equivalent. + * @param value the value. + */ +unsigned char* getByteEquivalent(void* value) { + if(((AST_TREE_BRANCH*)value)->type == AST_TYPE_VALUE) { + AST_VALUE* val = (AST_VALUE*)value; + + switch(*val->valueType) { + case INT32: + case INT24: + case INT16: + case INT8: + + int num = atoi(val->value); + + unsigned char* buff = malloc(4); + + buff[0] = (num >> 24) & 0xFF; + buff[1] = (num >> 16) & 0xFF; + buff[2] = (num >> 8) & 0xFF; + buff[3] = num & 0xFF; + + return buff; + } + } +} + /** * Gets the value size for a certain type for a parameter. * @param type the type's byte indentifier. diff --git a/src/ir/irs/values.h b/src/ir/irs/values.h index 018b3ad..900f873 100644 --- a/src/ir/irs/values.h +++ b/src/ir/irs/values.h @@ -13,6 +13,12 @@ */ void parseValue(void** buff, int index, void* value); +/** + * Gets the byte equivalent. + * @param value the value. + */ +unsigned char* getByteEquivalent(void* value); + /** * Gets the value size for a certain type for a parameter. * @param type the type's byte indentifier. diff --git a/src/ir/irs/variables.c b/src/ir/irs/variables.c index c35e6d5..596f70c 100644 --- a/src/ir/irs/variables.c +++ b/src/ir/irs/variables.c @@ -7,6 +7,7 @@ #include #include "../../parser/structs/variables.h" +#include "../../parser/structs/values.h" #include "./values.h" @@ -32,6 +33,7 @@ void parseVariableDeclaration(IR_BASIC_BLOCK* block, AST_VARIABLE_DEC* node) { case INT16: allocSize = 16; break; + case BIT: // bit is 8 for now, only for now case INT8: allocSize = 8; break; @@ -53,15 +55,60 @@ void parseVariableDeclaration(IR_BASIC_BLOCK* block, AST_VARIABLE_DEC* node) { params[1] = node->name; + appendInstruction(block, STACK_SAVE, NULL, 0); + appendInstruction(block, S_ALLOC, params, 2); if(node->value != NULL) { - params = malloc(sizeof(void*) * 2); - params[0] = node->name; + AST_VALUE* val = (AST_VALUE*) node->value; + if(node->type[0] == BIT) { + params = malloc(sizeof(void*) * 2); + params[0] = node->name; + + params[1] = malloc(1); + ((unsigned char*)params[1])[0] = strcmp(val->value, "true") == 0; + + appendInstruction(block, PTR_SET, params, 2); + } + else if(allocSize == 32) { // if allocates 32 bits, use qd_set + params = malloc(sizeof(void*) * 2); + params[0] = node->name; - parseValue(params, 1, node->value); - - appendInstruction(block, PTR_SET, params, 2); + parseValue(params, 1, node->value); + + appendInstruction(block, QUAD_SET, params, 2); + } + else { + unsigned char* equiv = getByteEquivalent(node->value); + + for(int i = 4; i > (4 - allocSize / 8); --i) { + int size = strlen(node->name) + 2; + char* ptrName = malloc(size); + ptrName[size] = '\0'; + ptrName[size - 1] = (char) i + 97; + + params = malloc(sizeof(void*) * 3); + params[0] = ptrName; + params[1] = node->name; + + params[2] = malloc(4); + unsigned char* buff = (unsigned char*) params[2]; + + buff[0] = ((i - 4) * 8 - 1 >> 24) & 0xFF; + buff[1] = ((i - 4) * 8 - 1 >> 16) & 0xFF; + buff[2] = ((i - 4) * 8 - 1 >> 8) & 0xFF; + buff[3] = (i - 4) * 8 - 1 & 0xFF; + + appendInstruction(block, PTR_DEC_OFF, params, 3); + + params = malloc(sizeof(void*) * 2); + params[0] = ptrName; + params[1] = malloc(1); + ((unsigned char*)params[1])[0] = equiv[i - 1]; + + appendInstruction(block, PTR_SET, params, 2); + } + } } } diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 72fac0d..ce915a7 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -8,14 +8,12 @@ #include #include "./lexer.h" -#include "./tokens.h" -#include "../utils/hashes.h" /** * Sets the token type of the currently selected token in the LexerResult with the provided token type. */ -void pushToken(LEXER_RESULT* result, TOKEN_TYPE type) { +void pushToken(LEXER_RESULT* result, LEXER_TOKEN_TYPE type) { result->tokens[result->size].type = type; result->size++; } @@ -64,13 +62,19 @@ LEXER_RESULT runLexer(char* string, int size) { } else if (c == '\"') { int strLen = 0; - while(c != '\"') { + ++i; + c = string[i]; + + while(c != '\"' && c != '\0') { buff[strLen] = c; strLen++; ++i; c = string[i]; - } + } + + buff[strLen] = '\0'; + ++i; pushToken(&result, STRING); result.tokens[result.size - 1].value = buff; @@ -121,6 +125,9 @@ LEXER_RESULT runLexer(char* string, int size) { else if(strcmp(buff, "int8") == 0) { pushToken(&result, TYPE_INT8); } + else if(strcmp(buff, "bit") == 0) { + pushToken(&result, TYPE_BIT); + } else { pushToken(&result, KEYWORD); result.tokens[result.size - 1].value = buff; diff --git a/src/lexer/lexer.h b/src/lexer/lexer.h index 61bb123..959c297 100644 --- a/src/lexer/lexer.h +++ b/src/lexer/lexer.h @@ -2,7 +2,45 @@ #define LEXER_H #include -#include "./tokens.h" + +typedef enum { + ASM_FUNCTION, + FUNCTION, + RETURN, + VAR, + BRACKETS_OPEN, + BRACKETS_CLOSE, + PAREN_OPEN, + PAREN_CLOSE, + ARRAY_OPEN, + ARRAY_CLOSE, + NUMBER, + STRING, + BOOLEAN_VALUE, + NU, + KEYWORD, + SEMICOLON, + COMMA, + DECLARE, + USE, + NONE, + MATH_OP, + + TYPE_INT32, + TYPE_INT24, + TYPE_INT16, + TYPE_INT8, + TYPE_BIT +} LEXER_TOKEN_TYPE; + +/** + * An lexer token generated by the Lexer. + */ +typedef struct { + LEXER_TOKEN_TYPE type; + char* value; +} TOKEN; + /** * Contains the results of lexical analysis @@ -23,6 +61,6 @@ LEXER_RESULT runLexer(char* input, int size); * @param result The LexerResult to add the token to * @param type The type of the token to add */ -void pushToken(LEXER_RESULT* result, TOKEN_TYPE type); +void pushToken(LEXER_RESULT* result, LEXER_TOKEN_TYPE type); #endif diff --git a/src/lexer/tokens.h b/src/lexer/tokens.h deleted file mode 100644 index 15391f6..0000000 --- a/src/lexer/tokens.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TOKENS_H -#define TOKENS_H - -typedef enum { - ASM_FUNCTION, - FUNCTION, - RETURN, - VAR, - BRACKETS_OPEN, - BRACKETS_CLOSE, - PAREN_OPEN, - PAREN_CLOSE, - ARRAY_OPEN, - ARRAY_CLOSE, - NUMBER, - STRING, - BOOLEAN_VALUE, - NU, - KEYWORD, - SEMICOLON, - COMMA, - DECLARE, - USE, - NONE, - MATH_OP, - - TYPE_INT32, - TYPE_INT24, - TYPE_INT16, - TYPE_INT8 -} TOKEN_TYPE; - -/** - * An lexer token generated by the Lexer. - */ -typedef struct { - TOKEN_TYPE type; - char* value; -} TOKEN; - - -#endif diff --git a/src/lib/types.h b/src/lib/types.h index 24b0ad0..3063a03 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -13,7 +13,8 @@ typedef enum LIB_TYPES { INT32 = 0x01, INT24 = 0x02, INT16 = 0x03, - INT8 = 0x04 + INT8 = 0x04, + BIT = 0x05 } LIB_TYPES; diff --git a/src/parser/asts/functions.c b/src/parser/asts/functions.c index 662f83f..5fb68d6 100644 --- a/src/parser/asts/functions.c +++ b/src/parser/asts/functions.c @@ -15,6 +15,8 @@ #include "../../lexer/lexer.h" +#include "../../utils/string.h" + /** * Parses a function declaration into AST. * @param result the Lexer result. @@ -98,14 +100,44 @@ AST_ASM_FUNCTION_DEC* parseASMFunctionDeclaration(LEXER_RESULT result, int index index = func->endingIndex; - if(result.tokens[index + 1].type != BRACKETS_OPEN || result.tokens[index + 2].type != STRING || result.tokens[index + 3].type != BRACKETS_CLOSE) { + if(result.tokens[index + 1].type != BRACKETS_OPEN) { printf("Error: Badly made ASM function body!\n"); return NULL; } - func->buff = result.tokens[index + 2].value; - func->buffIndex = strlen(func->buff); + int allocatedBuff = 512; + + func->buff = malloc(allocatedBuff); + func->buffIndex = 0; + + index += 2; + for(; index < result.size; ++index) { + TOKEN t = result.tokens[index]; + + if(t.type == BRACKETS_CLOSE) { + func->endingIndex = index; + return func; + } + else if(t.type == STRING) { + func->buffIndex = fast_strcat(func->buff, t.value, func->buffIndex) + 1; // Adds one to the index to keep the seperator. + func->buff[func->buffIndex - 1] = '\n'; + + if(func->buffIndex >= allocatedBuff) { + allocatedBuff *= 1.5; + func->buff = realloc(func->buff, allocatedBuff); + } + + } + else { + printf("Error: disallowed token %d in ASM function! Only string are allowed in body!\n", t.type); + printf("%s", t.value); + return NULL; + } + + } + + func->endingIndex = index; return func; } diff --git a/src/parser/asts/values.c b/src/parser/asts/values.c index 26ab697..80a6d35 100644 --- a/src/parser/asts/values.c +++ b/src/parser/asts/values.c @@ -36,6 +36,15 @@ AST_VALUE* parseASTValue(LEXER_RESULT result, int index, LIB_TYPES exceptedType) value->valueType = malloc(1); value->valueType[0] = exceptedType; break; + case BIT: + if(result.tokens[index].type != BOOLEAN_VALUE) { + printf("Excepted boolean as bit value!\n"); + return NULL; + } + + value->valueType = malloc(1); + value->valueType[0] = BIT; + break; } value->endingIndex = index + 1; @@ -59,6 +68,10 @@ void* parseValueGroup(LEXER_RESULT result, int index, LIB_TYPES exceptedType) { return parseASTValue(result, index, exceptedType); break; + + case BOOLEAN_VALUE: + return parseASTValue(result, index, exceptedType); + default: printf("Error: couldn't parse value token group!\n"); return NULL; diff --git a/src/parser/asts/variables.c b/src/parser/asts/variables.c index edc5e0a..2da8e6e 100644 --- a/src/parser/asts/variables.c +++ b/src/parser/asts/variables.c @@ -29,6 +29,7 @@ AST_VARIABLE_DEC* parseASTVariableDeclaration(LEXER_RESULT result, int index) { case TYPE_INT24: case TYPE_INT16: case TYPE_INT8: + case TYPE_BIT: var->type[0] = (result.tokens[index].type - TYPE_INT32) + 0x01; break; diff --git a/src/parser/parser.c b/src/parser/parser.c index 533f1fa..9cae156 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -38,6 +38,7 @@ void* parseRoot(LEXER_RESULT result, int startingIndex, AST_TYPE type) { case TYPE_INT24: case TYPE_INT16: case TYPE_INT8: + case TYPE_BIT: case VAR: void* node = parseASTVariableDeclaration(result, i); if(node != NULL) { diff --git a/src/qasm/parser/parser.c b/src/qasm/parser/parser.c index 6ffccf5..ef6354e 100644 --- a/src/qasm/parser/parser.c +++ b/src/qasm/parser/parser.c @@ -38,6 +38,12 @@ void parseQAsmInstructions(IR_BASIC_BLOCK* block, char* buffer, int size) { if(c == '\0') return; if(c == '\n') { + if(secIndex != 0) { + ((char*)buff[buffIndex])[secIndex] = '\0'; + secIndex = 0; + buffIndex++; + } + IR_INSTRUCTION* instruction = parseInstruction(buff, buffIndex); if(instruction == NULL) { @@ -80,7 +86,7 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { // Determines the instruction type based on the string hash. switch(instructionHash) { - case 2985: + case 1648: instruction->opCode = BLOCK_SWAP; b = malloc(sizeof(void*)); parseInt32(b, 0, buff[1]); @@ -88,7 +94,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 1; break; - case 2987: + + case 842: instruction->opCode = COND_BLOCK_SWAP; b = malloc(sizeof(void*) * 2); @@ -98,7 +105,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 2; break; - case 3275: + + case 1891: instruction->opCode = LOGICAL_BLOCK_SWAP; b = malloc(sizeof(int*) * 3); @@ -109,7 +117,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1798: + + case 275: instruction->opCode = S_ALLOC; b = malloc(sizeof(void*) * 2); @@ -119,17 +128,19 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 2; break; - case 2887: + + case 2133: instruction->opCode = PTR_SET; b = malloc(sizeof(void*) * 2); - parseInt32(b, 0, buff[1]); - parseVariableName(b, 1, buff[2]); + parseVariableName(b, 0, buff[1]); + parseInt32(b, 1, buff[2]); instruction->params = b; instruction->paramCount = 2; break; - case 2472: + + case 2059: instruction->opCode = PTR_LOAD; b = malloc(sizeof(void*) * 2); @@ -139,7 +150,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 2; break; - case 452: + + case 3257: instruction->opCode = IADD; b = malloc(sizeof(void*) * 3); @@ -150,7 +162,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1508: + + case 1305: instruction->opCode = ISUB; b = malloc(sizeof(void*) * 3); @@ -161,7 +174,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1636: + + case 386: instruction->opCode = IMUL; b = malloc(sizeof(void*) * 3); @@ -172,7 +186,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1284: + + case 780: instruction->opCode = IDIV; b = malloc(sizeof(void*) * 3); @@ -183,7 +198,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1188: + + case 3858: instruction->opCode = ICMP; b = malloc(sizeof(void*) * 3); @@ -194,7 +210,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1350: + + case 3409: instruction->opCode = ICMP_H; b = malloc(sizeof(void*) * 3); @@ -205,7 +222,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 1478: + + case 118: instruction->opCode = ICMP_L; b = malloc(sizeof(void*) * 3); @@ -216,7 +234,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 3; break; - case 3272: + + case 2745: instruction->opCode = PRM_PUSH; b = malloc(sizeof(void*) * 2); @@ -226,7 +245,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 2; break; - case 3144: + + case 3108: instruction->opCode = RET_PUSH; b = malloc(sizeof(void*)); @@ -235,7 +255,8 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 1; break; - case 772: + + case 2123: instruction->opCode = CALL; b = malloc(sizeof(void*)); @@ -244,11 +265,86 @@ IR_INSTRUCTION* parseInstruction(char** buff, int bufferSize) { instruction->params = b; instruction->paramCount = 1; break; - case 1283: + + case 1042: instruction->opCode = RET; instruction->params = NULL; instruction->paramCount = 0; break; + + case 865: + instruction->opCode = STACK_SAVE; + instruction->params = NULL; + instruction->paramCount = 0; + break; + + case 572: + instruction->opCode = STACK_LOAD; + instruction->params = NULL; + instruction->paramCount = 0; + break; + + case 3237: + instruction->opCode = STACK_FREE_FUNC; + instruction->params = NULL; + instruction->paramCount = 0; + break; + + case 745: + instruction->opCode = QUAD_SET; + b = malloc(sizeof(void*) * 2); + + parseVariableName(b, 0, buff[1]); + parseInt32(b, 1, buff[2]); + + instruction->params = b; + instruction->paramCount = 2; + break; + + case 2397: + instruction->opCode = DUO_SET; + b = malloc(sizeof(void*) * 2); + + parseVariableName(b, 0, buff[1]); + parseInt32(b, 1, buff[2]); + + instruction->params = b; + instruction->paramCount = 2; + break; + + case 3398: + instruction->opCode = OCT_SET; + b = malloc(sizeof(void*) * 2); + + parseVariableName(b, 0, buff[1]); + parseInt32(b, 1, buff[2]); + + instruction->params = b; + instruction->paramCount = 2; + + case 2087: + instruction->opCode = PTR_DEC; + b = malloc(sizeof(void*) * 2); + + parseVariableName(b, 0, buff[1]); + parseInt32(b, 1, buff[2]); + + instruction->params = b; + instruction->paramCount = 2; + break; + + case 2137: + instruction->opCode = PTR_DEC_OFF; + b = malloc(sizeof(void*) * 3); + + parseVariableName(b, 0, buff[1]); + parseVariableName(b, 1, buff[2]); + parseVariableName(b, 2, buff[3]); + + instruction->params = b; + instruction->paramCount = 3; + break; + default: printf("Error: Unknown instruction %s!\n", buff[0]); return NULL; diff --git a/src/qasm/parser/values.c b/src/qasm/parser/values.c index 48b3e9f..56c2cd4 100644 --- a/src/qasm/parser/values.c +++ b/src/qasm/parser/values.c @@ -36,5 +36,9 @@ void parseVariableName(void** buff, int index, char* str) { return; } - buff[index] = (str + 1); + int size = strlen(str); + buff[index] = malloc(size); + + memccpy(buff[index], str, 1, size); + ((char*)buff[index])[size] = '\0'; } \ No newline at end of file diff --git a/src/qasm/writer/writer.c b/src/qasm/writer/writer.c index 29fd6bd..64b6af5 100644 --- a/src/qasm/writer/writer.c +++ b/src/qasm/writer/writer.c @@ -9,7 +9,7 @@ #include "../../ir/instructions.h" #include "../../ir/structs.h" -const char* formatedInstructions[] = {"blck_swap", "cblk_swap", "lblck_swap", "salloc", "ptr_set", "ptr_load", "iadd", "isub", "imul", "idiv", "icmp", "icmp_h", "icmp_l", "prm_push", "ret_push", "call", "ret"}; +const char* formatedInstructions[] = {"blck_swap", "cblk_swap", "lblck_swap", "salloc", "ptr_load", "iadd", "isub", "imul", "idiv", "icmp", "icmp_h", "icmp_l", "prm_push", "ret_push", "call", "ret", "st_push", "st_load", "st_freef", "ptr_set", "qd_set", "dd_set", "od_set", "ptr_dec", "optr_dec"}; /** * Writes some standart QuickAssembly code equivalent to the parsed IR. @@ -62,7 +62,6 @@ void writeQASM(FILE* fptr, IR_OUTPUT* output) { case RET_PUSH: writeVarName(fptr, instruction->params, 0); break; - } } diff --git a/src/utils/hash.c b/src/utils/hash.c index 6f5e5d9..db6857f 100644 --- a/src/utils/hash.c +++ b/src/utils/hash.c @@ -2,16 +2,23 @@ * Hashing related utilities. */ -#include - unsigned int hashstr(char* str) { - unsigned int result = 0; - unsigned char* p = (unsigned char*) str; - - while(*p != '\0') { - result = ((*p - 97) << 5) + result + 1; - ++p; - } - - return result; + unsigned int hash = 2166136261u; // FNV offset basis + unsigned char *p = (unsigned char *)str; + + while (*p) { + char c = *p++; + if(c == '\0') break; + + hash ^= c; + hash *= 16777619u; // FNV prime + hash &= 0x0FFF; // Keep only 12 bits to maintain smaller values + } + + // Final mixing for better distribution in small range + hash ^= hash >> 6; + hash *= 0x9E3779B1; // Golden ratio prime + hash &= 0x0FFF; // Final mask to 12 bits + + return hash; } diff --git a/src/utils/hash.h b/src/utils/hash.h index 50e1340..4278472 100644 --- a/src/utils/hash.h +++ b/src/utils/hash.h @@ -1,6 +1,7 @@ #ifndef HASH_UTILS #define HASH_UTILS + /** * Hashes the string. */ diff --git a/src/utils/hashes.c b/src/utils/hashes.c deleted file mode 100644 index e04cde9..0000000 --- a/src/utils/hashes.c +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Hashmap related utilities for Quickfall. - */ - -#include - -/** - * Generates a hash for a lexar token. Currently compromisable - */ -int tokenHash(char* token) { - return strlen(token); -} \ No newline at end of file diff --git a/src/utils/hashes.h b/src/utils/hashes.h deleted file mode 100644 index 93d6d12..0000000 --- a/src/utils/hashes.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef HASHES_H -#define HASHES_H - -/** - * Calculates a hash value for a string. - * Uses a simple but fast hashing algorithm. - */ -int tokenHash(const char* str); - -#endif \ No newline at end of file diff --git a/src/utils/string.c b/src/utils/string.c new file mode 100644 index 0000000..2f29174 --- /dev/null +++ b/src/utils/string.c @@ -0,0 +1,23 @@ +/** + * String related utilities. + */ + +/** + * Adds a char array (string) into another one. + * @param output the output string. + * @param input the input string. + * @param index the starting index. + * @return the last index. + */ +int fast_strcat(char* output, char* input, int index) { + char c; + while(c = *input++) { + output[index] = c; + + if(c == '\0') return index; + + index++; + } + + return index; +} \ No newline at end of file diff --git a/src/utils/string.h b/src/utils/string.h new file mode 100644 index 0000000..0c39e29 --- /dev/null +++ b/src/utils/string.h @@ -0,0 +1,17 @@ +/** + * String related utilities. + */ + +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +/** + * Adds a char array (string) into another one. + * @param output the output string. + * @param input the input string. + * @param index the starting index. + * @return the last index. + */ +int fast_strcat(char* output, char* input, int index); + +#endif \ No newline at end of file