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