Compare commits
No commits in common. "823223ffa7f820ad24b5972a5067a91bcfc91749" and "2831474f79086772120927f1b54528555c4af380" have entirely different histories.
823223ffa7
...
2831474f79
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
#include "../string/str.h"
|
|
||||||
|
|
||||||
typedef union Register {
|
typedef union Register {
|
||||||
u32 u32v;
|
u32 u32v;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "List.h"
|
#include "List.h"
|
||||||
|
|
||||||
|
List_define(cstr);
|
||||||
List_define(u32);
|
List_define(u32);
|
||||||
List_define(u8);
|
List_define(u8);
|
||||||
|
|||||||
@ -54,5 +54,6 @@
|
|||||||
}\
|
}\
|
||||||
|
|
||||||
|
|
||||||
|
List_declare(cstr);
|
||||||
List_declare(u32);
|
List_declare(u32);
|
||||||
List_declare(u8);
|
List_declare(u8);
|
||||||
|
|||||||
@ -5,30 +5,30 @@ List_define(Operation);
|
|||||||
List_define(DataDefinition);
|
List_define(DataDefinition);
|
||||||
List_define(Section);
|
List_define(Section);
|
||||||
|
|
||||||
static str _ArgumentType_str[] = {
|
static cstr _ArgumentType_str[] = {
|
||||||
STR("Unset"),
|
"Unset",
|
||||||
STR("Register"),
|
"Register",
|
||||||
STR("ConstValue"),
|
"ConstValue",
|
||||||
STR("DataName"),
|
"DataName",
|
||||||
STR("NamedDataPointer"),
|
"NamedDataPointer",
|
||||||
STR("NamedDataSize"),
|
"NamedDataSize",
|
||||||
};
|
};
|
||||||
|
|
||||||
str ArgumentType_toString(ArgumentType t){
|
cstr ArgumentType_toString(ArgumentType t){
|
||||||
if(t >= ARRAY_SIZE(_ArgumentType_str))
|
if(t >= ARRAY_SIZE(_ArgumentType_str))
|
||||||
return STR("!!INDEX_ERROR!!");
|
return "!!INDEX_ERROR!!";
|
||||||
return _ArgumentType_str[t];
|
return _ArgumentType_str[t];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Section_init(Section* sec, str name){
|
void Section_init(Section* sec, char* name){
|
||||||
sec->name = name;
|
sec->name = name;
|
||||||
sec->data = List_DataDefinition_alloc(256);
|
sec->data = List_DataDefinition_alloc(256);
|
||||||
sec->code = List_Operation_alloc(1024);
|
sec->code = List_Operation_alloc(1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Section_free(Section* sec){
|
void Section_free(Section* sec){
|
||||||
free(sec->name.data);
|
free(sec->name);
|
||||||
free(sec->data.data);
|
free(sec->data.data);
|
||||||
free(sec->code.data);
|
free(sec->code.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
#include "../string/str.h"
|
|
||||||
#include "../instructions/instructions.h"
|
#include "../instructions/instructions.h"
|
||||||
#include "../collections/List.h"
|
#include "../collections/List.h"
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ typedef enum ArgumentType {
|
|||||||
ArgumentType_NamedDataSize,
|
ArgumentType_NamedDataSize,
|
||||||
} ArgumentType;
|
} ArgumentType;
|
||||||
|
|
||||||
str ArgumentType_toString(ArgumentType t);
|
cstr ArgumentType_toString(ArgumentType t);
|
||||||
|
|
||||||
|
|
||||||
typedef struct Argument {
|
typedef struct Argument {
|
||||||
@ -33,7 +32,7 @@ List_declare(Operation);
|
|||||||
|
|
||||||
|
|
||||||
typedef struct DataDefinition {
|
typedef struct DataDefinition {
|
||||||
str name;
|
cstr name;
|
||||||
List_u8 data;
|
List_u8 data;
|
||||||
u32 element_size;
|
u32 element_size;
|
||||||
} DataDefinition;
|
} DataDefinition;
|
||||||
@ -42,14 +41,14 @@ List_declare(DataDefinition);
|
|||||||
|
|
||||||
|
|
||||||
typedef struct Section {
|
typedef struct Section {
|
||||||
str name;
|
char* name;
|
||||||
List_DataDefinition data;
|
List_DataDefinition data;
|
||||||
List_Operation code;
|
List_Operation code;
|
||||||
} Section;
|
} Section;
|
||||||
|
|
||||||
List_declare(Section);
|
List_declare(Section);
|
||||||
|
|
||||||
void Section_init(Section* Section, str name);
|
void Section_init(Section* Section, char* name);
|
||||||
void Section_free(Section* Section);
|
void Section_free(Section* Section);
|
||||||
|
|
||||||
typedef struct AST {
|
typedef struct AST {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "Compiler_internal.h"
|
#include "Compiler_internal.h"
|
||||||
|
|
||||||
|
|
||||||
void Compiler_init(Compiler* cmp){
|
void Compiler_init(Compiler* cmp){
|
||||||
memset(cmp, 0, sizeof(Compiler));
|
memset(cmp, 0, sizeof(Compiler));
|
||||||
cmp->state = CompilerState_Initial;
|
cmp->state = CompilerState_Initial;
|
||||||
@ -9,7 +10,7 @@ void Compiler_init(Compiler* cmp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Compiler_free(Compiler* cmp){
|
void Compiler_free(Compiler* cmp){
|
||||||
free(cmp->code.data);
|
free(cmp->code);
|
||||||
free(cmp->tokens.data);
|
free(cmp->tokens.data);
|
||||||
free(cmp->line_lengths.data);
|
free(cmp->line_lengths.data);
|
||||||
AST_free(&cmp->ast);
|
AST_free(&cmp->ast);
|
||||||
@ -17,7 +18,7 @@ void Compiler_free(Compiler* cmp){
|
|||||||
|
|
||||||
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
|
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
|
||||||
u32 prev_lines_len = 0;
|
u32 prev_lines_len = 0;
|
||||||
if(pos >= cmp->code.len)
|
if(pos >= cmp->code_len)
|
||||||
return CodePos_create(0, 0);
|
return CodePos_create(0, 0);
|
||||||
|
|
||||||
for(u32 i = 0; i < cmp->line_lengths.len; i++){
|
for(u32 i = 0; i < cmp->line_lengths.len; i++){
|
||||||
@ -32,8 +33,8 @@ CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
|
|||||||
|
|
||||||
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
|
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
|
||||||
// happens at the end of file
|
// happens at the end of file
|
||||||
if(cmp->pos >= cmp->code.len)
|
if(cmp->pos >= cmp->code_len)
|
||||||
cmp->pos = cmp->code.len - 1;
|
cmp->pos = cmp->code_len - 1;
|
||||||
char position_str[32];
|
char position_str[32];
|
||||||
CodePos code_pos = Compiler_getLineAndColumn(cmp, cmp->pos);
|
CodePos code_pos = Compiler_getLineAndColumn(cmp, cmp->pos);
|
||||||
sprintf(position_str, "[at %u:%u][", code_pos.line, code_pos.column);
|
sprintf(position_str, "[at %u:%u][", code_pos.line, code_pos.column);
|
||||||
@ -55,8 +56,10 @@ void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
|
|||||||
Compiler_setError(cmp, FORMAT, ##__VA_ARGS__);\
|
Compiler_setError(cmp, FORMAT, ##__VA_ARGS__);\
|
||||||
}
|
}
|
||||||
|
|
||||||
str Compiler_constructTokenStr(Compiler* cmp, Token t){
|
char* Compiler_extractTokenStr(Compiler* cmp, Token t){
|
||||||
str s = str_construct((char*)(cmp->code.data + t.begin), t.length, false);
|
char* s = malloc(t.length + 1);
|
||||||
|
memcpy(s, cmp->code, t.length);
|
||||||
|
s[t.length] = 0;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,34 +75,37 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
if(f == NULL)
|
if(f == NULL)
|
||||||
returnError("ERROR: can't open file '%s'", source_file_name);
|
returnError("ERROR: can't open file '%s'", source_file_name);
|
||||||
|
|
||||||
StringBuilder sb = StringBuilder_alloc(64 * 1024);
|
List_u8 buf = List_u8_alloc(64 * 1024);
|
||||||
int ret;
|
int ret;
|
||||||
while((ret = fgetc(f)) != EOF) {
|
while((ret = fgetc(f)) != EOF) {
|
||||||
StringBuilder_append_char(&sb, ret);
|
List_u8_push(&buf, ret);
|
||||||
}
|
}
|
||||||
if(ferror(f)){
|
if(ferror(f)){
|
||||||
StringBuilder_free(&sb);
|
free(buf.data);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
returnError("can't read file '%s'", source_file_name);
|
returnError("can't read file '%s'", source_file_name);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if(sb.buffer.len == 0){
|
if(buf.len == 0){
|
||||||
StringBuilder_free(&sb);
|
free(buf.data);
|
||||||
|
fclose(f);
|
||||||
returnError("soucre file is empty");
|
returnError("soucre file is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp->code = str_copy(StringBuilder_getStr(&sb));
|
cmp->code = (char*)buf.data;
|
||||||
StringBuilder_free(&sb);
|
cmp->code_len = buf.len;
|
||||||
|
List_u8_push(&buf, 0);
|
||||||
|
|
||||||
f = fopen(out_file_name, "wb");
|
f = fopen(out_file_name, "wb");
|
||||||
if(f == NULL){
|
if(f == NULL){
|
||||||
|
free(buf.data);
|
||||||
returnError("ERROR: can't open file '%s'", out_file_name);
|
returnError("ERROR: can't open file '%s'", out_file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(debug_log){
|
if(debug_log){
|
||||||
printf("----------------------------------[%s]---------------------------------\n", source_file_name);
|
printf("----------------------------------[%s]---------------------------------\n", source_file_name);
|
||||||
fputs(cmp->code.data, stdout);
|
fputs(cmp->code, stdout);
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +120,11 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
Token t = cmp->tokens.data[i];
|
Token t = cmp->tokens.data[i];
|
||||||
CodePos pos = Compiler_getLineAndColumn(cmp, t.begin);
|
CodePos pos = Compiler_getLineAndColumn(cmp, t.begin);
|
||||||
char* tokstr = malloc(4096);
|
char* tokstr = malloc(4096);
|
||||||
strncpy(tokstr, cmp->code.data + t.begin, t.length);
|
strncpy(tokstr, cmp->code + t.begin, t.length);
|
||||||
tokstr[t.length] = 0;
|
tokstr[t.length] = 0;
|
||||||
printf("[l:%3u, c:%3u] %s '%s'\n",
|
printf("[l:%3u, c:%3u] %s '%s'\n",
|
||||||
pos.line, pos.column,
|
pos.line, pos.column,
|
||||||
TokenType_toString(t.type).data, tokstr);
|
TokenType_toString(t.type), tokstr);
|
||||||
free(tokstr);
|
free(tokstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
#include "../string/str.h"
|
|
||||||
#include "../collections/List.h"
|
#include "../collections/List.h"
|
||||||
#include "Token.h"
|
#include "Token.h"
|
||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
@ -15,7 +14,8 @@ typedef enum CompilerState {
|
|||||||
} CompilerState;
|
} CompilerState;
|
||||||
|
|
||||||
typedef struct Compiler {
|
typedef struct Compiler {
|
||||||
str code;
|
char* code;
|
||||||
|
u32 code_len;
|
||||||
u32 column; // > 0 if code parsing started
|
u32 column; // > 0 if code parsing started
|
||||||
u32 pos;
|
u32 pos;
|
||||||
CompilerState state;
|
CompilerState state;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
#include "../string/StringBuilder.h"
|
|
||||||
|
|
||||||
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...) __attribute__((__format__(__printf__, 3, 4)));
|
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...) __attribute__((__format__(__printf__, 3, 4)));
|
||||||
|
|
||||||
@ -24,7 +23,7 @@ typedef struct CodePos {
|
|||||||
/// @param pos index in code buffer
|
/// @param pos index in code buffer
|
||||||
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos);
|
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos);
|
||||||
|
|
||||||
str Compiler_constructTokenStr(Compiler* cmp, Token t);
|
char* Compiler_extractTokenStr(Compiler* cmp, Token t);
|
||||||
|
|
||||||
bool Compiler_lex(Compiler* cmp);
|
bool Compiler_lex(Compiler* cmp);
|
||||||
bool Compiler_parse(Compiler* cmp);
|
bool Compiler_parse(Compiler* cmp);
|
||||||
|
|||||||
@ -19,8 +19,8 @@ static void readCommentSingleLine(Compiler* cmp){
|
|||||||
cmp->column++;
|
cmp->column++;
|
||||||
cmp->pos++;
|
cmp->pos++;
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
c = cmp->code.data[cmp->pos];
|
c = cmp->code[cmp->pos];
|
||||||
// end of line
|
// end of line
|
||||||
if(c == '\r' || c == '\n'){
|
if(c == '\r' || c == '\n'){
|
||||||
tok.length = cmp->pos - tok.begin;
|
tok.length = cmp->pos - tok.begin;
|
||||||
@ -44,10 +44,10 @@ static void readCommentMultiLine(Compiler* cmp){
|
|||||||
cmp->column++;
|
cmp->column++;
|
||||||
cmp->pos++;
|
cmp->pos++;
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
c = cmp->code.data[cmp->pos];
|
c = cmp->code[cmp->pos];
|
||||||
// closing comment
|
// closing comment
|
||||||
if(cmp->pos > tok.begin + 3 && c == '/' && cmp->code.data[cmp->pos - 1] == '*') {
|
if(cmp->pos > tok.begin + 3 && c == '/' && cmp->code[cmp->pos - 1] == '*') {
|
||||||
tok.length = cmp->pos - tok.begin + 1;
|
tok.length = cmp->pos - tok.begin + 1;
|
||||||
List_Token_push(&cmp->tokens, tok);
|
List_Token_push(&cmp->tokens, tok);
|
||||||
return;
|
return;
|
||||||
@ -65,14 +65,14 @@ static void readCommentMultiLine(Compiler* cmp){
|
|||||||
|
|
||||||
static void readComment(Compiler* cmp){
|
static void readComment(Compiler* cmp){
|
||||||
char c; // '/'
|
char c; // '/'
|
||||||
if(cmp->pos + 1 == cmp->code.len){
|
if(cmp->pos + 1 == cmp->code_len){
|
||||||
setError(Error_endOfFile);
|
setError(Error_endOfFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = cmp->code.data[cmp->pos + 1];
|
c = cmp->code[cmp->pos + 1];
|
||||||
if(c == '\r' || c == '\n'){
|
if(c == '\r' || c == '\n'){
|
||||||
setError(Error_unexpectedCharacter(cmp->code.data[--cmp->pos]));
|
setError(Error_unexpectedCharacter(cmp->code[--cmp->pos]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +91,14 @@ static void readLabel(Compiler* cmp){
|
|||||||
cmp->column++;
|
cmp->column++;
|
||||||
Token tok = Token_construct(TokenType_Label, cmp->pos, 0);
|
Token tok = Token_construct(TokenType_Label, cmp->pos, 0);
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
c = cmp->code.data[cmp->pos];
|
c = cmp->code[cmp->pos];
|
||||||
// end of line
|
// end of line
|
||||||
if(c == ':' || c == '\r' || c == '\n'){
|
if(c == ':' || c == '\r' || c == '\n'){
|
||||||
tok.length = cmp->pos - tok.begin;
|
tok.length = cmp->pos - tok.begin;
|
||||||
if(tok.length > 0)
|
if(tok.length > 0)
|
||||||
List_Token_push(&cmp->tokens, tok);
|
List_Token_push(&cmp->tokens, tok);
|
||||||
else setError(Error_unexpectedCharacter(cmp->code.data[--cmp->pos]));
|
else setError(Error_unexpectedCharacter(cmp->code[--cmp->pos]));
|
||||||
// cmp->line will be increased in lex()
|
// cmp->line will be increased in lex()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -125,12 +125,12 @@ static void readArguments(Compiler* cmp){
|
|||||||
Token tok = Token_construct(TokenType_Unset, cmp->pos, 0);
|
Token tok = Token_construct(TokenType_Unset, cmp->pos, 0);
|
||||||
char quot = '\0'; // quotation character of a string value
|
char quot = '\0'; // quotation character of a string value
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
c = cmp->code.data[cmp->pos];
|
c = cmp->code[cmp->pos];
|
||||||
|
|
||||||
// string argument reading
|
// string argument reading
|
||||||
if(quot != '\0'){
|
if(quot != '\0'){
|
||||||
if(c == quot && cmp->code.data[cmp->pos - 1] != '\\'){
|
if(c == quot && cmp->code[cmp->pos - 1] != '\\'){
|
||||||
quot = '\0';
|
quot = '\0';
|
||||||
}
|
}
|
||||||
else if(c == '\r' || c == '\n'){
|
else if(c == '\r' || c == '\n'){
|
||||||
@ -189,8 +189,8 @@ static void readInstruction(Compiler* cmp){
|
|||||||
cmp->pos++;
|
cmp->pos++;
|
||||||
cmp->column++;
|
cmp->column++;
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
char c = cmp->code.data[cmp->pos];
|
char c = cmp->code[cmp->pos];
|
||||||
// end of line
|
// end of line
|
||||||
if(c == '\r' || c == '\n' || c == ';'){
|
if(c == '\r' || c == '\n' || c == ';'){
|
||||||
tok.length = cmp->pos - tok.begin;
|
tok.length = cmp->pos - tok.begin;
|
||||||
@ -232,8 +232,8 @@ bool Compiler_lex(Compiler* cmp){
|
|||||||
cmp->state = CompilerState_Lexing;
|
cmp->state = CompilerState_Lexing;
|
||||||
cmp->column = 1;
|
cmp->column = 1;
|
||||||
|
|
||||||
while(cmp->pos < cmp->code.len){
|
while(cmp->pos < cmp->code_len){
|
||||||
char c = cmp->code.data[cmp->pos];
|
char c = cmp->code[cmp->pos];
|
||||||
switch(c){
|
switch(c){
|
||||||
// skip blank characters
|
// skip blank characters
|
||||||
case ' ': case '\t': case '\r': case '\n':
|
case ' ': case '\t': case '\r': case '\n':
|
||||||
@ -257,7 +257,7 @@ bool Compiler_lex(Compiler* cmp){
|
|||||||
if(cmp->state == CompilerState_Error)
|
if(cmp->state == CompilerState_Error)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
c = cmp->code.data[cmp->pos];
|
c = cmp->code[cmp->pos];
|
||||||
if(c == '\n')
|
if(c == '\n')
|
||||||
completeLine(cmp);
|
completeLine(cmp);
|
||||||
cmp->column++;
|
cmp->column++;
|
||||||
|
|||||||
@ -6,15 +6,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define setError_unexpectedToken(T) {\
|
#define setError_unexpectedToken(T) {\
|
||||||
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
|
char* tok_str = Compiler_extractTokenStr(cmp, T);\
|
||||||
cmp->pos = T.begin;\
|
cmp->pos = T.begin;\
|
||||||
Compiler_setError(cmp, "unexpected token '%s'", tok_str.data);\
|
Compiler_setError(cmp, "unexpected token '%s'", tok_str);\
|
||||||
free(tok_str.data);\
|
free(tok_str);\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define setError_unexpectedTokenChar(T, I) {\
|
#define setError_unexpectedTokenChar(T, I) {\
|
||||||
cmp->pos = T.begin + I;\
|
cmp->pos = T.begin + I;\
|
||||||
Compiler_setError(cmp, "unexpected token '%c'", cmp->code.data[cmp->pos]);\
|
Compiler_setError(cmp, "unexpected token '%c'", cmp->code[cmp->pos]);\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -30,63 +30,62 @@ 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 inline bool isVarSizeBits(u32 B) { return (B == 8 && B == 16 && B == 32 && B == 64); }
|
||||||
|
|
||||||
static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
|
static NULLABLE(u8*) resolveEscapeSequences(Compiler* cmp, cstr src){
|
||||||
StringBuilder sb = StringBuilder_alloc(src.len);
|
u32 len = strlen(src);
|
||||||
|
List_u8 resolved = List_u8_alloc(len);
|
||||||
char c;
|
char c;
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
for(u32 i = 0; i < src.len; i++){
|
for(u32 i = 0; i < len; i++){
|
||||||
c = src.data[i];
|
c = src[i];
|
||||||
if(c == '\\'){
|
if(c == '\\'){
|
||||||
escaped = !escaped;
|
escaped = !escaped;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!escaped){
|
if(!escaped){
|
||||||
StringBuilder_append_char(&sb, c);
|
List_u8_push(&resolved, c);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// escape codes
|
// escape codes
|
||||||
switch(c){
|
switch(c){
|
||||||
case '0':
|
case '0':
|
||||||
StringBuilder_append_char(&sb, '\0');
|
List_u8_push(&resolved, '\0');
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
StringBuilder_append_char(&sb, '\n');
|
List_u8_push(&resolved, '\n');
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
StringBuilder_append_char(&sb, '\r');
|
List_u8_push(&resolved, '\r');
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
StringBuilder_append_char(&sb, '\t');
|
List_u8_push(&resolved, '\t');
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
StringBuilder_append_char(&sb, '\e');
|
List_u8_push(&resolved, '\e');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
|
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
|
||||||
StringBuilder_free(&sb);
|
free(resolved.data);
|
||||||
return str_null;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return StringBuilder_getStr(&sb);
|
return resolved.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* ddf){
|
static void parseDataDefinition(Compiler* cmp, char* instr_name, DataDefinition* ddf){
|
||||||
i32 _element_size_bits;
|
i32 _element_size_bits;
|
||||||
str _instr_name_zero_terminated = str_copy(instr_name);
|
if(sscanf(instr_name, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
|
||||||
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);
|
setError(Error_BitSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(_instr_name_zero_terminated.data);
|
|
||||||
ddf->element_size = _element_size_bits / 8;
|
ddf->element_size = _element_size_bits / 8;
|
||||||
|
|
||||||
Token tok = cmp->tokens.data[++cmp->tok_i];
|
Token tok = cmp->tokens.data[++cmp->tok_i];
|
||||||
str tok_str = Compiler_constructTokenStr(cmp, tok);
|
char* tok_str = Compiler_extractTokenStr(cmp, tok);
|
||||||
str processed_str = str_null;
|
u8* processed_str = NULL;
|
||||||
|
u32 len = 0;
|
||||||
ddf->name = tok_str;
|
ddf->name = tok_str;
|
||||||
|
|
||||||
while(++cmp->tok_i < cmp->tokens.len){
|
while(++cmp->tok_i < cmp->tokens.len){
|
||||||
@ -99,38 +98,37 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
|
|||||||
// skip comments
|
// skip comments
|
||||||
break;
|
break;
|
||||||
case TokenType_Number:
|
case TokenType_Number:
|
||||||
tok_str = Compiler_constructTokenStr(cmp, tok);
|
tok_str = Compiler_extractTokenStr(cmp, tok);
|
||||||
processed_str = str_copy(tok_str);
|
if(cstr_seekChar(tok_str, '.', 0, -1) != -1){
|
||||||
if(str_seekChar(tok_str, '.', 0) != -1){
|
f64 f = atof(tok_str);
|
||||||
f64 f = atof(tok_str.data);
|
|
||||||
List_u8_pushBytes(&ddf->data, &f, 8 - ddf->element_size, ddf->element_size);
|
List_u8_pushBytes(&ddf->data, &f, 8 - ddf->element_size, ddf->element_size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
i64 i = atoll(tok_str.data);
|
i64 i = atoll(tok_str);
|
||||||
List_u8_pushBytes(&ddf->data, &i, 8 - ddf->element_size, ddf->element_size);
|
List_u8_pushBytes(&ddf->data, &i, 8 - ddf->element_size, ddf->element_size);
|
||||||
}
|
}
|
||||||
free(processed_str.data);
|
|
||||||
break;
|
break;
|
||||||
case TokenType_Char:
|
case TokenType_Char:
|
||||||
tok.begin += 1;
|
tok.begin += 1;
|
||||||
tok.length -= 2;
|
tok.length -= 2;
|
||||||
tok_str = Compiler_constructTokenStr(cmp, tok);
|
tok_str = Compiler_extractTokenStr(cmp, tok);
|
||||||
processed_str = resolveEscapeSequences(cmp, tok_str);
|
processed_str = resolveEscapeSequences(cmp, tok_str);
|
||||||
|
free(tok_str);
|
||||||
if(processed_str.len != ddf->element_size){
|
len = strlen((char*)processed_str);
|
||||||
setError("can't fit char of size %i in %u bit variable", processed_str.len, _element_size_bits);
|
if(len != ddf->element_size){
|
||||||
|
setError("can't fit char of size %i in %u bit variable", len, _element_size_bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
|
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
|
||||||
free(processed_str.data);
|
|
||||||
break;
|
break;
|
||||||
case TokenType_String:
|
case TokenType_String:
|
||||||
tok.begin += 1;
|
tok.begin += 1;
|
||||||
tok.length -= 2;
|
tok.length -= 2;
|
||||||
tok_str = Compiler_constructTokenStr(cmp, tok);
|
tok_str = Compiler_extractTokenStr(cmp, tok);
|
||||||
processed_str = resolveEscapeSequences(cmp, tok_str);
|
processed_str = resolveEscapeSequences(cmp, tok_str);
|
||||||
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
|
free(tok_str);
|
||||||
free(processed_str.data);
|
len = strlen((char*)processed_str);
|
||||||
|
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
|
||||||
break;
|
break;
|
||||||
case TokenType_OperationEnd:
|
case TokenType_OperationEnd:
|
||||||
return;
|
return;
|
||||||
@ -142,7 +140,7 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
|
static void parseOperation(Compiler* cmp, char* instr_name, Operation* operPtr){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,14 +162,14 @@ bool Compiler_parse(Compiler* cmp){
|
|||||||
case TokenType_Label:
|
case TokenType_Label:
|
||||||
// create new section
|
// create new section
|
||||||
sec = List_Section_expand(&cmp->ast.sections, 1);
|
sec = List_Section_expand(&cmp->ast.sections, 1);
|
||||||
Section_init(sec, Compiler_constructTokenStr(cmp, tok));
|
Section_init(sec, Compiler_extractTokenStr(cmp, tok));
|
||||||
break;
|
break;
|
||||||
case TokenType_Instruction:
|
case TokenType_Instruction:
|
||||||
if(sec == NULL)
|
if(sec == NULL)
|
||||||
returnError("no section");
|
returnError("no section");
|
||||||
str instr_name = Compiler_constructTokenStr(cmp, tok);
|
char* instr_name = Compiler_extractTokenStr(cmp, tok);
|
||||||
// data definition starts with const
|
// data definition starts with const
|
||||||
if(str_startsWith(instr_name, STR("const"))){
|
if(cstr_seek(instr_name, "const", 0, 1)){
|
||||||
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data, 1);
|
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data, 1);
|
||||||
parseDataDefinition(cmp, instr_name, dataDefPtr);
|
parseDataDefinition(cmp, instr_name, dataDefPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,22 +2,22 @@
|
|||||||
|
|
||||||
List_define(Token);
|
List_define(Token);
|
||||||
|
|
||||||
static str _TokenType_str[] = {
|
static cstr _TokenType_str[] = {
|
||||||
STR("Unset"),
|
"Unset",
|
||||||
STR("SingleLineComment"),
|
"SingleLineComment",
|
||||||
STR("MultiLineComment"),
|
"MultiLineComment",
|
||||||
STR("Instruction"),
|
"Instruction",
|
||||||
STR("Label"),
|
"Label",
|
||||||
STR("Number"),
|
"Number",
|
||||||
STR("Char"),
|
"Char",
|
||||||
STR("String"),
|
"String",
|
||||||
STR("Name"),
|
"Name",
|
||||||
STR("NamedDataPointer"),
|
"NamedDataPointer",
|
||||||
STR("NamedDataSize")
|
"NamedDataSize"
|
||||||
};
|
};
|
||||||
|
|
||||||
str TokenType_toString(TokenType t){
|
cstr TokenType_toString(TokenType t){
|
||||||
if(t >= ARRAY_SIZE(_TokenType_str))
|
if(t >= ARRAY_SIZE(_TokenType_str))
|
||||||
return STR("!!INDEX_ERROR!!");
|
return "!!INDEX_ERROR!!";
|
||||||
return _TokenType_str[t];
|
return _TokenType_str[t];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
#include "../string/str.h"
|
|
||||||
#include "../collections/List.h"
|
#include "../collections/List.h"
|
||||||
|
|
||||||
typedef enum TokenType {
|
typedef enum TokenType {
|
||||||
@ -18,7 +17,7 @@ typedef enum TokenType {
|
|||||||
TokenType_OperationEnd, // EOL or EOF or ;
|
TokenType_OperationEnd, // EOL or EOF or ;
|
||||||
} TokenType;
|
} TokenType;
|
||||||
|
|
||||||
str TokenType_toString(TokenType t);
|
cstr TokenType_toString(TokenType t);
|
||||||
|
|
||||||
typedef struct Token {
|
typedef struct Token {
|
||||||
u32 begin; // some index in Compiler->code
|
u32 begin; // some index in Compiler->code
|
||||||
|
|||||||
68
src/cstr.c
68
src/cstr.c
@ -50,3 +50,71 @@ char* NULLABLE(vsprintf_malloc)(size_t buffer_size, cstr format, va_list argv){
|
|||||||
}
|
}
|
||||||
return buf;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -19,13 +19,13 @@ typedef enum __attribute__((__packed__)) Opcode {
|
|||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
typedef struct Instruction {
|
typedef struct Instruction {
|
||||||
str name;
|
cstr name;
|
||||||
InstructionImplFunc_t implementation;
|
InstructionImplFunc_t implementation;
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
} Instruction;
|
} Instruction;
|
||||||
|
|
||||||
#define Instruction_construct(NAME) {\
|
#define Instruction_construct(NAME) {\
|
||||||
.name = STR(#NAME), \
|
.name = #NAME, \
|
||||||
.implementation = NAME##_impl, \
|
.implementation = NAME##_impl, \
|
||||||
.opcode = Opcode_##NAME\
|
.opcode = Opcode_##NAME\
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ i32 main(const i32 argc, cstr* argv){
|
|||||||
for(u8 opcode = 0; opcode < 255; opcode++){
|
for(u8 opcode = 0; opcode < 255; opcode++){
|
||||||
const Instruction* instr = Instruction_getByOpcode(opcode);
|
const Instruction* instr = Instruction_getByOpcode(opcode);
|
||||||
if(instr != NULL){
|
if(instr != NULL){
|
||||||
printf("%02X %s\n", opcode, instr->name.data);
|
printf("%02X %s\n", opcode, instr->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
20
src/std.h
20
src/std.h
@ -58,3 +58,23 @@ 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 isAlphabeticalLower(char c) { return 'a' <= c && c <= 'z'; }
|
||||||
static inline bool isAlphabeticalUpper(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'; }
|
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);
|
||||||
|
|||||||
@ -2,24 +2,14 @@
|
|||||||
|
|
||||||
void StringBuilder_free(StringBuilder* b){
|
void StringBuilder_free(StringBuilder* b){
|
||||||
free(b->buffer.data);
|
free(b->buffer.data);
|
||||||
b->buffer = List_u8_construct(NULL, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str StringBuilder_getStr(StringBuilder* b){
|
str StringBuilder_build(StringBuilder* b){
|
||||||
List_u8_push(&b->buffer, '\0');
|
List_u8_push(&b->buffer, '\0');
|
||||||
str result = str_construct((char*)b->buffer.data, b->buffer.len - 1, true);
|
str result = str_construct((char*)b->buffer.data, b->buffer.len - 1, true);
|
||||||
return result;
|
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){
|
void StringBuilder_append_char(StringBuilder* b, char c){
|
||||||
List_u8_push(&b->buffer, c);
|
List_u8_push(&b->buffer, c);
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../collections/List.h"
|
#include "../collections/List.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
@ -7,12 +11,11 @@ typedef struct StringBuilder {
|
|||||||
List_u8 buffer;
|
List_u8 buffer;
|
||||||
} StringBuilder;
|
} StringBuilder;
|
||||||
|
|
||||||
static inline StringBuilder StringBuilder_alloc(u32 initial_size) {
|
static inline StringBuilder StringBuilder_construct(u32 initial_size) {
|
||||||
return (StringBuilder){ .buffer = List_u8_alloc(initial_size) };
|
return (StringBuilder){ .buffer = List_u8_alloc(initial_size) };
|
||||||
}
|
}
|
||||||
void StringBuilder_free(StringBuilder* b);
|
void StringBuilder_free(StringBuilder* b);
|
||||||
|
|
||||||
/// @param count set to -1 to clear StringBuilder
|
|
||||||
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count);
|
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count);
|
||||||
void StringBuilder_append_char(StringBuilder* b, char c);
|
void StringBuilder_append_char(StringBuilder* b, char c);
|
||||||
void StringBuilder_append_cstr(StringBuilder* b, char* s);
|
void StringBuilder_append_cstr(StringBuilder* b, char* s);
|
||||||
@ -23,3 +26,7 @@ void StringBuilder_append_f64(StringBuilder* b, f64 a);
|
|||||||
|
|
||||||
// adds '\0' to the buffer and returns pointer to buffer content
|
// adds '\0' to the buffer and returns pointer to buffer content
|
||||||
str StringBuilder_getStr(StringBuilder* b);
|
str StringBuilder_getStr(StringBuilder* b);
|
||||||
|
|
||||||
|
#if __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -3,97 +3,27 @@
|
|||||||
str str_copy(str src){
|
str str_copy(str src){
|
||||||
if(src.data == NULL || src.len == 0)
|
if(src.data == NULL || src.len == 0)
|
||||||
return src;
|
return src;
|
||||||
|
|
||||||
str nstr = str_construct((char*)malloc(src.len + 1), src.len, true);
|
str nstr = str_construct((char*)malloc(src.len + 1), src.len, true);
|
||||||
memcpy(nstr.data, src.data, src.len);
|
memcpy(nstr.data, src.data, src.len);
|
||||||
nstr.data[nstr.len] = '\0';
|
nstr.data[nstr.len] = '\0';
|
||||||
return nstr;
|
return nstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool str_equals(str s0, str s1){
|
bool str_compare(str str0, str str1){
|
||||||
if(s0.len != s1.len)
|
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++ )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(u32 i = 0; i < s0.len; i++)
|
|
||||||
if(s0.data[i] != s1.data[i])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
str str_reverse(str s){
|
str str_reverse(str s){
|
||||||
if(s.data == NULL || s.len == 0)
|
if(s.data == NULL || s.len == 0)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
str r = str_construct(malloc(s.len), s.len, s.isZeroTerminated);
|
str r = str_construct(malloc(s.len), s.len, s.isZeroTerminated);
|
||||||
for(u32 i = 0; i < s.len; i++ )
|
for(u32 i = 0; i < s.len; i++ )
|
||||||
r.data[i] = s.data[s.len - i - 1];
|
r.data[i] = s.data[s.len - i - 1];
|
||||||
return r;
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,27 +8,23 @@ typedef struct str {
|
|||||||
bool isZeroTerminated;
|
bool isZeroTerminated;
|
||||||
} str;
|
} 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 })
|
#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);
|
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
|
/// copies src content to new string and adds \0 at the end
|
||||||
str str_copy(str src);
|
str str_copy(str src);
|
||||||
|
|
||||||
/// compares two strings, NullPtr-friendly
|
/// compares two strings, NullPtr-friendly
|
||||||
bool str_equals(str str0, str str1);
|
bool str_compare(str str0, str str1);
|
||||||
|
|
||||||
/// allocates new string which is reversed variant of <s>
|
/// allocates new string which is reversed variant of <s>
|
||||||
str str_reverse(str s);
|
str str_reverse(str s);
|
||||||
|
|
||||||
i32 str_seek(str src, str fragment, u32 startIndex);
|
#if __cplusplus
|
||||||
i32 str_seekReverse(str src, str fragment, u32 startIndex);
|
}
|
||||||
|
#endif
|
||||||
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);
|
|
||||||
Loading…
Reference in New Issue
Block a user