#include "tok.h" #include #include #include "util.h" size_t type_size[TypeEnumSize] = { [TypeVoid] = 0, [TypeFloat] = sizeof(((Value*)NULL)->Float), [TypeInt] = sizeof(((Value*)NULL)->Int), [TypeBool] = sizeof(((Value*)NULL)->Bool), [TypeChar] = sizeof(((Value*)NULL)->Char), [TypePtr] = sizeof(((Value*)NULL)->Ptr), [TypeArr] = sizeof(((Value*)NULL)->Arr), }; const char *type_str[TypeEnumSize] = { [TypeVoid] = "void", [TypeFloat] = "float", [TypeInt] = "int", [TypeBool] = "bool", [TypeChar] = "char", [TypePtr] = "ptr", [TypeArr] = "arr", }; /* if purge is set, even statically allocated literals will be freed */ void free_value(Value *v, bool purge) { switch (v->type) { case TypeArr: if (v->Arr.vals && (purge || v->Arr.dynamically_allocated)) { free(v->Arr.vals); v->Arr.vals = NULL; v->Arr.len = 0; v->Arr.cap = 0; } break; default: break; } } void print_value(const Value *v, bool raw) { switch (v->type) { case TypeVoid: printf("(void)"); break; case TypeFloat: printf("%f", v->Float); break; case TypeInt: printf("%zd", v->Int); break; case TypeBool: printf("%s", v->Bool ? "true" : "false"); break; case TypeChar: if (raw) printf("%c", v->Char); else { const char *esc = unescape_char(v->Char); if (esc) printf("'%s'", esc); else printf("'%c'", v->Char); } break; case TypePtr: { if (v->Ptr.val) { printf("ptr<%s>(", type_str[v->Ptr.type]); Value deref = { .type = v->Ptr.type }; memcpy(&deref.Void, v->Ptr.val, type_size[v->Ptr.type]); print_value(&deref, false); printf(")"); } else printf("ptr<%s>(nil)", type_str[v->Ptr.type]); break; } case TypeArr: if (v->Arr.is_string) { if (v->Arr.type != TypeChar) ASSERT_UNREACHED(); char *str = v->Arr.vals; if (!raw) printf("\""); for (size_t i = 0; i < v->Arr.len; i++) { char c = str[i]; if (raw) printf("%c", c); else { const char *esc = unescape_char(c); if (esc) printf("%s", esc); else printf("%c", c); } } if (!raw) printf("\""); } else { printf("["); for (size_t i = 0;; i++) { size_t ty_sz = type_size[v->Arr.type]; Value ty_val = { .type = v->Arr.type }; memcpy(&ty_val.Void, (uint8_t*)v->Arr.vals + ty_sz * i, ty_sz); print_value(&ty_val, false); if (i+1 >= v->Arr.len) break; printf(", "); } printf("]"); } break; default: ASSERT_UNREACHED(); } } int8_t op_prec[OperatorEnumSize] = { [OpEOF] = PREC_DELIM, [OpNewLn] = PREC_DELIM, [OpLCurl] = PREC_DELIM, [OpRParen] = PREC_DELIM, [OpRBrack] = PREC_DELIM, [OpComma] = PREC_DELIM, [OpAnd] = 0, [OpOr] = 0, [OpEq] = 1, [OpNeq] = 1, [OpLt] = 1, [OpGt] = 1, [OpLe] = 1, [OpGe] = 1, [OpAdd] = 2, [OpSub] = 2, [OpMul] = 3, [OpDiv] = 3, }; const char *op_str[OperatorEnumSize] = { [OpLCurl] = "{", [OpRCurl] = "}", [OpLParen] = "(", [OpRParen] = ")", [OpLBrack] = "[", [OpRBrack] = "]", [OpComma] = ",", [OpAdd] = "+", [OpSub] = "-", [OpMul] = "*", [OpDiv] = "/", [OpNot] = "!", [OpNewLn] = "\\n", [OpEOF] = "EOF", [OpEq] = "==", [OpNeq] = "!=", [OpLt] = "<", [OpGt] = ">", [OpLe] = "<=", [OpGe] = ">=", [OpAnd] = "&&", [OpOr] = "||", }; const char *tok_str[TokKindEnumSize] = { [TokAssign] = "=", [TokDeclare] = ":=", [TokIf] = "if", [TokElse] = "else", [TokWhile] = "while", }; #define TOKLIST_MEMPOOL_INIT_CAP 32768 static inline TokListItem *toklist_alloc_item(TokList *l) { TokListItem *itm = pool_alloc(l->p, sizeof(TokListItem)); itm->prev = itm->next = NULL; return itm; } void toklist_init(TokList *l) { l->begin = l->end = NULL; l->p = pool_new(TOKLIST_MEMPOOL_INIT_CAP); } void toklist_term(TokList *l) { pool_term(l->p); } void toklist_append(TokList *l, Tok t) { TokListItem *itm = toklist_alloc_item(l); itm->tok = t; if (l->begin == NULL) { l->begin = l->end = itm; return; } l->end->next = itm; itm->prev = l->end; l->end = itm; } void toklist_del(TokList *l, TokListItem *from, TokListItem *to) { if (from == l->begin) { l->begin = to->next; if (to->next) to->next->prev = NULL; } else from->prev->next = to->next; if (to == l->end) { l->end = from->prev; if (from->prev) from->prev->next = NULL; } else to->next->prev = from->prev; } void print_toks(TokList *l) { for (TokListItem *i = l->begin; i != NULL; i = i->next) { printf("( "); switch (i->tok.kind) { case TokOp: printf(C_IYELLOW "Op" C_RESET); printf(": " C_ICYAN "%s" C_RESET, op_str[i->tok.Op]); break; case TokVal: printf(C_IYELLOW "Val" C_RESET ": " C_ICYAN); print_value(&i->tok.Val, false); printf(C_RESET); break; case TokIdent: printf(C_IYELLOW "Ident" C_RESET); if (i->tok.Ident.kind == IdentName) printf(": " C_ICYAN "Name" C_RESET ": " C_IGREEN "'%s'" C_RESET, i->tok.Ident.Name); else if (i->tok.Ident.kind == IdentAddr) printf(": " C_ICYAN "Addr" C_RESET ": " C_IGREEN "%zu" C_RESET, i->tok.Ident.Addr); break; default: if (tok_str[i->tok.kind]) { printf(C_IYELLOW "%s" C_RESET, tok_str[i->tok.kind]); } } printf(" | %zu:%zu )\n", i->tok.ln, i->tok.col); } }