Compare commits

...

4 Commits

Author SHA1 Message Date
823223ffa7 cstr -> str where possible 2025-02-02 19:18:01 +05:00
8a38813ba5 StringBuilder_alloc 2025-02-02 19:16:29 +05:00
7c2809aae2 StringBuilder_removeFromEnd 2025-02-02 17:59:50 +05:00
9e9b43afb4 str_seek 2025-02-02 17:59:30 +05:00
20 changed files with 220 additions and 233 deletions

View File

@ -1,5 +1,6 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
typedef union Register {
u32 u32v;

View File

@ -1,5 +1,4 @@
#include "List.h"
List_define(cstr);
List_define(u32);
List_define(u8);

View File

@ -54,6 +54,5 @@
}\
List_declare(cstr);
List_declare(u32);
List_declare(u8);

View File

@ -5,30 +5,30 @@ List_define(Operation);
List_define(DataDefinition);
List_define(Section);
static cstr _ArgumentType_str[] = {
"Unset",
"Register",
"ConstValue",
"DataName",
"NamedDataPointer",
"NamedDataSize",
static str _ArgumentType_str[] = {
STR("Unset"),
STR("Register"),
STR("ConstValue"),
STR("DataName"),
STR("NamedDataPointer"),
STR("NamedDataSize"),
};
cstr ArgumentType_toString(ArgumentType t){
str ArgumentType_toString(ArgumentType t){
if(t >= ARRAY_SIZE(_ArgumentType_str))
return "!!INDEX_ERROR!!";
return STR("!!INDEX_ERROR!!");
return _ArgumentType_str[t];
}
void Section_init(Section* sec, char* name){
void Section_init(Section* sec, str name){
sec->name = name;
sec->data = List_DataDefinition_alloc(256);
sec->code = List_Operation_alloc(1024);
}
void Section_free(Section* sec){
free(sec->name);
free(sec->name.data);
free(sec->data.data);
free(sec->code.data);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../instructions/instructions.h"
#include "../collections/List.h"
@ -12,7 +13,7 @@ typedef enum ArgumentType {
ArgumentType_NamedDataSize,
} ArgumentType;
cstr ArgumentType_toString(ArgumentType t);
str ArgumentType_toString(ArgumentType t);
typedef struct Argument {
@ -32,7 +33,7 @@ List_declare(Operation);
typedef struct DataDefinition {
cstr name;
str name;
List_u8 data;
u32 element_size;
} DataDefinition;
@ -41,14 +42,14 @@ List_declare(DataDefinition);
typedef struct Section {
char* name;
str name;
List_DataDefinition data;
List_Operation code;
} Section;
List_declare(Section);
void Section_init(Section* Section, char* name);
void Section_init(Section* Section, str name);
void Section_free(Section* Section);
typedef struct AST {

View File

@ -1,6 +1,5 @@
#include "Compiler_internal.h"
void Compiler_init(Compiler* cmp){
memset(cmp, 0, sizeof(Compiler));
cmp->state = CompilerState_Initial;
@ -10,7 +9,7 @@ void Compiler_init(Compiler* cmp){
}
void Compiler_free(Compiler* cmp){
free(cmp->code);
free(cmp->code.data);
free(cmp->tokens.data);
free(cmp->line_lengths.data);
AST_free(&cmp->ast);
@ -18,7 +17,7 @@ void Compiler_free(Compiler* cmp){
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
u32 prev_lines_len = 0;
if(pos >= cmp->code_len)
if(pos >= cmp->code.len)
return CodePos_create(0, 0);
for(u32 i = 0; i < cmp->line_lengths.len; i++){
@ -33,8 +32,8 @@ CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
// happens at the end of file
if(cmp->pos >= cmp->code_len)
cmp->pos = cmp->code_len - 1;
if(cmp->pos >= cmp->code.len)
cmp->pos = cmp->code.len - 1;
char position_str[32];
CodePos code_pos = Compiler_getLineAndColumn(cmp, cmp->pos);
sprintf(position_str, "[at %u:%u][", code_pos.line, code_pos.column);
@ -56,10 +55,8 @@ void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
Compiler_setError(cmp, FORMAT, ##__VA_ARGS__);\
}
char* Compiler_extractTokenStr(Compiler* cmp, Token t){
char* s = malloc(t.length + 1);
memcpy(s, cmp->code, t.length);
s[t.length] = 0;
str Compiler_constructTokenStr(Compiler* cmp, Token t){
str s = str_construct((char*)(cmp->code.data + t.begin), t.length, false);
return s;
}
@ -75,37 +72,34 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
if(f == NULL)
returnError("ERROR: can't open file '%s'", source_file_name);
List_u8 buf = List_u8_alloc(64 * 1024);
StringBuilder sb = StringBuilder_alloc(64 * 1024);
int ret;
while((ret = fgetc(f)) != EOF) {
List_u8_push(&buf, ret);
StringBuilder_append_char(&sb, ret);
}
if(ferror(f)){
free(buf.data);
StringBuilder_free(&sb);
fclose(f);
returnError("can't read file '%s'", source_file_name);
}
fclose(f);
if(buf.len == 0){
free(buf.data);
fclose(f);
if(sb.buffer.len == 0){
StringBuilder_free(&sb);
returnError("soucre file is empty");
}
cmp->code = (char*)buf.data;
cmp->code_len = buf.len;
List_u8_push(&buf, 0);
cmp->code = str_copy(StringBuilder_getStr(&sb));
StringBuilder_free(&sb);
f = fopen(out_file_name, "wb");
if(f == NULL){
free(buf.data);
returnError("ERROR: can't open file '%s'", out_file_name);
}
if(debug_log){
printf("----------------------------------[%s]---------------------------------\n", source_file_name);
fputs(cmp->code, stdout);
fputs(cmp->code.data, stdout);
fputc('\n', stdout);
}
@ -120,11 +114,11 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
Token t = cmp->tokens.data[i];
CodePos pos = Compiler_getLineAndColumn(cmp, t.begin);
char* tokstr = malloc(4096);
strncpy(tokstr, cmp->code + t.begin, t.length);
strncpy(tokstr, cmp->code.data + t.begin, t.length);
tokstr[t.length] = 0;
printf("[l:%3u, c:%3u] %s '%s'\n",
pos.line, pos.column,
TokenType_toString(t.type), tokstr);
pos.line, pos.column,
TokenType_toString(t.type).data, tokstr);
free(tokstr);
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../collections/List.h"
#include "Token.h"
#include "AST.h"
@ -14,8 +15,7 @@ typedef enum CompilerState {
} CompilerState;
typedef struct Compiler {
char* code;
u32 code_len;
str code;
u32 column; // > 0 if code parsing started
u32 pos;
CompilerState state;

View File

@ -1,4 +1,5 @@
#include "Compiler.h"
#include "../string/StringBuilder.h"
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...) __attribute__((__format__(__printf__, 3, 4)));
@ -23,7 +24,7 @@ typedef struct CodePos {
/// @param pos index in code buffer
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos);
char* Compiler_extractTokenStr(Compiler* cmp, Token t);
str Compiler_constructTokenStr(Compiler* cmp, Token t);
bool Compiler_lex(Compiler* cmp);
bool Compiler_parse(Compiler* cmp);

View File

@ -19,8 +19,8 @@ static void readCommentSingleLine(Compiler* cmp){
cmp->column++;
cmp->pos++;
while(cmp->pos < cmp->code_len){
c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
c = cmp->code.data[cmp->pos];
// end of line
if(c == '\r' || c == '\n'){
tok.length = cmp->pos - tok.begin;
@ -44,10 +44,10 @@ static void readCommentMultiLine(Compiler* cmp){
cmp->column++;
cmp->pos++;
while(cmp->pos < cmp->code_len){
c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
c = cmp->code.data[cmp->pos];
// closing comment
if(cmp->pos > tok.begin + 3 && c == '/' && cmp->code[cmp->pos - 1] == '*') {
if(cmp->pos > tok.begin + 3 && c == '/' && cmp->code.data[cmp->pos - 1] == '*') {
tok.length = cmp->pos - tok.begin + 1;
List_Token_push(&cmp->tokens, tok);
return;
@ -65,14 +65,14 @@ static void readCommentMultiLine(Compiler* cmp){
static void readComment(Compiler* cmp){
char c; // '/'
if(cmp->pos + 1 == cmp->code_len){
if(cmp->pos + 1 == cmp->code.len){
setError(Error_endOfFile);
return;
}
c = cmp->code[cmp->pos + 1];
c = cmp->code.data[cmp->pos + 1];
if(c == '\r' || c == '\n'){
setError(Error_unexpectedCharacter(cmp->code[--cmp->pos]));
setError(Error_unexpectedCharacter(cmp->code.data[--cmp->pos]));
return;
}
@ -91,14 +91,14 @@ static void readLabel(Compiler* cmp){
cmp->column++;
Token tok = Token_construct(TokenType_Label, cmp->pos, 0);
while(cmp->pos < cmp->code_len){
c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
c = cmp->code.data[cmp->pos];
// end of line
if(c == ':' || c == '\r' || c == '\n'){
tok.length = cmp->pos - tok.begin;
if(tok.length > 0)
List_Token_push(&cmp->tokens, tok);
else setError(Error_unexpectedCharacter(cmp->code[--cmp->pos]));
else setError(Error_unexpectedCharacter(cmp->code.data[--cmp->pos]));
// cmp->line will be increased in lex()
return;
}
@ -125,12 +125,12 @@ static void readArguments(Compiler* cmp){
Token tok = Token_construct(TokenType_Unset, cmp->pos, 0);
char quot = '\0'; // quotation character of a string value
while(cmp->pos < cmp->code_len){
c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
c = cmp->code.data[cmp->pos];
// string argument reading
if(quot != '\0'){
if(c == quot && cmp->code[cmp->pos - 1] != '\\'){
if(c == quot && cmp->code.data[cmp->pos - 1] != '\\'){
quot = '\0';
}
else if(c == '\r' || c == '\n'){
@ -189,8 +189,8 @@ static void readInstruction(Compiler* cmp){
cmp->pos++;
cmp->column++;
while(cmp->pos < cmp->code_len){
char c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
char c = cmp->code.data[cmp->pos];
// end of line
if(c == '\r' || c == '\n' || c == ';'){
tok.length = cmp->pos - tok.begin;
@ -232,8 +232,8 @@ bool Compiler_lex(Compiler* cmp){
cmp->state = CompilerState_Lexing;
cmp->column = 1;
while(cmp->pos < cmp->code_len){
char c = cmp->code[cmp->pos];
while(cmp->pos < cmp->code.len){
char c = cmp->code.data[cmp->pos];
switch(c){
// skip blank characters
case ' ': case '\t': case '\r': case '\n':
@ -257,7 +257,7 @@ bool Compiler_lex(Compiler* cmp){
if(cmp->state == CompilerState_Error)
return false;
c = cmp->code[cmp->pos];
c = cmp->code.data[cmp->pos];
if(c == '\n')
completeLine(cmp);
cmp->column++;

View File

@ -6,15 +6,15 @@
}
#define setError_unexpectedToken(T) {\
char* tok_str = Compiler_extractTokenStr(cmp, T);\
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
cmp->pos = T.begin;\
Compiler_setError(cmp, "unexpected token '%s'", tok_str);\
free(tok_str);\
Compiler_setError(cmp, "unexpected token '%s'", tok_str.data);\
free(tok_str.data);\
}
#define setError_unexpectedTokenChar(T, I) {\
cmp->pos = T.begin + I;\
Compiler_setError(cmp, "unexpected token '%c'", cmp->code[cmp->pos]);\
Compiler_setError(cmp, "unexpected token '%c'", cmp->code.data[cmp->pos]);\
}
@ -30,62 +30,63 @@ static void List_u8_pushBytes(List_u8* l, void* value, u32 startIndex, u32 count
static inline bool isVarSizeBits(u32 B) { return (B == 8 && B == 16 && B == 32 && B == 64); }
static NULLABLE(u8*) resolveEscapeSequences(Compiler* cmp, cstr src){
u32 len = strlen(src);
List_u8 resolved = List_u8_alloc(len);
static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
StringBuilder sb = StringBuilder_alloc(src.len);
char c;
bool escaped = false;
for(u32 i = 0; i < len; i++){
c = src[i];
for(u32 i = 0; i < src.len; i++){
c = src.data[i];
if(c == '\\'){
escaped = !escaped;
continue;
}
if(!escaped){
List_u8_push(&resolved, c);
StringBuilder_append_char(&sb, c);
continue;
}
// escape codes
switch(c){
case '0':
List_u8_push(&resolved, '\0');
StringBuilder_append_char(&sb, '\0');
break;
case 'n':
List_u8_push(&resolved, '\n');
StringBuilder_append_char(&sb, '\n');
break;
case 'r':
List_u8_push(&resolved, '\r');
StringBuilder_append_char(&sb, '\r');
break;
case 't':
List_u8_push(&resolved, '\t');
StringBuilder_append_char(&sb, '\t');
break;
case 'e':
List_u8_push(&resolved, '\e');
StringBuilder_append_char(&sb, '\e');
break;
default:
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
free(resolved.data);
return NULL;
StringBuilder_free(&sb);
return str_null;
}
}
return resolved.data;
return StringBuilder_getStr(&sb);
}
static void parseDataDefinition(Compiler* cmp, char* instr_name, DataDefinition* ddf){
static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* ddf){
i32 _element_size_bits;
if(sscanf(instr_name, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
str _instr_name_zero_terminated = str_copy(instr_name);
if(sscanf(_instr_name_zero_terminated.data, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
free(_instr_name_zero_terminated.data);
setError(Error_BitSize);
return;
}
free(_instr_name_zero_terminated.data);
ddf->element_size = _element_size_bits / 8;
Token tok = cmp->tokens.data[++cmp->tok_i];
char* tok_str = Compiler_extractTokenStr(cmp, tok);
u8* processed_str = NULL;
u32 len = 0;
str tok_str = Compiler_constructTokenStr(cmp, tok);
str processed_str = str_null;
ddf->name = tok_str;
while(++cmp->tok_i < cmp->tokens.len){
@ -98,37 +99,38 @@ static void parseDataDefinition(Compiler* cmp, char* instr_name, DataDefinition*
// skip comments
break;
case TokenType_Number:
tok_str = Compiler_extractTokenStr(cmp, tok);
if(cstr_seekChar(tok_str, '.', 0, -1) != -1){
f64 f = atof(tok_str);
tok_str = Compiler_constructTokenStr(cmp, tok);
processed_str = str_copy(tok_str);
if(str_seekChar(tok_str, '.', 0) != -1){
f64 f = atof(tok_str.data);
List_u8_pushBytes(&ddf->data, &f, 8 - ddf->element_size, ddf->element_size);
}
else {
i64 i = atoll(tok_str);
i64 i = atoll(tok_str.data);
List_u8_pushBytes(&ddf->data, &i, 8 - ddf->element_size, ddf->element_size);
}
free(processed_str.data);
break;
case TokenType_Char:
tok.begin += 1;
tok.length -= 2;
tok_str = Compiler_extractTokenStr(cmp, tok);
tok_str = Compiler_constructTokenStr(cmp, tok);
processed_str = resolveEscapeSequences(cmp, tok_str);
free(tok_str);
len = strlen((char*)processed_str);
if(len != ddf->element_size){
setError("can't fit char of size %i in %u bit variable", len, _element_size_bits);
if(processed_str.len != ddf->element_size){
setError("can't fit char of size %i in %u bit variable", processed_str.len, _element_size_bits);
return;
}
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
free(processed_str.data);
break;
case TokenType_String:
tok.begin += 1;
tok.length -= 2;
tok_str = Compiler_extractTokenStr(cmp, tok);
tok_str = Compiler_constructTokenStr(cmp, tok);
processed_str = resolveEscapeSequences(cmp, tok_str);
free(tok_str);
len = strlen((char*)processed_str);
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
free(processed_str.data);
break;
case TokenType_OperationEnd:
return;
@ -140,7 +142,7 @@ static void parseDataDefinition(Compiler* cmp, char* instr_name, DataDefinition*
}
static void parseOperation(Compiler* cmp, char* instr_name, Operation* operPtr){
static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
}
@ -162,14 +164,14 @@ bool Compiler_parse(Compiler* cmp){
case TokenType_Label:
// create new section
sec = List_Section_expand(&cmp->ast.sections, 1);
Section_init(sec, Compiler_extractTokenStr(cmp, tok));
Section_init(sec, Compiler_constructTokenStr(cmp, tok));
break;
case TokenType_Instruction:
if(sec == NULL)
returnError("no section");
char* instr_name = Compiler_extractTokenStr(cmp, tok);
str instr_name = Compiler_constructTokenStr(cmp, tok);
// data definition starts with const
if(cstr_seek(instr_name, "const", 0, 1)){
if(str_startsWith(instr_name, STR("const"))){
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data, 1);
parseDataDefinition(cmp, instr_name, dataDefPtr);
}

View File

@ -2,22 +2,22 @@
List_define(Token);
static cstr _TokenType_str[] = {
"Unset",
"SingleLineComment",
"MultiLineComment",
"Instruction",
"Label",
"Number",
"Char",
"String",
"Name",
"NamedDataPointer",
"NamedDataSize"
static str _TokenType_str[] = {
STR("Unset"),
STR("SingleLineComment"),
STR("MultiLineComment"),
STR("Instruction"),
STR("Label"),
STR("Number"),
STR("Char"),
STR("String"),
STR("Name"),
STR("NamedDataPointer"),
STR("NamedDataSize")
};
cstr TokenType_toString(TokenType t){
str TokenType_toString(TokenType t){
if(t >= ARRAY_SIZE(_TokenType_str))
return "!!INDEX_ERROR!!";
return STR("!!INDEX_ERROR!!");
return _TokenType_str[t];
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../collections/List.h"
typedef enum TokenType {
@ -17,7 +18,7 @@ typedef enum TokenType {
TokenType_OperationEnd, // EOL or EOF or ;
} TokenType;
cstr TokenType_toString(TokenType t);
str TokenType_toString(TokenType t);
typedef struct Token {
u32 begin; // some index in Compiler->code

View File

@ -50,71 +50,3 @@ char* NULLABLE(vsprintf_malloc)(size_t buffer_size, cstr format, va_list argv){
}
return buf;
}
i32 cstr_seek(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
char sc = *src, fc = *fragment;
if(sc == 0 || fc == 0)
return -1;
u32 fr_start = startIndex;
for(u32 si = startIndex; si-startIndex < seekLength && sc != 0; si++){
sc = src[si];
fc = fragment[si-fr_start];
if(fc == 0)
return fr_start;
if(sc != fc)
fr_start++;
}
return -1;
}
i32 cstr_seekReverse(const char* src, const char* fragment, u32 startIndex, u32 seekLength){
char sc = *src, fc = *fragment;
if(sc == 0 || fc == 0)
return -1;
i32 len = strlen(src);
if(startIndex == (u32)-1)
startIndex = len-1;
u32 fr_len = strlen(fragment);
for(u32 si = startIndex; si < (u32)-1 && si != (len - seekLength - 1); si--){
if(si + 1 < fr_len)
return -1;
sc = src[si];
fc = fragment[0];
u32 fr_start = si;
for(u32 fi = 0; fc == sc ; fi++){
if(fi == fr_len)
return fr_start;
fc = fragment[fi];
sc = src[si--];
}
}
return -1;
}
i32 cstr_seekChar(const char* src, char fragment, u32 startIndex, u32 seekLength){
char sc=*src;
if(sc==0 || fragment==0)
return -1;
for(u32 si=startIndex; si-startIndex<seekLength && sc!=0; si++){
sc=src[si];
if(sc==fragment)
return si;
}
return -1;
}
i32 cstr_seekCharReverse(const char* src, char fragment, u32 startIndex, u32 seekLength){
char sc=*src;
if(sc==0 || fragment==0)
return -1;
i32 len=strlen(src);
if(startIndex==(u32)-1)
startIndex=len-1;
for(u32 si=startIndex; si<(u32)-1 && si!=len-1-seekLength; si--){
sc=src[si];
if(sc==fragment)
return si;
}
return -1;
}

View File

@ -19,13 +19,13 @@ typedef enum __attribute__((__packed__)) Opcode {
} Opcode;
typedef struct Instruction {
cstr name;
str name;
InstructionImplFunc_t implementation;
Opcode opcode;
} Instruction;
#define Instruction_construct(NAME) {\
.name = #NAME, \
.name = STR(#NAME), \
.implementation = NAME##_impl, \
.opcode = Opcode_##NAME\
}

View File

@ -38,7 +38,7 @@ i32 main(const i32 argc, cstr* argv){
for(u8 opcode = 0; opcode < 255; opcode++){
const Instruction* instr = Instruction_getByOpcode(opcode);
if(instr != NULL){
printf("%02X %s\n", opcode, instr->name);
printf("%02X %s\n", opcode, instr->name.data);
}
}
return 0;

View File

@ -58,23 +58,3 @@ char* NULLABLE(vsprintf_malloc)(size_t buffer_size, cstr format, va_list argv);
static inline bool isAlphabeticalLower(char c) { return 'a' <= c && c <= 'z'; }
static inline bool isAlphabeticalUpper(char c) { return 'A' <= c && c <= 'Z'; }
static inline bool isDigit(char c) { return '0' <= c && c <= '9'; }
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cstr_seek(const char* src, const char* fragment, u32 startIndex, u32 seekLength);
/// @param startIndex -1 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cstr_seekReverse(const char* src, const char* fragment, u32 startIndex, u32 seekLength);
/// @param startIndex 0 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cstr_seekChar(const char* src, char fragment, u32 startIndex, u32 seekLength);
/// @param startIndex -1 ... src length
/// @param seekLength 0 ... -1
/// @return pos of first <fragment> inclusion in <src> or -1 if not found
i32 cstr_seekCharReverse(const char* src, char fragment, u32 startIndex, u32 seekLength);

View File

@ -2,14 +2,24 @@
void StringBuilder_free(StringBuilder* b){
free(b->buffer.data);
b->buffer = List_u8_construct(NULL, 0, 0);
}
str StringBuilder_build(StringBuilder* b){
str StringBuilder_getStr(StringBuilder* b){
List_u8_push(&b->buffer, '\0');
str result = str_construct((char*)b->buffer.data, b->buffer.len - 1, true);
return result;
}
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count){
if(count < b->buffer.len){
b->buffer.len -= count;
}
else{
b->buffer.len = 0;
}
}
void StringBuilder_append_char(StringBuilder* b, char c){
List_u8_push(&b->buffer, c);

View File

@ -1,9 +1,5 @@
#pragma once
#if __cplusplus
extern "C" {
#endif
#include "../collections/List.h"
#include "str.h"
@ -11,11 +7,12 @@ typedef struct StringBuilder {
List_u8 buffer;
} StringBuilder;
static inline StringBuilder StringBuilder_construct(u32 initial_size) {
static inline StringBuilder StringBuilder_alloc(u32 initial_size) {
return (StringBuilder){ .buffer = List_u8_alloc(initial_size) };
}
void StringBuilder_free(StringBuilder* b);
/// @param count set to -1 to clear StringBuilder
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count);
void StringBuilder_append_char(StringBuilder* b, char c);
void StringBuilder_append_cstr(StringBuilder* b, char* s);
@ -26,7 +23,3 @@ void StringBuilder_append_f64(StringBuilder* b, f64 a);
// adds '\0' to the buffer and returns pointer to buffer content
str StringBuilder_getStr(StringBuilder* b);
#if __cplusplus
}
#endif

View File

@ -3,27 +3,97 @@
str str_copy(str src){
if(src.data == NULL || src.len == 0)
return src;
str nstr = str_construct((char*)malloc(src.len + 1), src.len, true);
memcpy(nstr.data, src.data, src.len);
nstr.data[nstr.len] = '\0';
return nstr;
}
bool str_compare(str str0, str str1){
if(str0.len!= str1.len) return false;
if(!str0.data) return str1.data ? false : true;
else if(!str1.data) return false;
while(str0.len-- > 0)
if(*str0.data++ != *str1.data++ )
bool str_equals(str s0, str s1){
if(s0.len != s1.len)
return false;
for(u32 i = 0; i < s0.len; i++)
if(s0.data[i] != s1.data[i])
return false;
return true;
}
str str_reverse(str s){
if(s.data == NULL || s.len == 0)
return s;
str r = str_construct(malloc(s.len), s.len, s.isZeroTerminated);
for(u32 i = 0; i < s.len; i++ )
r.data[i] = s.data[s.len - i - 1];
return r;
}
i32 str_seek(str src, str fragment, u32 startIndex){
if(src.len == 0 || fragment.len == 0)
return -1;
for(u32 i = startIndex; i < src.len - fragment.len + 1; i++){
for(u32 j = 0;; j++){
if(j == fragment.len)
return i;
if(src.data[i + j] != fragment.data[j])
break;
}
}
return -1;
}
i32 str_seekReverse(str src, str fragment, u32 startIndex){
if(src.len == 0 || fragment.len == 0)
return -1;
if(startIndex > src.len - 1)
startIndex = src.len - 1;
for(u32 i = startIndex; i >= fragment.len - 1; i--){
for(u32 j = 0;; j++){
if(j == fragment.len)
return i - j + 1;
if(src.data[i - j] != fragment.data[fragment.len - 1 - j])
break;
}
}
return -1;
}
i32 str_seekChar(str src, char c, u32 startIndex){
for(u32 i = startIndex; i < src.len; i++){
if(src.data[i] == c)
return i;
}
return -1;
}
i32 str_seekCharReverse(str src, char c, u32 startIndex){
if(startIndex > src.len - 1)
startIndex = src.len - 1;
for(u32 i = startIndex; i != (u32)-1; i--){
if(src.data[i] == c)
return i;
}
return -1;
}
bool str_startsWith(str src, str fragment){
if(src.len < fragment.len)
return false;
src.len = fragment.len;
return str_equals(src, fragment);
}
bool str_endsWith(str src, str fragment){
if(src.len < fragment.len)
return false;
src.data = (char*)(src.data + src.len - fragment.len);
src.len = fragment.len;
return str_equals(src, fragment);
}

View File

@ -8,23 +8,27 @@ typedef struct str {
bool isZeroTerminated;
} str;
// creates str from a string literal
#define STR(LITERAL) str_construct(LITERAL, ARRAY_SIZE(LITERAL) - 1, true)
#define str_construct(DATA, LEN, ZERO_TERMINATED) ((str){ .data = DATA, .len = LEN, .isZeroTerminated = ZERO_TERMINATED })
static const str str_null = str_construct(NULL, 0, 0);
/// copies str content to new char pointer value (adding '\0' at the end)
char* str_extractcstr(str str);
/// copies src content to new string and adds \0 at the end
str str_copy(str src);
/// compares two strings, NullPtr-friendly
bool str_compare(str str0, str str1);
bool str_equals(str str0, str str1);
/// allocates new string which is reversed variant of <s>
str str_reverse(str s);
#if __cplusplus
}
#endif
i32 str_seek(str src, str fragment, u32 startIndex);
i32 str_seekReverse(str src, str fragment, u32 startIndex);
i32 str_seekChar(str src, char c, u32 startIndex);
i32 str_seekCharReverse(str src, char c, u32 startIndex);
bool str_startsWith(str src, str fragment);
bool str_endsWith(str src, str fragment);