/* Takes a char pointer "key", variable "value", and "user_data" (not used), and prints information about "value" */ static void var_display_func( madparser* mp, gpointer key, gpointer value, gpointer user_data ) { quatro* p = (quatro*)user_data; FILE* out = (FILE*)(p->first_); GNode* expr = ((variable*)value)->expr_; fprintf( out, "Variable: %s; defined on line %d in file %s\n", ((variable*)value)->name_, ((variable*)value)->local_linenum_, ((variable*)value)->filename_ ); fprintf( out, "Expression: "); expr_display( mp, out, expr, (GHashTable*)(p->third_), (GHashTable*)(p->fourth_) ); fprintf( out, "\nValue: "); if ( ((expr_struct*)(expr->data))->kind_ == STRING_EXPR ) { fprintf( out, "\"%s\"", ((expr_struct*)(expr->data))->svalue_); } else if ( ((expr_struct*)(expr->data))->kind_ == STR_IDENT_EXPR ) { fprintf( out, "\"%s\"", ( (constant*)const_table_lookup( ((expr_struct*)(expr->data))->svalue_, (GHashTable*)(p->second_) ))->svalue_ ); } else if ( ((expr_struct*)(expr->data))->kind_ == VAR_IDENT_EXPR ) { char* str = expr_is_string( mp, expr, (GHashTable*)(p->second_), (GHashTable*)(p->third_) ); if ( str != NULL ) { fprintf( out, "\"%s\"", str); } else { fprintf( out, "%f", expr_evaluate( mp, expr, (GHashTable*)(p->third_), (GHashTable*)(p->fourth_) ) ); } } else { fprintf( out, "%f", expr_evaluate( mp, expr, (GHashTable*)(p->third_), (GHashTable*)(p->fourth_) ) ); } fprintf( out, "\n" ); }
const cml_atom * cml_node_get_value(cml_node *mn) { const cml_binding *bd; switch (mn->treetype) { case MN_DERIVED: assert(mn->expr != 0); cml_atom_init(&mn->value); expr_evaluate(mn->expr, &mn->value); return &mn->value; case MN_MENU: if (!cml_node_is_radio(mn)) return 0; /* fall through */ case MN_SYMBOL: if ((bd = _cml_tx_get(mn->rulebase, mn)) == 0) { cml_atom_init(&mn->value); if (cml_node_is_radio(mn->parent)) { mn->value.type = A_BOOLEAN; mn->value.value.tritval = (cml_node_get_value(mn->parent)->value.node == mn ? CML_Y : CML_N); } else if (!mn_eval_default_expr(mn, &mn->value)) { /* * Failed to set default value from expression, * so use fallback defaults. */ cml_atom_init(&mn->value); /* zero value */ if (mn->value_type == A_NODE) { mn->value.type = A_NODE; mn->value.value.node = (mn->children == 0 ? 0 : mn->children->data); } else if (!mn->rulebase->cml1_default_vals) { /* CML2 default value is a zero value of the right type */ mn->value.type = mn->value_type; } /* CML1 default is type A_NONE, i.e. a null */ } return &mn->value; } return &bd->value; case MN_UNKNOWN: case MN_EXPLANATION: return 0; } return 0; }
void expr_evaluate_some(struct expression *e, expr_var v, double min, double max, int npoints, double *buffer) { int i; for (i=0; i<npoints; i++) { expr_set_variable (e, v, min+(((max-min)*i)/(npoints-1))); buffer[i] = expr_evaluate(e); } }
gboolean mn_is_saveable(const cml_node *mn) { cml_atom a; if (mn->saveability_expr == 0) return cml_node_is_visible(mn); cml_atom_init(&a); expr_evaluate(mn->saveability_expr, &a); assert(a.type == A_BOOLEAN); return (a.value.tritval == CML_Y); }
static gboolean mn_eval_default_expr(cml_node *mn, cml_atom *val) { if (mn->expr == 0) return FALSE; /* no explicit expression for default value */ cml_atom_init(val); expr_evaluate(mn->expr, val); if (basic_type(val->type) != basic_type(mn->value_type) && mn->value_type != A_NONE) return FALSE; return TRUE; }
int main( int argc, char *argv[] ) { printf("CSE 40243 Expression Compiler\n"); printf("Enter an infix expression using the operators +-*/() ending with ;\n\n"); if(yyparse()==0) { printf("parse successful: "); expr_print(parser_result); printf("\n"); printf("evaluates to: %lg\n",expr_evaluate(parser_result)); return 0; } else { printf("parse failed!\n"); return 1; } }
static void if_handle(state_t* state, match_t* match, bool* reprocess) { list_t* result = ppparam_get(state); struct expr* expr = NULL; uint16_t value; bstring output; bool stopped_at_else; // Ensure the parameter format is correct. if (list_size(result) == 1 && ((parameter_t*)list_get_at(result, 0))->type == EXPRESSION) { // Get the expression. expr = ((parameter_t*)list_get_at(result, 0))->expr; replace_state = state; value = expr_evaluate(expr, &if_define_replace, &dhalt_expression_exit_handler); replace_state = NULL; if (value) { output = skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) skip_to_endif(state, false, &stopped_at_else); } else { bassigncstr(output, ""); skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) { output = skip_to_endif(state, false, &stopped_at_else); } } // print the output to the pre processor input ppimpl_printf(state, "%s", output->data); } else dhalt(ERR_PP_ASM_IF_PARAMETERS_INCORRECT, ppimpl_get_location(state)); ppparam_free(result); }
static uint16_t if_define_replace(bstring define) { // Search through all of the defines to find one where // the name matches. size_t i = 0; match_t* match; struct expr* tree; for (i = 0; i < list_size(&replace_state->handlers); i++) { match = list_get_at(&replace_state->handlers, i); if (biseq(match->text.ref, define)) { // Found a match. tree = expr_parse(match->userdata); if (tree == NULL) dhalt(ERR_PP_DEFINE_NOT_EXPRESSION, ppimpl_get_location(replace_state)); return expr_evaluate(tree, &if_define_replace, &dhalt_expression_exit_handler); } } dhalt(ERR_PP_DEFINE_NOT_FOUND, ppimpl_get_location(replace_state)); return 0; }
gboolean cml_node_is_visible(const cml_node *mn) { cml_atom a; GList *iter; if (mn->visibility_expr == 0) return TRUE; /* default is to be visible always */ cml_atom_init(&a); expr_evaluate(mn->visibility_expr, &a); if (a.value.tritval != CML_Y) return FALSE; for (iter = mn->dependees ; iter != 0 ; iter = iter->next) { cml_node *dep = (cml_node *)iter->data; if (!cml_node_is_visible(dep)) return FALSE; } return TRUE; }
void process_line(struct ast_node_line* line) { struct instruction_mapping* insttype; struct process_parameters_results ppresults; struct process_parameter_results dparam; struct ast_node_parameter* dcurrent; uint32_t dchrproc; uint16_t i, flimit, fchar, opos; // Change depending on the type of line. switch (line->type) { case type_keyword: switch (line->keyword) { case BOUNDARY: fprintf(stderr, ".BOUNDARY"); // Emit safety boundary of 16 NULL words. for (i = 0; i < 16; i += 1) aout_emit(aout_create_raw(0)); break; case FILL: fprintf(stderr, ".FILL"); // Emit N words with value X flimit = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler); fchar = expr_evaluate(line->keyword_data_expr_2, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler); for (i = 0; i < flimit; i++) aout_emit(aout_create_raw(fchar)); break; case EXTENSION: fprintf(stderr, ".EXTENSION %s", line->keyword_data_string); // Emit extension metadata. aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0'))); break; case INCBIN: fprintf(stderr, ".INCBIN %s", line->keyword_data_string); // Emit binary include metadata. aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0'))); break; case ORIGIN: opos = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler); fprintf(stderr, ".ORIGIN 0x%04X", opos); // Emit origin set metadata. aout_emit(aout_create_metadata_origin(opos)); break; case EXPORT: fprintf(stderr, ".EXPORT %s", line->keyword_data_string); // Emit export metadata. aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0'))); break; case IMPORT: fprintf(stderr, ".IMPORT %s", line->keyword_data_string); // Emit export metadata. aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0'))); break; default: fprintf(stderr, "\n"); ahalt(ERR_UNSUPPORTED_KEYWORD, NULL); } fprintf(stderr, "\n"); break; case type_instruction: // Check to see if this is DAT. if (strcmp(line->instruction->instruction, "DAT") == 0) { // Handle data. fprintf(stderr, "EMIT DAT"); // Process parameters as data. reverse_parameters(line->instruction->parameters); dcurrent = line->instruction->parameters->last; while (dcurrent != NULL) { // Process parameter normally. dparam = process_parameter(dcurrent); // Output depending on what kind of parameter it was. if (dparam.v_label != NULL) // If this is a label, output something that we need to replace. aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label))))); else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it. { fprintf(stderr, " \"%s\"", dparam.v_raw->data); for (dchrproc = 0; dchrproc < blength(dparam.v_raw); dchrproc++) aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc])); } else if (dparam.v_extra_used == true) // Just a single address. aout_emit(aout_create_expr(dparam.v_extra)); else // Something that isn't handled by DAT. { fprintf(stderr, "\n"); ahalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL); } dcurrent = dcurrent->prev; } } else { // Handle instruction. insttype = get_instruction_by_name(line->instruction->instruction); if (insttype == NULL) ahalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction); fprintf(stderr, "EMIT %s", insttype->name); // Process parameters normally. ppresults = process_parameters(line->instruction->parameters); // Force the parameter value to be NXT if it's a label. if (ppresults.a_label != NULL) ppresults.a = NXT_LIT; if (ppresults.b_label != NULL) ppresults.b = NXT_LIT; if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT; if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT; // Output the initial opcode. if (insttype->opcode != OP_NONBASIC) aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b)); else aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a)); // If the parameter is a label or requires an extra word, output them. if (ppresults.b_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label))))); else if (ppresults.b_extra_used) aout_emit(aout_create_expr(ppresults.b_extra)); if (ppresults.a_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label))))); else if (ppresults.a_extra_used) aout_emit(aout_create_expr(ppresults.a_extra)); } fprintf(stderr, "\n"); break; case type_label: // Handle label definition. fprintf(stderr, ":%s\n", line->label->name); aout_emit(aout_create_label(line->label->name)); break; } }
void section_write_elf(Elf *e, struct sect *sect, struct buffer *shstrtab_buf) { unsigned i; struct buffer buf; Elf_Scn *scn; Elf_Data *data; Elf32_Shdr *shdr; buffer_init(&buf); for (i = 0; i < sect->size; i++) { if (sect->type == SECT_XLATE) { buffer_write(&buf, sect->data[i].type, 1); switch (sect->data[i].type) { case TYPE_ALIGN: buffer_write(&buf, sect->data[i].size, 1); break; case TYPE_SIZE: { struct reloc_info size = expr_evaluate(sect->data[i].raw); if (size.symbol != NULL) { eprintf("Cannot relocate function size");; exit(EXIT_FAILURE); } if ((size.intval > (1 << 15)) || (size.intval < 0)) { eprintf("Invalid size %016llx", size.intval); exit(EXIT_FAILURE); } buffer_write(&buf, size.intval, 4); } break; case 0x0: /* nothing to dump for a nop */ break; case 0x1: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); break; case 0x2: buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); break; case 0x4: buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); break; case 0x8: buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0x3: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); break; case 0x5: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); break; case 0x9: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0x6: buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); break; case 0xA: buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0xC: buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0x7: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); break; case 0xB: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0xD: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0xE: buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; case 0xF: buffer_write(&buf, conv_asmop(sect->data[i].op[0].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[1].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[2].op, sect->name, buf.pos), 4); buffer_write(&buf, conv_asmop(sect->data[i].op[3].op, sect->name, buf.pos), 4); break; default: eprintf("Invalid type for translated section"); exit(EXIT_FAILURE); } } else if (sect->type == SECT_ZERO) { unsigned j; switch (sect->data[i].type) { case TYPE_ALIGN: case TYPE_ZERO: for (j = 0; j < sect->data[i].size; j++) { buffer_write(&buf, 0, 1); } break; case TYPE_RAW: { struct reloc_info raw = expr_evaluate(sect->data[i].raw); if (raw.symbol != NULL) { eprintf("Cannot relocate in zero section"); exit(EXIT_FAILURE); } if (raw.intval != 0) { eprintf("Cannot put non-zero data in zero section"); exit(EXIT_FAILURE); } buffer_write(&buf, raw.intval, sect->data[i].size); } break; default: eprintf("Invalid type for zero section"); exit(EXIT_FAILURE); } } else { unsigned j; switch (sect->data[i].type) { case TYPE_ALIGN: case TYPE_ZERO: for (j = 0; j < sect->data[i].size; j++) { buffer_write(&buf, 0, 1); } break; case TYPE_RAW: { struct reloc_info raw = expr_evaluate(sect->data[i].raw); if (raw.symbol != NULL) { if (sect->data[i].size != 4) { eprintf("Invalid size for relocated data: %d", sect->data[i].size); exit(EXIT_FAILURE); } sym_addreloc(raw.symbol, sect->name, buf.pos, R_LEMBERG_FULL, raw.intval); buffer_write(&buf, 0, sect->data[i].size); } else { buffer_write(&buf, raw.intval, sect->data[i].size); } } break; default: eprintf("Invalid type for raw section"); exit(EXIT_FAILURE); } } } scn = xelf_newscn(e); shdr = xelf32_getshdr(scn); shdr->sh_name = shstrtab_buf->pos; buffer_writestr(shstrtab_buf, sect->name); switch (sect->type) { case SECT_XLATE: shdr->sh_type = SHT_PROGBITS; shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR | SHF_OS_NONCONFORMING; shdr->sh_info = sect->pos; break; case SECT_ZERO: shdr->sh_type = SHT_NOBITS; shdr->sh_flags = SHF_WRITE | SHF_ALLOC; break; case SECT_RAW: shdr->sh_type = SHT_PROGBITS; shdr->sh_flags = SHF_WRITE | SHF_ALLOC; break; default: eprintf("Unknown section type"); exit(EXIT_FAILURE); } data = xelf_newdata(scn); data->d_align = sect->align; data->d_off = 0; data->d_type = ELF_T_BYTE; data->d_version = EV_CURRENT; data->d_buf = buf.data; data->d_size = buf.pos; }
Elf_Scn *symtab_write_elf(Elf *e, struct sect * sects, struct buffer *strtab_buf, struct buffer *shstrtab_buf) { unsigned i, k; struct sym_info *sym; Elf32_Sym esym; Elf_Scn *scn, *relscn, *tmpscn; Elf_Data *data, *reldata; Elf32_Shdr *shdr, *relshdr; struct buffer buf; struct buffer *relbuf; struct sect *s; buffer_init(&buf); esym.st_name = 0; esym.st_value = 0; esym.st_size = 0; esym.st_info = 0; esym.st_other = 0; esym.st_shndx = 0; buffer_writemem(&buf, &esym, sizeof(esym)); relbuf = malloc(0); for (s = sects, k = 0; s != NULL; s = s->next, k++) { relbuf = realloc(relbuf, (k+1)*sizeof(struct buffer)); buffer_init(&relbuf[k]); } for (i = 0; i < SYMTAB_SIZE; i++) { for (sym = symtab[i]; sym != NULL; sym = sym->next) { if (sym->symbol[0] != '.' || sym->relocs != NULL) { struct reloc_info size; int type = STT_NOTYPE; int bind = STB_LOCAL; if (!sym->defined || sym->bind == SYM_BIND_GLOBAL) { bind = STB_GLOBAL; } esym.st_name = strtab_buf->pos; buffer_writestr(strtab_buf, sym->symbol); esym.st_value = sym->addr; size = expr_evaluate(sym->size); if (size.symbol != NULL) { eprintf("Cannot relocate symbol size"); exit(EXIT_FAILURE); } esym.st_size = size.intval; if (strcmp(sym->type, "@function") == 0) type = STT_FUNC; if (strcmp(sym->type, "@object") == 0) type = STT_OBJECT; esym.st_info = ELF32_ST_INFO(bind, type); esym.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT); tmpscn = section_find(e, sym->section, shstrtab_buf); if (tmpscn == NULL && sym->section != NULL) tmpscn = section_find(e, pile_name(pile_match(sym->section)), shstrtab_buf); esym.st_shndx = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; if (sym->relocs != NULL) { struct sym_reloc_info *r; for (r = sym->relocs; r != NULL; r = r->next) { Elf32_Rela rel; rel.r_offset = r->addr; rel.r_info = ELF32_R_INFO(buf.pos/sizeof(esym), r->type); rel.r_addend = r->addend; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (strcmp(s->name, r->sect) == 0) { buffer_writemem(&relbuf[k], &rel, sizeof(rel)); } } } } buffer_writemem(&buf, &esym, sizeof(esym)); } } } scn = xelf_newscn(e); shdr = xelf32_getshdr(scn); shdr->sh_name = shstrtab_buf->pos; buffer_writestr(shstrtab_buf, ".symtab"); shdr->sh_type = SHT_SYMTAB; shdr->sh_flags = 0; data = xelf_newdata(scn); data->d_align = 4; data->d_off = 0; data->d_type = ELF_T_SYM; data->d_version = EV_CURRENT; data->d_buf = buf.data; data->d_size = buf.pos; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (relbuf[k].pos > 0) { char *relname; relscn = xelf_newscn(e); relshdr = xelf32_getshdr(relscn); relshdr->sh_name = shstrtab_buf->pos; relname = malloc(strlen(s->name)+6); strcpy(relname, ".rela"); strcat(relname, s->name); buffer_writestr(shstrtab_buf, relname); relshdr->sh_type = SHT_RELA; shdr->sh_flags = 0; reldata = xelf_newdata(relscn); reldata->d_align = 4; reldata->d_off = 0; reldata->d_type = ELF_T_RELA; reldata->d_version = EV_CURRENT; reldata->d_buf = relbuf[k].data; reldata->d_size = relbuf[k].pos; relshdr->sh_link = elf_ndxscn(scn); tmpscn = section_find(e, s->name, shstrtab_buf); relshdr->sh_info = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; } } return scn; }
void process_line(struct ast_node_line* line) { struct instruction_mapping* insttype; struct process_parameters_results ppresults; struct process_parameter_results dparam; struct ast_node_parameter* dcurrent; uint32_t dchrproc; uint16_t i, flimit, fchar, opos; struct aout_byte* result = NULL; struct dbg_sym* newsym; // Change depending on the type of line. switch (line->type) { case type_keyword: switch (line->keyword) { case SYMBOL: printd(LEVEL_VERBOSE, ".SYMBOL %s", bstr2cstr(line->keyword_data_string, '0')); // Emit debugging symbol. list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_STRING, dbgfmt_create_symbol_string(line->keyword_data_string, DBGFMT_UNDETERMINED))); break; case SECTION: printd(LEVEL_VERBOSE, ".SECTION %s", bstr2cstr(line->keyword_data_string, '0')); // Emit section metadata. aout_emit(aout_create_metadata_section(bstr2cstr(line->keyword_data_string, '0'))); break; case OUTPUT: printd(LEVEL_VERBOSE, ".OUTPUT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit output metadata. aout_emit(aout_create_metadata_output(bstr2cstr(line->keyword_data_string, '0'))); break; case BOUNDARY: printd(LEVEL_VERBOSE, ".BOUNDARY"); // Emit safety boundary of 16 NULL words. for (i = 0; i < 16; i += 1) aout_emit(aout_create_raw(0)); break; case FILL: printd(LEVEL_VERBOSE, ".FILL"); if (line->keyword_data_expr_1 == NULL || line->keyword_data_expr_2 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } // Emit N words with value X flimit = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); fchar = expr_evaluate(line->keyword_data_expr_2, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); for (i = 0; i < flimit; i++) aout_emit(aout_create_raw(fchar)); break; case EXTENSION: printd(LEVEL_VERBOSE, ".EXTENSION %s", bstr2cstr(line->keyword_data_string, '0')); // Emit extension metadata. aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0'))); break; case INCBIN: printd(LEVEL_VERBOSE, ".INCBIN %s", bstr2cstr(line->keyword_data_string, '0')); // Emit binary include metadata. aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0'))); break; case ORIGIN: if (line->keyword_data_expr_1 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); printd(LEVEL_VERBOSE, ".ORIGIN 0x%04X", opos); // Emit origin set metadata. aout_emit(aout_create_metadata_origin(opos)); break; case SEEK: if (line->keyword_data_expr_1 == NULL) { if (line->keyword_data_string != NULL) dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, line->keyword_data_string->data); else dhalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, ""); } opos = expr_evaluate(line->keyword_data_expr_1, &dhalt_label_resolution_not_permitted, &dhalt_expression_exit_handler); printd(LEVEL_VERBOSE, ".SEEK 0x%04X", opos); // Emit seek metadata. aout_emit(aout_create_metadata_seek(opos)); break; case EXPORT: printd(LEVEL_VERBOSE, ".EXPORT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit export metadata. aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0'))); break; case IMPORT: printd(LEVEL_VERBOSE, ".IMPORT %s", bstr2cstr(line->keyword_data_string, '0')); // Emit import metadata. aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0'))); break; case IMPORT_OPTIONAL: printd(LEVEL_VERBOSE, ".IMPORT OPTIONAL %s", bstr2cstr(line->keyword_data_string, '0')); // Emit import metadata. aout_emit(aout_create_metadata_import_optional(bstr2cstr(line->keyword_data_string, '0'))); break; case JUMP: if (line->keyword_data_string == NULL) printd(LEVEL_VERBOSE, ".JUMP <table>"); else printd(LEVEL_VERBOSE, ".JUMP %s", bstr2cstr(line->keyword_data_string, '0')); // Emit jump metadata. if (line->keyword_data_string == NULL) aout_emit(aout_create_metadata_jump(NULL)); else aout_emit(aout_create_metadata_jump(bstr2cstr(line->keyword_data_string, '0'))); break; default: printd(LEVEL_VERBOSE, "?? UNKNOWN KEYWORD\n"); dhalt(ERR_UNSUPPORTED_KEYWORD, NULL); } printd(LEVEL_VERBOSE, "\n"); break; case type_instruction: // Check to see if this is DAT. if (strcmp(line->instruction->instruction, "DAT") == 0) { // Handle data. printd(LEVEL_VERBOSE, "EMIT DAT"); // Process parameters as data. reverse_parameters(line->instruction->parameters); dcurrent = line->instruction->parameters->last; while (dcurrent != NULL) { // Process parameter normally. dparam = process_parameter(dcurrent); // Output depending on what kind of parameter it was. if (dparam.v_label != NULL) // If this is a label, output something that we need to replace. aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label))))); else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it. { printd(LEVEL_VERBOSE, " \"%s\"", dparam.v_raw->data); for (dchrproc = 0; dchrproc < (uint32_t)blength(dparam.v_raw); dchrproc++) aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc])); } else if (dparam.v_extra_used == true) // Just a single address. aout_emit(aout_create_expr(dparam.v_extra)); else // Something that isn't handled by DAT. { printd(LEVEL_VERBOSE, "\n"); dhalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL); } dcurrent = dcurrent->prev; } } else { // Handle instruction. insttype = get_instruction_by_name(line->instruction->instruction); if (insttype == NULL) dhalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction); printd(LEVEL_VERBOSE, "EMIT %s", insttype->name); // Check parameter count. if (line->instruction->parameters == NULL && strcmp(line->instruction->instruction, "RFI") == 0) { // Handle RFI (which can accept no parameters). result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, 0x21 /* 0 literal */)); printd(LEVEL_VERBOSE, "\n"); break; } else if (line->instruction->parameters == NULL) { // Halt and error. dhalt(ERR_INVALID_PARAMETER_COUNT, NULL); } // Process parameters normally. ppresults = process_parameters(line->instruction->parameters); // Force the parameter value to be NXT if it's a label. if (ppresults.a_label != NULL) ppresults.a = NXT_LIT; if (ppresults.b_label != NULL) ppresults.b = NXT_LIT; if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT; if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT; // Check for relative addressing. if ((insttype->opcode == OP_ADD || insttype->opcode == OP_SUB || insttype->opcode == OP_MUL || insttype->opcode == OP_DIV) && ppresults.a == PC) { // Warn about relative addressing portability. dwarn(WARN_RELATIVE_PC_ADDRESSING, NULL); } // Output the initial opcode. if (insttype->opcode != OP_NONBASIC) result = aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b)); else result = aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a)); // If the parameter is a label or requires an extra word, output them. if (ppresults.b_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label))))); else if (ppresults.b_extra_used) aout_emit(aout_create_expr(ppresults.b_extra)); if (ppresults.a_label != NULL) aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label))))); else if (ppresults.a_extra_used) aout_emit(aout_create_expr(ppresults.a_extra)); } printd(LEVEL_VERBOSE, "\n"); break; case type_label: // Handle label definition. list_append(&newsyms, dbgfmt_create_symbol(DBGFMT_SYMBOL_LABEL, dbgfmt_create_symbol_label(bfromcstr(line->label->name), DBGFMT_UNDETERMINED))); printd(LEVEL_VERBOSE, ":%s\n", line->label->name); aout_emit(aout_create_label(line->label->name)); break; default: assert(false); } // If we can associate debugging symbols with this instruction... if (result != NULL) { // While the new symbols list is not empty, copy those symbols // into the output and associate. while (list_size(&newsyms) > 0) { newsym = list_extract_at(&newsyms, 0); printd(LEVEL_DEBUG, "Debugging custom symbol: %i\n", newsym->length); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); } // If the line information is provided, output // debugging symbols. if (line != NULL && line->file != NULL) { // Output a file / line number debugging symbol here. newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->file, line->line, DBGFMT_UNDETERMINED)); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); printd(LEVEL_DEBUG, "Debugging symbol: %i %s\n", line->line, line->file->data); } // If the higher-language line information is // provided, output debugging symbols. if (line != NULL && line->ufile != NULL) { // Output a file / line number debugging symbol here. newsym = dbgfmt_create_symbol(DBGFMT_SYMBOL_LINE, dbgfmt_create_symbol_line(line->ufile, line->uline, DBGFMT_UNDETERMINED)); list_append(&result->symbols, newsym); list_append(assem_dbg_symbols, newsym); printd(LEVEL_DEBUG, "High-level debugging symbol: %i %s\n", line->uline, line->ufile->data); } } }
uint16_t aout_write(FILE* out, bool relocatable, bool intermediate) { struct aout_byte* current_outer; struct aout_byte* current_inner; struct lprov_entry* linker_provided = NULL; struct lprov_entry* linker_required = NULL; struct lprov_entry* linker_adjustment = NULL; struct lprov_entry* linker_section = NULL; struct lprov_entry* linker_output = NULL; struct lprov_entry* linker_temp = NULL; uint32_t mem_index, out_index; uint16_t inst; BFILE* temp = NULL; bstring bname, ename; uint16_t eaddr; bool did_find; bool shown_expr_warning = false; bool has_output = false; // Initialize out our extension table. code_offset += textn_init(start); // If relocatable, initialize out our relocation table. if (relocatable) code_offset += treloc_init(start); // First go through and evaluate all expressions that need to be. current_outer = start; out_index = code_offset; while (current_outer != NULL) { if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN) { // Adjust memory address. out_index = current_outer->opcode; } else if (current_outer->type == AOUT_TYPE_METADATA_SECTION) { assert(current_outer->label != NULL); // We're exporting the current address as the beginning // of a section. if (!intermediate) ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL); // Check to make sure outputs haven't previously been emitted. if (has_output) ahalt(ERR_OUTPUT_BEFORE_SECTION, NULL); // Create linker entry. linker_temp = lprov_create(current_outer->label, out_index); linker_temp->next = linker_section; linker_section = linker_temp; printd(LEVEL_VERBOSE, "LINK SECTION %s -> 0x%04X\n", current_outer->label, out_index); } else if (current_outer->type == AOUT_TYPE_METADATA_OUTPUT) { assert(current_outer->label != NULL); // We're exporting the current address as the beginning // of a section. if (!intermediate) ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL); // Create linker entry. has_output = true; linker_temp = lprov_create(current_outer->label, out_index); linker_temp->next = linker_output; linker_output = linker_temp; printd(LEVEL_VERBOSE, "LINK OUTPUT 0x%04X -> %s\n", out_index, current_outer->label); } else if (current_outer->type == AOUT_TYPE_METADATA_EXPORT) { assert(current_outer->label != NULL); // We're exporting the address of this label in the // object table. if (!intermediate) ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL); // Resolve label position. ename = bfromcstr(current_outer->label); eaddr = aout_get_label_address(ename); bdestroy(ename); // Create linker entry. linker_temp = lprov_create(current_outer->label, eaddr); linker_temp->next = linker_provided; linker_provided = linker_temp; printd(LEVEL_VERBOSE, "LINK REPLACE %s -> 0x%04X\n", current_outer->label, eaddr); } else if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->expr != NULL) { if (current_outer->expr->type != EXPR_LABEL) { // This is either just a number or a more complicated expression, so // evaluate it using the preprocessor expression engine. if ((relocatable || intermediate) && !shown_expr_warning) { printd(LEVEL_WARNING, "warning: expressions will not be adjusted at link or relocation time.\n"); printd(LEVEL_WARNING, " ensure labels are not used as part of expressions.\n"); shown_expr_warning = true; } current_outer->raw_used = true; current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler); expr_delete(current_outer->expr); current_outer->expr = NULL; } else { // If this is just a label, we can handle it directly (this allows // us to handle imported labels in intermediate code). current_inner = start; mem_index = code_offset; did_find = false; // Search for .IMPORT directives first. while (current_inner != NULL) { if (current_inner->type == AOUT_TYPE_METADATA_ORIGIN) { // Adjust memory address. mem_index = current_inner->opcode; } else if (current_inner->type == AOUT_TYPE_METADATA_IMPORT) { // An imported label (we don't need to adjust // memory index because the existance of this type // of entry doesn't affect executable size). if (!intermediate) ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL); assert(current_outer->expr->data != NULL); if (strcmp(current_inner->label, ((bstring)current_outer->expr->data)->data) == 0) { // We don't actually know our position yet; // that will be handled by the linker! current_outer->raw = 0xFFFF; expr_delete(current_outer->expr); current_outer->expr = NULL; linker_temp = lprov_create(current_inner->label, out_index); linker_temp->next = linker_required; linker_required = linker_temp; printd(LEVEL_VERBOSE, "LINK REPLACE 0x%04X -> %s\n", out_index, current_inner->label); did_find = true; break; } } // Goto next. current_inner = current_inner->next; } // If it wasn't found in the .IMPORT directives, try searching // labels directly using the expression engine. if (!did_find) { // Replace the label position. current_outer->raw_used = true; current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler); expr_delete(current_outer->expr); current_outer->expr = NULL; did_find = true; // We also need to add this entry to the adjustment // table for the linker since it also needs to adjust // internal label jumps in files when it concatenates // all of the object code together. linker_temp = lprov_create(NULL, out_index); linker_temp->next = linker_adjustment; linker_adjustment = linker_temp; printd(LEVEL_VERBOSE, "LINK ADJUST 0x%04X\n", out_index); } } } if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->label == NULL) out_index += 1; current_outer = current_outer->next; } // If intermediate, we need to write out our linker table // as the absolute first thing in the file. if (intermediate) { fwrite(ldata_objfmt, 1, strlen(ldata_objfmt) + 1, out); objfile_save(out, linker_provided, linker_required, linker_adjustment, linker_section, linker_output); // Adjust the "true origin" for .ORIGIN directivies because // the linker table won't exist in the final result when // linked. true_origin = (uint16_t)ftell(out); } // Write out our extension table. textn_write(out); // If relocatable, write out our relocation table. if (relocatable) treloc_write(out); // Now write to the file. current_outer = start; while (current_outer != NULL) { if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN) { // Adjust origin. fseek(out, true_origin + current_outer->opcode * 2 /* double because the number is in words, not bytes */, SEEK_SET); } else if (current_outer->type == AOUT_TYPE_METADATA_INCBIN) { // Include binary file. bname = ppfind_locate(bautofree(bfromcstr(current_outer->label))); if (bname == NULL) ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label); temp = bfopen((const char*)(bname->data), "rb"); if (temp == NULL) ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label); // Copy binary data. while (!bfeof(temp)) { // TODO: This could be faster if we didn't do it character // by character. fputc(bfgetc(temp), out); } // Finalize. bfclose(temp); bdestroy(bname); } else if (current_outer->type == AOUT_TYPE_NORMAL) { // Update the debugging symbol. dbgfmt_update_symbol_list(¤t_outer->symbols, (uint16_t)((ftell(out) - true_origin) / 2)); // Normal output. if (current_outer->raw_used == true) { inst = current_outer->raw; iwrite(&inst, out); } else if (current_outer->label == NULL) { inst = INSTRUCTION_CREATE(current_outer->opcode, current_outer->a, current_outer->b); iwrite(&inst, out); } } // Goto next in linked list. current_outer = current_outer->next; } fflush(out); return (uint16_t)((ftell(out) - true_origin) / 2); }