示例#1
0
/* 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;
    }
}
示例#2
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;
}