The goal of Pass 1 in the assembler is to process the source code and gather the necessary information for later stages. This includes:
Reading the source code: The assembler reads the code line by line.
Handling assembler directives: Directives like START are processed to determine the starting address of the program.
Processing labels: Labels, which mark specific locations in the code, are identified and processed.
Building the symbol table: The assembler creates a symbol table that stores labels and their corresponding addresses or values.
Handling variables and constants: Variables are allocated memory, and constants are assigned values.
Creating intermediate code: The assembler generates a simplified version of the code, called intermediate code, which is easier to process in later passes.
Note: Pass 1 prepares the program by translating assembly language into a basic form (intermediate code). In Pass 2, the assembler uses this intermediate code to generate the final object code.
Symbol Table:
Stores labels (like variables and functions) and their corresponding memory addresses or values.
It's often implemented as a hash table where labels are the keys, and addresses/values are the values.
Intermediate Code:
A simplified version of the source code that is easier for the assembler to work with.
It’s typically stored as a list or array where each item represents a line of code with its opcode and operands.
begin
read first input line
if OPCODE ='START' then
begin
save #[OPERAND] as starting address
initialize LOCCTR to starting address
write line to intermediate file
read next input line
end {if START}
else
initialize LOCCTR to 0
while OCODE != 'END' do
begin
if this is not a comment line then
begin
if there is a symbol in the LABEL field then
begin
search SYMTAB for LABEL
if found then
set error flag (duplicate symbol)
else
insert (LABEL,LOCCTR) into SYMTAB
end {if symbol}
search OPTAB for OPCODE
if found then
add 3 {instruction length} to LOCCTR
else if OPCODE='WORD' then
add 3 to LOCCTR
else if OPCODE = 'RESW' then
add 3 * #[OPERAND] to LOCCTR
else if OPCODE = 'RESB' then
add #[OPERAND] to LOCCTR
else if OPCODE = 'BYTE' then
begin
find length of constant in bytes
add length to LOCCTR
end {if BYTE}
else
set error flag (invalid operation code)
end {if not a comment}
write line to intermediate file
read next input line
end {while not END}
write last line to intermediate file
save (LOCCTR – starting address) as program length
end {Pass 1}
input.txt -
COPY START 1000
- +LDA ALPHA
- ADD #1
- DIV #2
- STA BETA
- SUB #4
- STA GAMMA
- +LDA GAMMA
- ADD #2
- +LDA BETA
ALPHA BYTE C'COF'
BETA RESW 2
GAMMA RESW 2
- END 1000
optab.txt -
DIV 06
SUB 05
CMP 03
LDA 00
STA 23
ADD 01
JNC 08
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char *decimalToHex(int decimal) {
static char hex_string[10];
sprintf(hex_string, "%X", decimal);
return hex_string;
}
int main() {
printf("PASS 1\n");
char str;
char saved_labels[20][20];
int saved_labels_index = 0;
char label[20], opcode[20], operand[20];
char optab_opcode[10], machine_code[10];
int starting_address, location_counter;
bool opcode_found = false;
FILE *input_file, *optab_file, *symtab_file, *output_file;
input_file = fopen("input.txt", "r");
optab_file = fopen("optab.txt", "r");
symtab_file = fopen("symtab.txt", "w+");
output_file = fopen("intermediate.txt", "w");
if (input_file == NULL || optab_file == NULL || symtab_file == NULL || output_file == NULL) {
printf("Error! opening file");
exit(1);
} else {
printf("All file opened successfully\n");
}
fscanf(input_file, "%s %s %s", label, opcode, operand);
if (strcmp(opcode, "START") == 0) {
starting_address = strtol(operand, NULL, 16);
location_counter = starting_address;
} else {
location_counter = 0;
starting_address = 0;
}
printf("\nIntermidia File:\n\n");
fprintf(output_file, "%s\t%s\t%s\t%s\n", "-", label, opcode, operand);
printf("%s\t%s\t%s\t%s\n", "-", label, opcode, operand);
fscanf(input_file, "%s %s %s", label, opcode, operand);
while (strcmp(opcode, "END") != 0) {
if (strcmp(label, "-") != 0) {
for (int i = 0; i < 10; i++) {
if (strcmp(saved_labels[i], label) == 0) {
printf("Error! Duplicate label: %s found at line %d\n", label, i + 1);
exit(1);
}
}
strcpy(saved_labels[saved_labels_index], label);
saved_labels_index++;
fprintf(symtab_file, "%s\t%s\n", label, decimalToHex(location_counter));
}
rewind(optab_file);
opcode_found = false;
fscanf(optab_file, "%s %s", optab_opcode, machine_code);
while (!feof(optab_file)) {
if (strcmp(optab_opcode, opcode) == 0) {
opcode_found = true;
break;
}
fscanf(optab_file, "%s %s", optab_opcode, machine_code);
}
fprintf(output_file, "%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
printf("%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
if (opcode_found) {
location_counter += 3;
} else if (strcmp(opcode, "BYTE") == 0) {
location_counter += strlen(operand) - 3;
} else if (strcmp(opcode, "RESB") == 0) {
location_counter += atoi(operand);
} else if (strcmp(opcode, "WORD") == 0) {
location_counter += 3;
} else if (strcmp(opcode, "RESW") == 0) {
location_counter += 3 * atoi(operand);
} else {
printf("Error! Invalid opcode\n");
printf("opcode: %s\n", opcode);
exit(1);
}
fscanf(input_file, "%s %s %s", label, opcode, operand);
}
fprintf(output_file, "%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
printf("%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
printf("\nSize of the program: %s\n", decimalToHex(location_counter - starting_address));
printf("\n\nThe contents of Symbol Table :\n\n");
fclose(input_file);
fclose(optab_file);
fclose(symtab_file);
fclose(output_file);
symtab_file = fopen("symtab.txt", "r");
str = fgetc(symtab_file);
while (str != EOF) {
printf("%c", str);
str = fgetc(symtab_file);
}
fclose(symtab_file);
return 0;
}