0% found this document useful (0 votes)
7 views7 pages

SPCC 7

The document outlines the implementation of a two-pass assembler, which translates assembly language code into machine code. The first pass creates a symbol table with labels and their addresses, while the second pass resolves these labels and generates the corresponding machine code. The program includes detailed functions for each pass and demonstrates the assembler's operation through code examples.

Uploaded by

Jeet Rathod
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views7 pages

SPCC 7

The document outlines the implementation of a two-pass assembler, which translates assembly language code into machine code. The first pass creates a symbol table with labels and their addresses, while the second pass resolves these labels and generates the corresponding machine code. The program includes detailed functions for each pass and demonstrates the assembler's operation through code examples.

Uploaded by

Jeet Rathod
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Experiment No.

7
Roll no.:B-632

Aim : Program to implement two pass Assembler


Theory:
Two-Pass Assembler
Introduction to Assemblers
An assembler is a program that translates assembly language code into machine code that a computer
can execute. Assembly language is a low-level programming language that is closer to machine code
but more readable for humans. The translation process is typically done in two phases (or passes) to
handle labels and addresses efficiently.

The Two-Pass Process

A two-pass assembler works by reading the assembly code twice to generate the correct machine code:

1. First Pass: Building the Symbol Table


• The first pass processes the assembly code to build a symbol table. This table holds labels
(or symbols) and their corresponding addresses.
• In the first pass, the assembler does not yet generate machine code for the instructions.
Instead, it scans the code to identify labels and their locations in memory.
• Labels are identifiers in the code that represent addresses or locations within the program
(e.g., START:, LOOP:).
• The assembler records the address of each label as it scans through the code, associating
each label with the line number or memory location at which it occurs.
2. Second Pass: Resolving Labels and Generating Machine Code
• In the second pass, the assembler processes the code again, but this time, it generates the
final machine code.
• The assembler replaces labels in the instructions with their corresponding memory
addresses from the symbol table.
• Each instruction is converted into machine code, which consists of an opcode and an
operand. The opcode specifies the operation (e.g., ADD, SUB), and the operand
specifies the value or address the operation will use.
• In this phase, the assembler also generates the final output, which might include binary
machine code or a human-readable representation of the instructions.
Detailed Process:

1. First Pass:
• The first pass goes through each line of the assembly code:
• If a label is found (e.g., START: MOV 5), the assembler records the label and its memory
address (or line number).
• If an instruction is found (e.g., MOV 5), the assembler processes it but does not generate
machine code yet. It simply moves to the next instruction.
The main objective of the first pass is to gather all the labels and store their corresponding addresses.
At the end of the first pass, the symbol table will contain all the labels and their addresses.

Output of First Pass:


• A symbol table containing labels and their addresses.
• No machine code is generated yet.
2. Second Pass
• In the second pass, the assembler goes through the instructions again:
• It checks each instruction for any operands that refer to labels.
• It looks up the label in the symbol table and replaces it with the corresponding address.
• It then generates the machine code for the instruction, which consists of the opcode
(numeric representation) and the operand (either a value or address).
At the end of the second pass, the assembler generates a list of machine instructions that can be executed
by the computer.

Output of Second Pass:


• A sequence of machine instructions (e.g., opcode and operand values).
• All labels are replaced with actual memory addresses.
Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void chk_label();
void chk_opcode();
void READ_LINE();
void PASS1();
void PASS2();

void my_itoa(int num, char* str, int base) {


sprintf(str, "%d", num);
}

struct optab {
char code[10], objcode[10];
} myoptab[3] = {
{"LDA", "00"},
{"JMP", "01"},
{"STA", "02"}
};

struct symtab {
char symbol[10];
int addr;
} mysymtab[10];

int startaddr, locctr, symcount = 0, length;


