194 lines
6.2 KiB
C
194 lines
6.2 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) {\
|
|
char* tok_str = Compiler_extractTokenStr(cmp, T);\
|
|
cmp->pos = T.begin;\
|
|
Compiler_setError(cmp, "unexpected token '%s'", tok_str);\
|
|
free(tok_str);\
|
|
}
|
|
|
|
#define setError_unexpectedTokenChar(T, I) {\
|
|
cmp->pos = T.begin + I;\
|
|
Compiler_setError(cmp, "unexpected token '%c'", cmp->code[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(u8*) resolveEscapeSequences(Compiler* cmp, cstr src){
|
|
u32 len = strlen(src);
|
|
List_u8 resolved = List_u8_alloc(len);
|
|
char c;
|
|
bool escaped = false;
|
|
for(u32 i = 0; i < len; i++){
|
|
c = src[i];
|
|
if(c == '\\'){
|
|
escaped = !escaped;
|
|
continue;
|
|
}
|
|
|
|
if(!escaped){
|
|
List_u8_push(&resolved, c);
|
|
continue;
|
|
}
|
|
|
|
// escape codes
|
|
switch(c){
|
|
case '0':
|
|
List_u8_push(&resolved, '\0');
|
|
break;
|
|
case 'n':
|
|
List_u8_push(&resolved, '\n');
|
|
break;
|
|
case 'r':
|
|
List_u8_push(&resolved, '\r');
|
|
break;
|
|
case 't':
|
|
List_u8_push(&resolved, '\t');
|
|
break;
|
|
case 'e':
|
|
List_u8_push(&resolved, '\e');
|
|
break;
|
|
default:
|
|
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
|
|
free(resolved.data);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return resolved.data;
|
|
}
|
|
|
|
static void parseDataDefinition(Compiler* cmp, char* instr_name, DataDefinition* ddf){
|
|
i32 _element_size_bits;
|
|
if(sscanf(instr_name, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
|
|
setError(Error_BitSize);
|
|
return;
|
|
}
|
|
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;
|
|
i32 len = 0;
|
|
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_extractTokenStr(cmp, tok);
|
|
if(cstr_seekChar(tok_str, '.', 0, -1) != -1){
|
|
f64 f = atof(tok_str);
|
|
List_u8_pushBytes(&ddf->data, &f, 8 - ddf->element_size, ddf->element_size);
|
|
}
|
|
else {
|
|
i64 i = atoll(tok_str);
|
|
List_u8_pushBytes(&ddf->data, &i, 8 - ddf->element_size, ddf->element_size);
|
|
}
|
|
break;
|
|
case TokenType_Char:
|
|
tok.begin += 1;
|
|
tok.length -= 2;
|
|
tok_str = Compiler_extractTokenStr(cmp, tok);
|
|
processed_str = resolveEscapeSequences(cmp, tok_str);
|
|
free(tok_str);
|
|
len = strlen(processed_str);
|
|
if(len != ddf->element_size){
|
|
setError("can't fit char of size %i in %u bit variable", len, _element_size_bits);
|
|
return;
|
|
}
|
|
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
|
|
break;
|
|
case TokenType_String:
|
|
tok.begin += 1;
|
|
tok.length -= 2;
|
|
tok_str = Compiler_extractTokenStr(cmp, tok);
|
|
processed_str = resolveEscapeSequences(cmp, tok_str);
|
|
free(tok_str);
|
|
len = strlen(processed_str);
|
|
List_u8_pushBytes(&ddf->data, processed_str, 0, len);
|
|
break;
|
|
case TokenType_OperationEnd:
|
|
return;
|
|
default:
|
|
setError_unexpectedToken(tok);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void parseOperation(Compiler* cmp, char* 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);
|
|
Section_init(sec, Compiler_extractTokenStr(cmp, tok));
|
|
break;
|
|
case TokenType_Instruction:
|
|
if(sec == NULL)
|
|
returnError("no section");
|
|
char* instr_name = Compiler_extractTokenStr(cmp, tok);
|
|
// data definition starts with const
|
|
if(cstr_seek(instr_name, "const", 0, 1)){
|
|
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data);
|
|
parseDataDefinition(cmp, instr_name, dataDefPtr);
|
|
}
|
|
else {
|
|
Operation* operPtr = List_Operation_expand(&sec->code);
|
|
parseOperation(cmp, instr_name, operPtr);
|
|
}
|
|
break;
|
|
default:
|
|
setError_unexpectedToken(tok);
|
|
return false;
|
|
}
|
|
|
|
if(cmp->state == CompilerState_Error)
|
|
return false;
|
|
|
|
cmp->tok_i++;
|
|
}
|
|
|
|
return true;
|
|
}
|