/* First pass of the assembler. You should implement pass_two() first. This function should read each line, strip all comments, scan for labels, and pass instructions to write_pass_one(). The input file may or may not be valid. Here are some guidelines: 1. Only one label may be present per line. It must be the first token present. Once you see a label, regardless of whether it is a valid label or invalid label, treat the NEXT token as the beginning of an instruction. 2. If the first token is not a label, treat it as the name of an instruction. 3. Everything after the instruction name should be treated as arguments to that instruction. If there are more than MAX_ARGS arguments, call raise_extra_arg_error() and pass in the first extra argument. Do not write that instruction to the output file (eg. don't call write_pass_one()) 4. Only one instruction should be present per line. You do not need to do anything extra to detect this - it should be handled by guideline 3. 5. A line containing only a label is valid. The address of the label should be the byte offset of the next instruction, regardless of whether there is a next instruction or not. Just like in pass_two(), if the function encounters an error it should NOT exit, but process the entire file and return -1. If no errors were encountered, it should return 0. */ int pass_one(FILE* input, FILE* output, SymbolTable* symtbl) { //my own: setting the buffer and putting the input into it char buf[BUF_SIZE]; fgets(buf, BUF_SIZE, input); //my own: lines start at 1, and the byte offset at 0 uint32_t byte_offset = 0; int line_number = 1; //my own: tokenize by lines first strtok(buf, "\n"); while (strcmp(buf, "") == 0) { line_number++; strtok(buf, "\n"); } int errored = 0; while (buf != NULL) { skip_comment(buf); //myown: gets rid of comments for every line //my own: tokenize now by the args in each line char* args[50]; int num_args = 0; //my own: set it to 50, because... whos stupid enough to put in 50 args in MIPS... only idiots //my own: just have to do this because if the num_args > args size, GG. NO FIT. strtok(buf, " :,\n"); //myown: all the delimiters that could in MIPScode " :, and an new line" num_args = sizeof(args)/sizeof(args[0]); if (num_args > MAX_ARGS) { raise_extra_arg_error(line_number, args[1]); errored++; } int label1 = add_if_label(line_number, args[0], byte_offset, symtbl); int label2 = add_if_label(line_number, args[1], byte_offset, symtbl); if (label1 == -1) { errored++; line_number++; strtok(buf, "\n"); } else if (label2 == 1) { raise_extra_arg_error(line_number, args[1]); errored++; line_number++; strtok(buf, "\n"); } else if (label1 == 0) { //Myown:It's not a label. Treat like a reg instruction //Myown: pass in instructions into write_pass_one write_pass_one(output, args[0], args, num_args); byte_offset += 4; } else if (label1 == 1) { //My own: Adding label to the symbol table add_to_table(symtbl, args[0], byte_offset); byte_offset += 4; } line_number++; strtok(buf, "\n"); } if (errored > 0) { return -1; } else { return 0; } }
/* First pass of the assembler. You should implement pass_two() first. This function should read each line, strip all comments, scan for labels, and pass instructions to write_pass_one(). The input file may or may not be valid. Here are some guidelines: 1. Only one label may be present per line. It must be the first token present. Once you see a label, regardless of whether it is a valid label or invalid label, treat the NEXT token as the beginning of an instruction. 2. If the first token is not a label, treat it as the name of an instruction. 3. Everything after the instruction name should be treated as arguments to that instruction. If there are more than MAX_ARGS arguments, call raise_extra_arg_error() and pass in the first extra argument. Do not write that instruction to the output file (eg. don't call write_pass_one()) 4. Only one instruction should be present per line. You do not need to do anything extra to detect this - it should be handled by guideline 3. 5. A line containing only a label is valid. The address of the label should be the byte offset of the next instruction, regardless of whether there is a next instruction or not. Just like in pass_two(), if the function encounters an error it should NOT exit, but process the entire file and return -1. If no errors were encountered, it should return 0. */ int pass_one(FILE* input, FILE* output, SymbolTable* symtbl) { /* YOUR CODE HERE */ int err = 0; char buf[BUF_SIZE]; uint32_t line_no = 0; uint32_t addr = 0; // label addr while(fgets(buf, BUF_SIZE, input) != NULL) { line_no++; // strip comments skip_comment(buf); if(strlen(buf) == 0) continue; char* args[MAX_ARGS]; int num_args = 0; char nbuf[BUF_SIZE]; // buf for line with no label char instr[BUF_SIZE]; // instruction string char label[BUF_SIZE]; // label string instr[0] = '\0'; label[0] = '\0'; strcpy(nbuf, buf); char * pch; pch = strtok (buf, IGNORE_CHARS); // buf is clobbered if(pch == NULL) continue; strcpy(label, pch); // first pch maybe label int res = add_if_label(line_no, label, addr, symtbl); printf("Label1: %s\n", label); if( res == 0) { label[0] = '\0'; } else { if(res == -1) { err = -2; raise_label_error(line_no, label); } char* tmp = strstr(nbuf, label); strcpy(nbuf, tmp + strlen(label) + 1); printf("Label2: %s\n", label); } printf("nbuf (for instruction) : %s\n", nbuf); pch = strtok (nbuf, IGNORE_CHARS); if(pch != NULL) { strcpy(instr, pch); // first is instruction string pch = strtok (NULL, IGNORE_CHARS); while (pch != NULL) { // following is arguments args[num_args++] = strdup(pch); pch = strtok (NULL, IGNORE_CHARS); if(num_args > MAX_ARGS ) { raise_extra_arg_error(line_no, args[num_args]); err = -3; break; } } #if 0 printf("instr: %s\n", instr); printf("num_args: %d\n", num_args); printf("args:\n"); for(int i = 0; i < num_args; i++) printf("\t %s", args[i]); printf("addr: %d\n", addr); #endif if(err != -3) { int num_instr = write_pass_one(output, instr, args, num_args); addr += 4 * num_instr; printf("addr: %d\n", addr); if( num_instr == 0) { raise_inst_error(line_no, instr, args, num_args); err = -1; } } // free memeory in args for(int i = 0; i < num_args; i++) free(args[i]); } } return err < 0 ? -1 : 0; }