TCPU/src/compiler/Parser.c

196 lines
6.6 KiB
C

#include "Compiler_internal.h"
#define setError(FORMAT, ...) {\
cmp->pos = cmp->tokens.data[cmp->tok_i].begin;\
Compiler_setError(cmp, FORMAT, ##__VA_ARGS__);\
}
#define setError_unexpectedToken(T) {\
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
cmp->pos = T.begin;\
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.data[cmp->pos]);\
}
#define Error_TokenUnset "token of undefined type"
#define Error_BitSize "invalid size in bits"
static void List_u8_pushBytes(List_u8* l, void* value, u32 startIndex, u32 count){
u8* v = value;
for(u32 byte_i = startIndex; byte_i < startIndex + count; byte_i++){
List_u8_push(l, v[byte_i]);
}
}
static inline bool isVarSizeBits(u32 B) { return (B == 8 && B == 16 && B == 32 && B == 64); }
static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
StringBuilder sb = StringBuilder_alloc(src.len);
char c;
bool escaped = false;
for(u32 i = 0; i < src.len; i++){
c = src.data[i];
if(c == '\\'){
escaped = !escaped;
continue;
}
if(!escaped){
StringBuilder_append_char(&sb, c);
continue;
}
// escape codes
switch(c){
case '0':
StringBuilder_append_char(&sb, '\0');
break;
case 'n':
StringBuilder_append_char(&sb, '\n');
break;
case 'r':
StringBuilder_append_char(&sb, '\r');
break;
case 't':
StringBuilder_append_char(&sb, '\t');
break;
case 'e':
StringBuilder_append_char(&sb, '\e');
break;
default:
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
StringBuilder_free(&sb);
return str_null;
}
}
return StringBuilder_getStr(&sb);
}
static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* ddf){
i32 _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];
str tok_str = Compiler_constructTokenStr(cmp, tok);
str processed_str = str_null;
ddf->name = tok_str;
while(++cmp->tok_i < cmp->tokens.len){
switch(tok.type){
case TokenType_Unset:
setError(Error_TokenUnset);
return;
case TokenType_SingleLineComment:
case TokenType_MultiLineComment:
// skip comments
break;
case TokenType_Number:
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.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_constructTokenStr(cmp, tok);
processed_str = resolveEscapeSequences(cmp, tok_str);
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.data, 0, processed_str.len);
free(processed_str.data);
break;
case TokenType_String:
tok.begin += 1;
tok.length -= 2;
tok_str = Compiler_constructTokenStr(cmp, tok);
processed_str = resolveEscapeSequences(cmp, tok_str);
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
free(processed_str.data);
break;
case TokenType_OperationEnd:
return;
default:
setError_unexpectedToken(tok);
return;
}
}
}
static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
}
bool Compiler_parse(Compiler* cmp){
returnErrorIf_auto(cmp->state != CompilerState_Lexing);
cmp->state = CompilerState_Parsing;
Token tok;
Section* sec = NULL;
while(cmp->tok_i < cmp->tokens.len){
tok = cmp->tokens.data[cmp->tok_i];
switch(tok.type){
case TokenType_Unset:
returnError(Error_TokenUnset);
case TokenType_SingleLineComment:
case TokenType_MultiLineComment:
// skip comments
break;
case TokenType_Label:
// create new section
sec = List_Section_expand(&cmp->ast.sections, 1);
Section_init(sec, Compiler_constructTokenStr(cmp, tok));
break;
case TokenType_Instruction:
if(sec == NULL)
returnError("no section");
str instr_name = Compiler_constructTokenStr(cmp, tok);
// data definition starts with const
if(str_startsWith(instr_name, STR("const"))){
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data, 1);
parseDataDefinition(cmp, instr_name, dataDefPtr);
}
else {
Operation* operPtr = List_Operation_expand(&sec->code, 1);
parseOperation(cmp, instr_name, operPtr);
}
break;
default:
setError_unexpectedToken(tok);
return false;
}
if(cmp->state == CompilerState_Error)
return false;
cmp->tok_i++;
}
return true;
}