/* Writes instructions during the assembler's first pass to OUTPUT. The case for general instructions has already been completed, but you need to write code to translate the li and other pseudoinstructions. Your pseudoinstruction expansions should not have any side effects. NAME is the name of the instruction, ARGS is an array of the arguments, and NUM_ARGS specifies the number of items in ARGS. Error checking for regular instructions are done in pass two. However, for pseudoinstructions, you must make sure that ARGS contains the correct number of arguments. You do NOT need to check whether the registers / label are valid, since that will be checked in part two. Also for li: - make sure that the number is representable by 32 bits. (Hint: the number can be both signed or unsigned). - if the immediate can fit in the imm field of an addiu instruction, then expand li into a single addiu instruction. Otherwise, expand it into a lui-ori pair. For mul, quo, and rem, the expansions should be pretty straight forward if you paid attention to the lecture slides about the subtleties of $hi and $lo registers. MARS has slightly different translation rules for li, and it allows numbers larger than the largest 32 bit number to be loaded with li. You should follow the above rules if MARS behaves differently. Use fprintf() to write. If writing multiple instructions, make sure that each instruction is on a different line. Returns the number of instructions written (so 0 if there were any errors). */ unsigned write_pass_one(FILE* output, const char* name, char** args, int num_args) { if (strcmp(name, "li") == 0) { /* YOUR CODE HERE */ long int imm; if (translate_num(&imm, args[1], INT32_MIN, UINT32_MAX) == -1) { fprintf(stderr, "%s Number is more than 32 bits. \n", args[1]); return 0; } int err = translate_num(&imm, args[1], INT16_MIN, INT16_MAX); if (err == 0) { printf("optimization \n"); fprintf(output, "addiu %s $0 %s\n", args[0], args[1]); return 1; } else { //lui int upper = imm >> 16; fprintf(output, "lui $at %d\n", upper); // ori int lower; lower = imm & 0xffff; fprintf(output, "ori %s $at %d\n", args[0], lower); return 2; } } else if (strcmp(name, "mul") == 0) {
int main(int argc, char **argv) { freopen("null", "w", stderr); //Uncomment to show stderr. //TEST translate_num char num[] = "0x6fffff"; long int result = 0; int flag; //nornmal test. flag = translate_num(&result, num, 0, 999999999); assert(7340031 == result); assert(flag == 0); //out of bound. flag = translate_num(&result, num, 1, 2); assert(7340031 == result); assert(flag == -1); //invalid output pointer. flag = translate_num(NULL, num, 0, 999999999); assert(flag == -1); printf("PASSED: translate_num.\n"); //TEST add_to_table //uniqueTable: //tim1 4 //tim2 8 //tim3 12 //tim4 16 //tim5 20 //tim6 24 char* tim1 = "tim1"; char* tim2 = "tim2"; char* tim3 = "tim3"; char* tim4 = "tim4"; char* tim5 = "tim5"; char* tim6 = "tim6"; SymbolTable * uniqueTable = create_table(SYMTBL_UNIQUE_NAME); add_to_table(uniqueTable, tim1, 4); add_to_table(uniqueTable, tim2, 8); add_to_table(uniqueTable, tim3, 12); add_to_table(uniqueTable, tim4, 16); //normal. flag = add_to_table(uniqueTable, tim5, 20); assert(uniqueTable->len == 5); //name duplicate. flag = add_to_table(uniqueTable, tim5, 20); assert(flag == -1); //address not aligned. flag = add_to_table(uniqueTable, tim6, 1); assert(flag == -1); printf("2 expected errors are supressed above.\n"); printf("Uncomment line 19 to see error msg.\n"); flag = add_to_table(uniqueTable, tim6, 24); assert(uniqueTable->len == 6); assert(uniqueTable->cap == 10); //RUNNING valGrind here to expect a memory leak. // ./run-valgrind ./mytest printf("PASSED: add_to_table.\n"); //TEST free_table free_table(uniqueTable); //RUNNING valGrind here to expect the memory leak is fixed. // ./run-valgrind ./mytest printf("PASSED: free_table.\n"); // long int output; printf("%d\n", translate_num(&output, "35x", -100, 100)); printf("%ld\n", output); return 0; }