char line[20], label[8], opcode[8], operand[8], programname[10];
PASS1: First Pass of the Assembler
void PASS1() {
FILE *input, *inter;
input = fopen("input.txt", "r");
if (input == NULL) {
printf("Error: Cannot open input.txt\n");
exit(1);
}

inter = fopen("inter.txt", "w");


if (inter == NULL) {
printf("Error: Cannot create inter.txt\n");
fclose(input);
exit(1);
}

printf("LOCATION LABEL\tOPERAND\tOPCODE\n");
printf("____________________________________\n");

if (fgets(line, 20, input) == NULL) {


printf("Error: Input file is empty\n");
fclose(input);
fclose(inter);
exit(1);
}

READ_LINE();

if (!strcmp(opcode, "START")) {
startaddr = atoi(operand);
locctr = startaddr;
strcpy(programname, label);

fprintf(inter, "%s", line);


if (fgets(line, 20, input) == NULL) {
strcpy(line, "END");
}
} else {
programname[0] = '\0';
startaddr = 0;
locctr = 0;
}

printf("\n %d\t %s\t%s\t %s", locctr, label, opcode, operand);

while (strcmp(line, "END") != 0 && !feof(input)) {


READ_LINE();
printf("\n %d\t %s \t%s\t %s", locctr, label, opcode, operand);
if (label[0] != '\0')
chk_label();
chk_opcode();
fprintf(inter, "%s %s %s\n", label, opcode, operand);

if (fgets(line, 20, input) == NULL) {


strcpy(line, "END");
}
}

printf("\n %d\t\t%s", locctr, line);


fprintf(inter, "%s", line);

fclose(inter);
fclose(input);
}
PASS2: Second Pass of the Assembler
void PASS2() {
FILE *inter, *output;
char record[30], part[6], value[5];
int currtxtlen = 0, foundopcode, foundoperand, chk, operandaddr, recaddr = 0;
inter = fopen("inter.txt", "r");
if (inter == NULL) {
printf("Error: Cannot open inter.txt\n");
exit(1);
}

output = fopen("output.txt", "w");


if (output == NULL) {
printf("Error: Cannot create output.txt\n");
fclose(inter);
exit(1);
}

if (fgets(line, 20, inter) == NULL) {


printf("Error: Intermediate file is empty\n");
fclose(inter);
fclose(output);
exit(1);
}

READ_LINE();
if (!strcmp(opcode, "START")) {
if (fgets(line, 20, inter) == NULL) {
strcpy(line, "END");
}
}

printf("\n\nCorresponding Object code is..\n");


printf("\nH^ %s ^ %d ^ %d ", programname, startaddr, length);
fprintf(output, "\nH^ %s ^ %d ^ %d ", programname, startaddr, length);
recaddr = startaddr;
record[0] = '\0';

while (strcmp(line, "END") != 0 && !feof(inter)) {


operandaddr = foundoperand = foundopcode = 0;
value[0] = part[0] = '\0';
READ_LINE();

for (chk = 0; chk < 3; chk++) {


if (!strcmp(opcode, myoptab[chk].code)) {
foundopcode = 1;
strcpy(part, myoptab[chk].objcode);
break;
}
}

if (strlen(part) > 0) {
if ((currtxtlen + strlen(part)) <= 8) {
strcat(record, "^");
strcat(record, part);
currtxtlen += strlen(part);
} else {
printf("\nT^ %d ^%d %s", recaddr, currtxtlen, record);
fprintf(output, "\nT^ %d ^%d %s", recaddr, currtxtlen, record);
recaddr += currtxtlen;
currtxtlen = strlen(part);
strcpy(record, "^");
strcat(record, part);
}
}
}

printf("\nE^ %d\n", startaddr);


fprintf(output, "\nE^ %d\n", startaddr);
fclose(inter);
fclose(output);
}
Main Function
int main() {
printf("Starting two-pass assembler...\n");
PASS1();
length = locctr - startaddr;
PASS2();

printf("\nAssembly completed successfully!\n");


printf("Press Enter to continue...");
getchar();

return 0;
}

Output:
Conclusion:
The two-pass assembler is a common technique for translating assembly code into machine code. The
first pass builds a symbol table with labels and addresses, while the second pass resolves the labels to
their addresses and generates the final machine code.

You might also like