/* Reads STR and determines whether it is a label (ends in ':'), and if so, whether it is a valid label, and then tries to add it to the symbol table. INPUT_LINE is which line of the input file we are currently processing. Note that the first line is line 1 and that empty lines are included in this count. BYTE_OFFSET is the offset of the NEXT instruction (should it exist). Four scenarios can happen: 1. STR is not a label (does not end in ':'). Returns 0. 2. STR ends in ':', but is not a valid label. Returns -1. 3a. STR ends in ':' and is a valid label. Addition to symbol table fails. Returns -1. 3b. STR ends in ':' and is a valid label. Addition to symbol table succeeds. Returns 1. */ static int add_if_label(uint32_t input_line, char* str, uint32_t byte_offset, SymbolTable* symtbl) { size_t len = strlen(str); if (str[len - 1] == ':') { str[len - 1] = '\0'; if (is_valid_label(str)) { if (add_to_table(symtbl, str, byte_offset) == 0) { return 1; } else { return -1; } } else { raise_label_error(input_line, str); 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; }