#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; }