#include "asmmon.h" #define AM_ADDR (AM_ZM | AM_ZMX | AM_ZMY | \ AM_IND | AM_INDX | AM_INDY | \ AM_ABS | AM_ABX | AM_ABY | \ AM_AIND | AM_AINDX | AM_AINDY | \ AM_INDX2 | AM_ZM2) static const uint64_t mem_size = 0x04000000; /* Size of address space. */ token *tok_global; uint8_t isexpr(uint8_t type, uint8_t dbg) { switch (type) { case EXPR_PLUS: case EXPR_MINUS: case EXPR_LOW: case EXPR_HIGH: case EXPR_OR: case EXPR_LSHFT: case EXPR_RSHFT: return 1; default: return 0; } } uint8_t get_rs(token *t, uint8_t dbg) { if (t->id == TOK_RS) { return t->type; } else { return 0xFF; } } uint8_t get_of(token *t, uint8_t dbg) { if (t->id == TOK_OF) { return t->type; } else { return 0xFF; } } uint8_t get_ind(uint8_t mne, uint8_t am, uint8_t dbg) { uint8_t base_idx = 0; uint8_t offset = 0; switch (mne) { case CMP: base_idx = CMP_IND; break; case CPB: base_idx = CPB_IND; break; case JMP: base_idx = JMP_IND; break; case JSR: base_idx = JSR_IND; break; case LDA: base_idx = LDA_IND; break; case LDB: base_idx = LDB_IND; break; case LDX: base_idx = LDX_IND; break; case LDY: base_idx = LDY_IND; break; case STA: base_idx = STA_IND; break; case STB: base_idx = STB_IND; break; case STX: base_idx = STX_IND; break; case STY: base_idx = STY_IND; break; } switch (am) { case IND : offset = 0; break; case INDY: offset += 1; break; case INDX: offset += 2; break; } return base_idx + offset; } uint8_t get_eind(uint8_t mne, uint8_t dbg) { switch (mne) { case DEC: return DEC_EIND; case INC: return INC_EIND; case STY: return STY_EIND; case STA: return STA_EIND; case STB: return STB_EIND; case LDX: return LDX_EIND; case STX: return STX_EIND; case CPB: return CPB_EIND; case CPX: return CPX_EIND; case CPY: return CPY_EIND; } return 0xFF; } static void write_value(uint64_t value, uint64_t address, uint8_t size) { if (address < mem_size) { size = (size > 7) ? 7 : size; #if 1 if (size < 7) { uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); *(uint64_t *)(addr+address) = (*(uint64_t *)(addr+address) & ~mask) | (value & mask); } else { *(uint64_t *)(addr+address) = value; } #else memcpy(addr+address, &value, size+1); #endif } } uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t end_expr, uint8_t stop_reg, uint8_t dbg) { uint64_t value = 0; uint64_t tmp_val = 0; uint8_t type = EXPR_NONE; uint8_t isstart = 1; do { if (t->id == TOK_EXPR) { type = t->type; t = t->next; } if (stop_reg && t->id == TOK_REG) { break; } switch (t->id) { case TOK_HEX: case TOK_DEC: case TOK_BIN: case TOK_CHAR: tmp_val = t->qword; t = t->next; break; case TOK_SYM: case TOK_LABEL: for (; t->sym && t->sym->isstruct && t->next && t->next->id == TOK_SYM; t = t->next); tmp_val = (t->sym) ? t->sym->val : addr; t = t->next; break; } if (end_expr != 0xFF && type == end_expr) { break; } switch (type) { case EXPR_PLUS : (isstart) ? (value = tmp_val) : (value += tmp_val); break; case EXPR_MINUS: (isstart) ? (value = -tmp_val) : (value -= tmp_val); break; case EXPR_OR : value |= tmp_val; break; case EXPR_LSHFT: value <<= tmp_val; break; case EXPR_RSHFT: value >>= tmp_val; break; case EXPR_LOW : value = tmp_val; switch (size) { default: case 2 : value &= 0xFFFFFFFF; break; case 1 : value &= 0x0000FFFF; break; case 0 : value &= 0x000000FF; break; } break; case EXPR_HIGH : value = tmp_val; switch (size) { default: case 2 : value >>= 0x20; break; case 1 : value >>= 0x10; break; case 0 : value >>= 0x08; break; } break; case EXPR_NONE : value = tmp_val; break; } isstart = 0; if (dbg) { printf("get_val(): Value: $%"PRIX64", Expression type: $%X, Expression Value: $%"PRIX64".\n", value, type, tmp_val); } } while (t && t->id == TOK_EXPR && isexpr(t->type, dbg)); return value; } token *skip_expr(token *t, uint8_t end_expr, uint8_t stop_reg, uint8_t dbg) { do { t = (t->id == TOK_EXPR) ? t->next : t; if (stop_reg && t->id == TOK_REG) { break; } switch (t->id) { case TOK_HEX : case TOK_DEC : case TOK_BIN : case TOK_CHAR : case TOK_SYM : case TOK_LABEL: t = t->next; break; } if (end_expr != 0xFF && t->id == TOK_EXPR && t->type == end_expr) { break; } } while (t && t->id == TOK_EXPR && isexpr(t->type, dbg)); return t; } uint8_t get_directivesize(uint8_t type, uint8_t dbg) { switch (type) { case DIR_QWORD: return 3; case DIR_DWORD: return 2; case DIR_WORD : return 1; case DIR_BYTE : return 0; } return 0; } uint16_t handle_struct(line **ln, uint64_t address, uint16_t offset, uint8_t dbg) { uint8_t is_struct = 0; uint8_t done = 0; uint8_t ismember = 0; uint16_t size = 0; uint16_t member_size = 0; line *l = *ln; symbol *strct = NULL; token *tok = l->tok; for (uint8_t found = 0; tok && !found; tok = tok->next) { switch (tok->id) { case TOK_DIR: is_struct = (tok->type == DIR_STRUCT); found = (tok->type == DIR_STRUCT || tok->type == DIR_UNION); break; case TOK_STRUCT: is_struct = 1; case TOK_UNION : found = 1; break; } } if (tok != NULL) { strct = tok->sym; } if (l && l->next) { l = l->next; } for (; l && !done; l = l->next) { token *t = l->tok; token *start = t; symbol *member; for (; t && !done; t = t->next) { switch (t->id) { case TOK_MEMBER: ismember = 1; member = t->sym; break; case TOK_DIR : ismember = (t->type == DIR_STRUCT || t->type == DIR_UNION) ? 1 : ismember; done = ((is_struct && t->type == DIR_ENDSTRUCT) || (!is_struct && t->type == DIR_ENDUNION)); if (!done && ismember) { switch (t->type) { case DIR_BYTE : member_size = 1; break; case DIR_WORD : member_size = 2; break; case DIR_DWORD : member_size = 4; break; case DIR_QWORD : member_size = 8; break; case DIR_UNION : case DIR_STRUCT: member_size = handle_struct(&l, address, offset, dbg); break; case DIR_RES : member_size = get_val(t, address, 3, 0xFF, 0, dbg); t = skip_expr(t, 0xFF, 0, dbg); break; } if (member && t->type != DIR_UNION && t->type != DIR_STRUCT) { member->val = offset; } if (is_struct) { size += member_size; offset += member_size; } else if (size < member_size) { size = member_size; } } ismember = 0; break; } } if (done) { break; } } *ln = l; if (strct != NULL) { strct->val = size; } return size; } uint64_t handle_directive(token *t, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t dbg) { union reg val; uint8_t c = 0; uint8_t tmp = 0; uint8_t type = t->type; uint64_t tmpaddr = address; t = t->next; for (; t; t = t->next) { tmp = 0; switch (t->id) { case TOK_HEX: case TOK_DEC: case TOK_BIN: case TOK_CHAR: case TOK_SYM: case TOK_LABEL: val.u64 = get_val(t, tmpaddr, get_directivesize(type, dbg), 0xFF, 0, dbg); switch (type) { case DIR_QWORD: tmp = 8; break; case DIR_DWORD: tmp = 4; break; case DIR_WORD : tmp = 2; break; case DIR_BYTE : tmp = 1; break; } write_value(val.u64, tmpaddr, tmp-1); tmpaddr += tmp; bc->datasize += tmp; if (t->next && t->next->id == TOK_EXPR && isexpr(t->next->type, dbg)) { t = skip_expr(t, 0xFF, 0, dbg); } break; case TOK_STRING: if (type == DIR_BYTE) { for (uint16_t k = 0; t->str[k] != '\0'; k++) { switch (t->str[k]) { case '\\': switch (t->str[k+1]) { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; case '\"': c = '\"'; break; case '\'': c = '\''; break; case '\\': c = '\\'; break; case '0' : c = '\0'; break; } k++; break; default: c = t->str[k]; break; } if (isasm) { addr[tmpaddr] = c; } tmpaddr++; bc->datasize++; } if (isasm) { addr[tmpaddr] = '\0'; } tmpaddr++; bc->datasize++; } break; } if (t == NULL) { break; } } return tmpaddr; } static uint8_t write_inst(uint8_t prefix, uint8_t ext_prefix, uint8_t opcode, uint64_t value, uint64_t address, uint8_t size, uint8_t isasm, uint8_t dbg) { uint8_t inst_size = 0; union reg ins; if (prefix & 3) { ins.u8[inst_size++] = prefix; } if ((ext_prefix & 0x0D) == 0x0D) { ins.u8[inst_size++] = ext_prefix; } ins.u8[inst_size++] = opcode; if (isasm) { write_value(ins.u64, address, inst_size-1); if (size) { write_value(value, address+inst_size, size-1); } } inst_size += size; return inst_size; } void get_operands(token *t, operand *op, uint64_t address, uint8_t rs, uint8_t dbg) { uint8_t op_type; uint8_t op_inst; switch (t->id) { case TOK_OPCODE: case TOK_EXTOP : case TOK_ORTHO : op_type = tok->id; op_inst = tok->byte; t = t->next; break; } int i = 0; int old_i = -1; uint8_t expr_type = 0xFF; uint8_t stop_reg = 0; uint64_t value = 0; uint8_t reg = 0; uint8_t got_value = 0; uint8_t is_sib = 0; for (; t; t = t->next) { switch (t->id) { case TOK_HEX : case TOK_DEC : case TOK_BIN : case TOK_SYM : case TOK_LABEL: if (!got_value) { expr_type = (expr_type == 0xFF && t->next && t->next->id == TOK_EXPR) ? t->next->type : expr_type; switch (expr_type) { default : stop_reg = 1; break; case EXPR_MUL : stop_reg = 0; break; } is_sib = !stop_reg; value = get_val(t, address, (rs != 0xFF) ? rs : 0, (!stop_reg) ? expr_type : 0xFF, stop_reg, dbg); got_value = 1; } else { got_value = 0; } /* Falls Through. */ case TOK_MEM: if (old_i != i) { op[i].type = 1; /* Set type to memory. */ op[i].id = (t->id == TOK_MEM) ? t->type : op[i].id; op[i].id = (is_sib) ? MEM_SIB : op[i].id; op[i].id2[0] = (is_sib) ? value : op[i].id2[0]; old_i = i; } else { } op[i].value = (!is_sib && got_value) ? value : op[i].value; if (stop_reg && got_value) { t = skip_expr(t, 0xFF, stop_reg, dgb); } i += (t->next && t->next->id != TOK_EXPR); break; case TOK_REG: if (old_i != i) { op[i].type = 0; /* Set type to register. */ op[i].id = t->type; old_i = i; } else { op[i].id = (op[i].id == MEM_IND) ? MEM_RIND : op[i].id; is_sib = (op[i].id == MEM_SIB); op[i].id2[is_sib] = (t->type << (reg*4)); reg++; reg = (reg > 1) ? 0 : reg; } i += (t->next && t->next->id != TOK_EXPR); break; case TOK_EXPR: expr_type = t->type; switch (expr_type) { default : stop_reg = 1; break; case EXPR_MUL : stop_reg = 0; break; } if (!got_value) { value = get_val(t, address, (rs != 0xFF) ? rs : 0, (!stop_reg) ? expr_type : 0xFF, stop_reg, dbg); got_value = 1; } else { got_value = 0; } break; } } } uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t dbg) { union reg val; uint8_t opsize; uint8_t id; uint8_t instr; uint8_t opcode; uint8_t ext_prefix = 0; uint8_t type; uint32_t am = 0; uint8_t tmp = 0; uint8_t prefix = 0; uint8_t rs = 0; uint8_t of = 0; uint8_t tmp_prefix = 0; uint8_t inst_size = 0; val.u64 = 0; instruction ins; operand op[2]; memset(op, 0xFF, sizeof(op)); for (; t; t = t->next) { if (t->id == TOK_OPCODE || t->id == TOK_EXTOP) { id = t->id; instr = t->byte; type = t->type; } else { break; } tmp = 0; opsize = 1; opcode = 0; if (t->next) { rs = get_rs(t->next, dbg); t = (rs != 0xFF) ? t->next : t; if (t->next) { of = get_of(t->next, dbg); t = (of != 0xFF) ? t->next : t; } } get_operands(t, op, address, rs, dbg); if (rs != 0xFF || of != 0xFF) { tmp_prefix = (rs != 0xFF) ? (rs << 0) : tmp_prefix; tmp_prefix |= (of != 0xFF) ? (of << 2) : tmp_prefix; } prefix = (tmp_prefix) ? ((tmp_prefix << 4) | 3) : 0; uint8_t isincdec = (instr == INC || instr == DEC); uint8_t isimplied = (op[0].type == 0xFF); switch (id) { case TOK_OPCODE: ins = inst[instr]; break; case TOK_EXTOP : ins = ext_inst[instr]; break; case TOK_ORTHO : ins = ortho_inst[instr]; break; } am = ins.am; uint8_t is_eind = (op[0].type && op[0].id == MEM_RIND && op[0].id2[0] == REG_E); uint8_t is_mem = (op[0].type && op[0].id != MEM_IMM); uint8_t is_idx = (is_mem && !op[1].type && (op[1].id == REG_X || op[1].id == REG_Y)); if (id == TOK_EXTOP || (id == TOK_OPCODE && is_eind)) { ext_prefix = 0x0D; } else if (!is_idx) { ext_prefix = 0x1D; } if ((am & AM_IMPL) && isimplied) { type = IMPL; } else { if (ins.am & AM_REL) { type = REL; } } opcode = ins.op; uint64_t saveaddr = address; uint64_t max_val = 0; uint8_t i = 0; uint8_t j = 1; uint8_t type2 = 0xFF; switch (type) { case REG_B: case IMPL: case REG_E: if (id == TOK_OPCODE && instr == CPS) { rs = 0; } if ((am & (AM_IMPL|AM_BREG|AM_EIND|AM_EIND2))) { if ((type == EIND) && (am & AM_EIND|AM_EIND2)) { int eind_type = ((am & AM_EIND2) != 0); switch (eind_type) { case 0: opcode = (id == TOK_EXTOP) ? opcode+0x14 : opcode+0x10; break; case 1: opcode = (id == TOK_EXTOP) ? opcode+0x01 : eind_base_ops[get_eind(instr, dbg)]; break; } } opcode = ((am & AM_BREG) && type == BREG) ? opcode+0x14 : opcode; } break; case REL: case IMM: if (am & (AM_IMM|AM_REL|AM_ORTHO|AM_ORTHO2)) { rs = (rs != 0xFF) ? rs : 0; tmp = (1 << rs); if (type == REL) { uint64_t max_sign = 0; uint8_t offset = 1; uint64_t tmp_val; tmp_val = val.u64; offset += (prefix != 0); tmp_val -= offset+tmp; tmp_val -= address; switch (rs) { default: max_sign = (int8_t )(1 << 7); break; case 1 : max_sign = (int16_t)(1 << 15); break; case 2 : max_sign = (int32_t)(1 << 31); break; case 3 : max_sign = (int64_t)((uint64_t)1 << 63); break; } if ((int64_t)tmp_val > ~(int64_t)max_sign || (int64_t)tmp_val < (int64_t)max_sign) { offset += (!rs); rs += (rs <= 3); tmp = (1 << rs); tmp_val = val.u64; tmp_val -= offset+tmp; tmp_val -= address; prefix = ((rs << 4) | 3); } val.u64 = tmp_val; } } break; default: if (of != 0xFF) { i = 8; for (; i <= 64; i += 8, j++) { max_val |= ((uint64_t)1 << (i-1)); if ((int64_t)val.u64 >= ~(int64_t)(max_val) || (int64_t)val.u64 <= (int64_t)(max_val)) { opsize = j; break; } } } else { for (; i <= 64; i += 8, j++) { max_val |= (0xFF << i); if (val.u64 <= max_val) { opsize = j; break; } } } type2 = type; if (type == 0xFF || (id == TOK_EXTOP && type2 != 0xFF)) { switch (opsize-1) { case 0: case 2: case 5: case 3: type = ZM ; break; case 1: case 4: case 6: case 7: type = ABS; break; } } switch (type2) { case ZMX : type = (type == ABS) ? ABSX : type2; break; case ZMY : type = (type == ABS) ? ABSY : type2; break; case IND : type = (type == ABS) ? AIND : type2; break; case INDX: type = (type == ABS) ? AINDX : type2; break; case INDY: type = (type == ABS) ? AINDY : type2; break; } if (opsize) { uint8_t is_abs = 0; switch (type) { case ABS : case ABSX : case ABSY : case AIND : case AINDX: case AINDY: is_abs = 1; break; } if (!is_abs || (type2 != 0xFF && type == type2)) { switch (opsize) { case 2: opsize = 3; break; case 5: opsize = 6; break; } } prefix |= amp[opsize-1]; } if (am & AM_ADDR|AM_ORTHO|AM_ORTHO2) { switch (type) { case ZM: if (am & AM_ZM) { opcode += 0x04; } else if (am & AM_ZM2) { opcode += 0x20; } break; case ZMX: if (am & AM_ZMX) { opcode += (id == TOK_OPCODE) ? 0x06 : 0x54; } break; case ZMY: if (am & AM_ZMY) { opcode += 0x14; } break; case INDX: if (am & AM_INDX) { opcode += (id == TOK_OPCODE) ? 0x16 : 0x94; break; } /* Falls Through. */ case IND: case INDY: if ((id == TOK_OPCODE) && (am & (AM_IND|AM_INDY|AM_INDX2))) { opcode = ind_ops[get_ind(instr, type, dbg)]; } else { opcode += (type == IND) ? 0x44 : 0x84; } break; case ABS: if (am & AM_ABS) { opcode += 0x10; } break; case ABSX: if (am & AM_ABX) { opcode += 0x50; } break; case ABSY: if (am & AM_ABY) { opcode += 0x00; } break; case AIND: if (am & AM_AIND) { opcode += 0x40; } break; case AINDX: if (am & AM_AINDX) { opcode += 0x90; } break; case AINDY: if (am & AM_AINDY) { opcode += 0x80; } break; } tmp = opsize; } break; } inst_size = write_inst(prefix, ext_prefix, opcode, val.u64, address, tmp, isasm, dbg); address += inst_size; bc->progsize += inst_size; } return address; } uint64_t parse_tokens(token *t, line **l, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t dbg) { for (; t; t = t->next) { switch (t->id) { case TOK_DIR: switch (t->type) { case DIR_STRUCT: case DIR_UNION : handle_struct(l, address, 0, dbg); break; case DIR_RES: t = t->next; address += get_val(t, address, 3, 0xFF, 0, dbg); break; case DIR_ORG: t = t->next; address = get_val(t, address, 3, 0xFF, 0, dbg); break; case DIR_BYTE: case DIR_WORD: case DIR_DWORD: case DIR_QWORD: address = handle_directive(t, bc, isasm, address, dbg); break; } break; case TOK_EXTOP : case TOK_OPCODE: address = handle_opcode(t, bc, isasm, address, dbg); break; case TOK_COMMENT: break; } } return address; } token *make_token(uint8_t id, uint8_t type, uint8_t space, uint8_t tab, uint64_t value, char *str, symbol *s) { token *new_tok = malloc(sizeof(token)); (last_tok) ? (last_tok->next = new_tok) : (tokens = new_tok); new_tok->id = id; new_tok->type = type; new_tok->tab = tab; new_tok->space = space; new_tok->subtab = 0; new_tok->subspace = 0; new_tok->digits = 0; if (s) { new_tok->sym = s; } else if (str[0]) { new_tok->str = str; } else { new_tok->qword = value; } new_tok->next = NULL; last_tok = new_tok; return new_tok; } void assemble(line *ln, bytecount *bc, uint8_t dbg) { uint64_t address = 0; line *l = ln; for (int i = 0; i < 2; i++) { l = ln; for (; l; l = l->next) { l->addr = address; token *t = l->tok; address = parse_tokens(t, &l, bc, 0, address, dbg); } l = ln; for (; l; l = l->next) { address = l->addr; token *t = l->tok; for (; t; t = t->next) { if (t->id == TOK_LABEL && t->sym->val != address) { t->sym->val = l->addr; } } } } l = ln; bc->progsize = 0; bc->datasize = 0; for (; l; l = l->next) { address = parse_tokens(l->tok, &l, bc, 1, address, dbg); } } static void find_dupsym() { symbol *root = symbols; symbol *s = symbols; for (; s; s = s->next) { root = symbols; for (int i = 0; root; root = root->next) { if (root == s) { i++; } if (i > 1) { printf("Found duplicate symbol, s->name: %s, root->name: %s\n", s->name, root->name); i = 0; } } } } static symbol *find_fixup(token *t) { fixup* f = fixups; for (; f && t != f->t; f = f->next); return (f && t == f->t) ? f->s : NULL; } static void print_symval(symbol *s) { if (s) { if (s->down) { print_symval(s->down); } if (s->name) { printf("s->name: %s, s->val: $%"PRIX64"\n", s->name, s->val); } print_symval(s->next); } } static void print_symtree(symbol *s, int depth) { if (s) { if (s->name != NULL) { for (int i = depth; i; i--) { printf("|%s", (i > 1) ? " " : "--"); } printf("%s: $%"PRIX64"\n", s->name, s->val); } if (s->down != NULL) { print_symtree(s->down, depth+1); } print_symtree(s->next, depth); } } void fix_symtree(line *l) { symbol *s = symbols; symbol *cur_sym = NULL; symbol *sym_struct = NULL; symbols = NULL; last_sym = NULL; int islocal = 0; int isanon = 0; int is_struct = 0; int is_structsym = 0; for (; l; l = l->next) { token *t = l->tok; token *lt = NULL; for (; t; t = t->next) { int ismember = (t->id == TOK_MEMBER); switch (t->id) { case TOK_STRUCT: case TOK_UNION : islocal = !(is_struct == 1 && lt && lt->id == TOK_DIR); case TOK_SYM : if (t->id == TOK_SYM && t != l->tok) { break; } case TOK_MEMBER: case TOK_LABEL : if (symbols) { (!islocal && s && !s->up) ? (last_sym = s) : (last_loc = s); } if (((t->type == 1 || ismember) && !islocal) || (islocal && ismember && is_structsym)) { is_structsym = 0; last_loc = NULL; islocal = 1; cur_sym = s; s->down = t->sym; s->down->up = s; s = s->down; if (s) { s->next = NULL; s->prev = NULL; s->down = NULL; } locals = s; } else if ((islocal || t->type == 0)) { if (t->type == 0 && !is_struct && islocal && !ismember) { islocal = 0; if (s) { s->up->down = locals; s = s->up; } } symbol *tmp = s; s = t->sym; if (s) { s->prev = (tmp && tmp != s) ? tmp : NULL; s->up = (s->prev) ? s->prev->up : s->up; } if (s && s->next) { s->next = NULL; } } if (!islocal) { last_loc = NULL; (last_sym) ? (last_sym->next = s) : (symbols = s); cur_sym = s; if (last_sym) { last_sym->next->prev = last_sym; last_sym->next->up = last_sym->up; last_sym->next->down = NULL; } } else { (last_loc) ? (last_loc->next = s) : (locals = s); if (last_loc) { last_loc->next->prev = last_loc; last_loc->next->up = last_loc->up; last_loc->next->down = NULL; } else { locals->prev = NULL; locals->down = NULL; } } break; case TOK_DIR: if (t->type == DIR_STRUCT || t->type == DIR_UNION) { is_struct++; is_structsym = (t->next && (t->next->id == TOK_STRUCT || t->next->id == TOK_UNION)); if ((!is_structsym) || (isanon && is_structsym)) { isanon++; } sym->name = NULL; } s = s->next; free(sym); sym = NULL; free_symbols(s); } } static inline void free_fixups(fixup *f) { fixup *fix; if (f != NULL) { fix = f; f = f->next; free(fix); fix = NULL; free_fixups(f); } } uint64_t get_tokmem(token *t) { uint64_t i = 0; for (; t; t = t->next, i++); return i*sizeof(token); } void get_linemem(line *l) { uint64_t i = 0; uint64_t j = 0; for (; l; j += get_tokmem(l->tok), l = l->next, i++); printf("Bytes per line: %"PRIu64", Bytes per token: %"PRIu64", Total size of line table in bytes: %"PRIu64"\n", sizeof(line), sizeof(token), j+(i*sizeof(line))); } void cleanup() { uint16_t i; if (lines) { /*get_linemem(lines);*/ /*fix_symtree(lines);*/ free_lines(lines); lines = NULL; } if (symbols) { /*print_symtree(symbols, 0);*/ free_symbols(symbols); symbols = NULL; } if (fixups) { free_fixups(fixups); fixups = NULL; } while (i < stridx || i < comidx) { if (i < stridx && string[i]) { free(string[i]); string[i] = NULL; } if (i < comidx && comment[i]) { free(comment[i]); comment[i] = NULL; } i++; } }