Professional Documents
Culture Documents
SPCC
SPCC
1.EXPERIMENT VISION:
2.OBJECTIVE:
To understand the concept of two pass assembler and construct a program for it.
3.THEORY:
A two-pass assembler makes two passes over the input program. That is, it reads the
program twice. On the first pass, the assembler constructs the symbol table. On the second pass,
the complete symbol table is used to allow expressions to be evaluated without problems due to
forward references. If any symbol is not in the symbol table during an expression evaluation, it is
an error, not a forward reference.
FI
GURE 8.3 A block diagram of a two-pass assembler. Pass 1 produces a symbol table and a copy of the
input source program for pass 2. Pass 2 produces loader code and a listing.
Briefly, for a two-pass assembler, the first pass constructs the symbol table; the second pass
generates object code. This causes a major change in the basic flow of an assembler, and results
in another important data structure: the intermediate text. Since two passes are being made over
the input assembly language, it is necessary to save a copy of the program read for pass 1, to be
used in pass two. Notice that since the assembly listing includes the generated machine language
code, and the machine language code is not produced until pass 2, the assembly listing is not
produced until pass 2. This requires storing the entire input program, including comments, and so
forth, which are not needed by the assembler during pass 2.
The intermediate text can be stored in several ways. The best storage location would be in
main memory. However, since MIX memory is so small, this technique is not possible on the
MIX computer. On other machines, with more memory, this technique is sometimes used for
very small programs. Another approach, used for very small machines, is to simply require the
programmer to read his program into the computer twice, once for pass 1, and again for pass 2. A
PDP-8 assembler has used this approach, even going so far as to require the program be read in a
third time if a listing is desired.
A more common solution is to store the intermediate text on a secondary storage device,
such as tape, drum, or disk. During pass 1, the original program is read in, and copied to
secondary storage as the symbol table is constructed. Between passes, the device is repositioned
(rewound for tapes, or the head moved back to the first track for moving head disk or drum).
During pass 2, the program is read back from secondary storage for object code generation and
printing a listing. (Notice that precautions should be taken that the same tape is not used for both
storage of the intermediate text input for pass 2 and the storage of the object code produced as
output from pass 2 for the loader.)
The general flow of a two-pass assembler differs from that given above, in that now each
card must be processed twice, with different processing on each pass. It is also still necessary to
process each type of card differently, depending upon its opcode type. This applies to both pass 1
and pass 2.
For machine instructions, pass 1 processing involves simply defining the label (if any) and
incrementing the location counter by one. ALF and CON pseudo-instructions are handled in the
same way. ORIG statements must be handled exactly as we described above, however, in order
for the location counter to have the correct value for defining labels. Similarly, EQU statements
must also be treated on pass 1. This means that no matter what approach is used, no forward
references can be allowed in ORIG or EQU statements, since both are processed during pass 1.
The END statement needs to have its label defined and then should jump to pass 2 for further
processing.
During pass 2, EQU statements can be treated as comments. The label field can likewise be
ignored. ALF, CON, and machine instructions will be processed as described above, as will
the END statement.
The need to make two passes over the program can result in considerable duplication in
code and computation during pass 1 and pass 2. For example, on both passes, we need to find the
type of the opcode; on pass 1, to be able to treat ORIG, EQU, and END statements; on pass 2, for all
types. This can result in having to search the opcode table twice for each assembly language
statement. To prevent this, we need only save the index into the opcode table of the opcode (once
it is found during pass 1) with each instruction. Also, consider that since the operand "*" may be
used in the expressions evaluated during pass 2, it is necessary to duplicate during pass 2 the
efforts of pass 1 to define the location counter, unless we can simply store with each assembly
language statement the value of the location counter for that statement.
These considerations can result in extending the definition of the intermediate text to be
more than simply the input to pass 1. Each input assembly language statement can be a record
containing (at least) the following fields.
Additional fields may include error flags, a pointer to the column in which the operand starts (for
free-format assemblers), a line number, and so on; whatever is conveniently computed on pass 1
and needed on pass 2.
Assemblers, like loaders, are almost always I/O-bound programs, since the time to read a
card generally far exceeds the time to assemble it. Thus, requiring two passes means an
assembler takes twice as long to execute as an assembler which only uses one pass.
4.SOURCECODE:
#include<stdio.h>
#include<string.h>
#include<conio.h>
void main()
{
char *code[9][4]={
{"PRG1","START","",""},
{"","USING","*","15"},
{"","L","",""},
{"","A","",""},
{"","ST","",""},
{"FOUR","DC","F",""},
{"FIVE","DC","F",""},
{"TEMP","DS","1F",""},
{"","END","",""}
};
char av[2],avail[15]={'N','N','N','N','N','N','N','N','N','N','N','N','N','N','N'};
int i,j,k,count[3],lc[9]={0,0,0,0,0,0,0,0,0},loc=0;
printf("----------------------------------------------------\n");
printf("LABEL\t\tOPCODE\n");
printf("----------------------------------------------------\n\n");
for(i=0;i<=8;i++)
{
for(j=0;j<=3;j++)
{
printf("%s\t\t",code[i][j]);
}
j=0;
printf("\n");
}
getch();
printf("-----------------------------------------------------");
printf("\nVALUES FOR LC : \n\n");
for(j=0;j<=8;j++)
{
if((strcmp(code[j][1],"START")!=0)&&(strcmp(code[j][1],"USING")!=0)&&(strcmp(code[j]
[1],"L")!=0))
lc[j]=lc[j-1]+4;
printf("%d\t",lc[j]);
}
printf("\n\nSYMBOL TABLE:\n----------------------------------------------------\n");
printf("SYMBOL\t\tVALUE\t\tLENGTH\t\tR/A");
printf("\n----------------------------------------------------\n");
for(i=0;i<9;i++)
{
if(strcmp(code[i][1],"START")==0)
{
printf("%s\t\t%d\t\t%d\t\t%c\n",code[i][0],loc,4,'R');
}
else if(strcmp(code[i][0],"")!=0)
{
printf("%s\t\t%d\t\t%d\t\t%c\n",code[i][0],loc,4,'R');
loc=4+loc;
}
else if(strcmp(code[i][1],"USING")==0){}
else
{loc=4+loc;}
}
printf("----------------------------------------------------");
printf("\n\nBASE TABLE:\n-------------------------------------------------------\n");
printf("REG NO\t\tAVAILIBILITY\tCONTENTS OF BASE TABLE");
printf("\n-------------------------------------------------------\n");
for(j=0;j<=8;j++)
{
if(strcmp(code[j][1],"USING")!=0)
{}
else
{
strcpy(av,code[j][3]);
}
}
count[0]=(int)av[0]-48;
count[1]=(int)av[1]-48;
count[2]=count[0]*10+count[1];
avail[count[2]-1]='Y';
for(k=0;k<16;k++)
{
printf(" %d\t\t %c\n",k,avail[k-1]);
}
printf("-------------------------------------------------------\n");
printf("Continue..??");
getchar();
printf("PASS2 TABLE:\n\n");
printf("LABEL\t\tOP1\t\tLC\t\t");
printf("\n----------------------------------------------------\n");
loc=0;
for(i=0;i<=8;i++)
{
for(j=0;j<=3;j++)
{
printf("%s\t\t",code[i][j]);
}
j=0;
printf("\n");
}
printf("-----------------------------------------------------");
getch();
}
5.OUTPUT:
----------------------------------------------------
LABEL OPCODE
----------------------------------------------------
PRG1 START
USING * 15
L
A
ST
FOUR DC F
FIVE DC F
TEMP DS 1F
END
-----------------------------------------------------
VALUES FOR LC :
0 0 0 4 8 12 16 20 24
SYMBOL TABLE:
----------------------------------------------------
SYMBOL VALUE LENGTH R/A
----------------------------------------------------
PRG1 0 4 R
FOUR 12 4 R
FIVE 16 4 R
TEMP 20 4 R
----------------------------------------------------
BASE TABLE:
-------------------------------------------------------
REG NO AVAILIBILITY CONTENTS OF BASE TABLE
-------------------------------------------------------
0
1 N
2 N
3 N
4 N
5 N
6 N
7 N
8 N
9 N
10 N
11 N
12 N
13 N
14 N
15 Y
-------------------------------------------------------
CONTINUE..??
PASS2 TABLE:
LABEL OP1 LC
----------------------------------------------------
PRG1 START
USING * 15
A
ST
FOUR DC F
FIVE DC F
TEMP DS 1F
END
-----------------------------------------------------
6.CONCLUSION:
7.DISCUSSION QUESTIONS:
8.FIELD OF APPLICATION:
EXPERIMENT NO: 02
1.EXPERIMENT VISION:
2.OBJECTIVE:
To understand the concept of macro processor and construct a program for it.
3.THEORY:
A macro processor is a program that copies a stream of text from one place to another,
making a systematic set of replacements as it does so. Macro processors are often embedded in
other programs, such as assemblers and compilers. Sometimes they are standalone programs that
can be used to process any kind of text.
4.SOURCECODE:
#include<string.h>
#include<conio.h>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
void main()
{
char *opcode,*operand,*mac,*s,*s1;
FILE *f1,*f2;
clrscr();
f1=fopen("macroin.asm","r");
f2=fopen("macrout.c","w");
rewind(f1);
while(!feof(f1))
{
fscanf(f1,"%s",mac);
if(strcmp(mac,"MACRO")==0)
{
do
{
fscanf(f1,"%s",operand);
fscanf(f1,"%s",opcode);
}while(strcmp(opcode,"MEND")!=0);
}
if(strcmp(mac,"START")==0)
{
fprintf(f2,"\n%s",mac);
do
{
c:fscanf(f1,"%s",operand);
if(strcmp(operand,"M1")==0)
{
rewind(f1);
fscanf(f1,"%s%s%s%s",s,s1,opcode,operand);
l:fscanf(f1,"%s",opcode);
printf("\n%s",opcode);
if(strcmp(opcode,"ADD")==0)
{
fscanf(f1,"%s",operand);
fprintf(f2,"\n%s\t%s",opcode,operand);
fscanf(f1,"%s",opcode);
fprintf(f2,"\n%s",opcode);
exit (0);
}else
goto l;
}
fprintf(f2,"\t%s",operand);
fscanf(f1,"%s",opcode);
if(strcmp(opcode,"CALL")==0)
goto c;
else
fprintf(f2,"\n%s",opcode);
}while(strcmp(opcode,"END")==0);
}
}
fclose(f1);
fclose(f2);
getch();
}
5.OUTPUT:
START
LDA A
START
MOVE A,B
START
ADD A,B
END
6.CONCLUSION:
8.FIELD OF APPLICATION:
1.EXPERIMENT VISION:
2.OBJECTIVE:
3.THEORY:
Lexical analysis is the first phase of a compiler. It takes the modified source code from
language preprocessors that are written in the form of sentences. The lexical analyzer breaks
these syntaxes into a series of tokens, by removing any whitespace or comments in the source
code.
If the lexical analyzer finds a token invalid, it generates an error. The lexical analyzer works
closely with the syntax analyzer. It reads character streams from the source code, checks for
legal tokens, and passes the data to the syntax analyzer when it demands.
4.SOURCECODE:
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#define MAX 30
void main()
{
char str[MAX];
char *input, c;
int point;
int state = 0;
int i = 0, j, startid = 0, endid, startcon, endcon;
point = 0;
for (j = 0; j < MAX; j++)
str[j] = NULL; // Initialise NULL
printf("\t*** Program on Lexical Analysis ***");
printf("\n\nEnter the string: ");
gets(str); // Accept input string
str[strlen(str)] = ' ';
printf("Analysis:");
while (str[i] != NULL)
{
while (str[i] == ' ') // To eliminate spaces
i++;
switch (state)
{
case 0:
if (str[i] == 'i')
state = 1; // if
else if (str[i] == 'w')
state = 3; // while
else if (str[i] == 'd')
state = 8; // do
else if (str[i] == 'e')
state = 10; // else
else if (str[i] == 'f')
state = 14; // for
else if (isalpha(str[i]) || str[i] == '_')
{
state = 17;
startid = i;
} // identifiers
else if (str[i] == '<')
state = 19;
else if (str[i] == '-')
state = 30;
break;
case 1:
if (str[i] == 'f')
state = 2;
else
{
state = 17;
startid = i - 1;
i--;
}
break;
case 2:
if (str[i] == '(' || str[i] == NULL)
{
printf("\nif : Keyword");
state = 0;
i--;
}
else
{
state = 17;
startid = i - 2;
i--;
}
break;
case 3:
if (str[i] == 'h')
state = 4;
else
{
state = 17;
startid = i - 1;
i--;
}
break;
case 4:
if (str[i] == 'i')
state = 5;
else
{
state = 17;
startid = i - 2;
i--;
}
break;
case 5:
if (str[i] == 'l')
state = 6;
else
{
state = 17;
startid = i - 3;
i--;
}
break;
case 6:
if (str[i] == 'e')
state = 7;
else
{
state = 17;
startid = i - 4;
i--;
}
break;
case 7:
if (str[i] == '(' || str[i] == NULL)
{
printf("\nwhile: Keyword");
state = 0;
i--;
}
else
{
state = 17;
startid = i - 5;
i--;
}
break;
case 8:
if (str[i] == 'o')
state = 9;
else
{
state = 17;
startid = i - 1;
i--;
}
break;
case 9:
if (str[i] == '{' || str[i] == ' ' || str[i] == NULL || str[i] == '(')
{
printf("\ndo : Keyword");
state = 0;
i--;
}
break;
case 10:
if (str[i] == 'l')
state = 11;
else
{
state = 17;
startid = i - 1;
i--;
}
break;
case 11:
if (str[i] == 's')
state = 12;
else
{
state = 17;
startid = i - 2;
i--;
}
break;
case 12:
if (str[i] == 'e')
state = 13;
else
{
state = 17;
startid = i - 3;
i--;
}
break;
case 13:
if (str[i] == '{' || str[i] == NULL)
{
printf("\nelse: Keyword");
state = 0;
i--;
}
else
{
state = 17;
startid = i - 4;
i--;
}
break;
case 14:
if (str[i] == 'o')
state = 15;
else
{
state = 17;
startid = i - 1;
i--;
}
break;
case 15:
if (str[i] == 'r')
state = 16;
else
{
state = 17;
startid = i - 2;
i--;
}
break;
case 16:
if (str[i] == '(' || str[i] == NULL)
{
printf("\nfor : Keyword");
state = 0;
i--;
}
else
{
state = 17;
startid = i - 3;
i--;
break;
case 17:
if (isalnum(str[i]) || str[i] == '_')
{
state = 18;
i++;
}
else if (str[i] == NULL || str[i] == '<' || str[i] == '>' || str[i] == '(' || str[i] ==
')' || str[i] == ';' || str[i] == '=' || str[i] == '+' || str[i] == '-')
state = 18;
i--;
break;
case 18:
if (str[i] == NULL || str[i] == '<' || str[i] == '>' || str[i] == '(' || str[i] == ')' ||
str[i] == ';' || str[i] == '=' || str[i] == '+' || str[i] == '-')
{
endid = i - 1;
printf("");
for (j = startid; j <= endid; j++)
printf("\n%c", str[j]);
printf(" : Identifier");
state = 0;
i--;
}
break;
case 19:
if (str[i] == '=')
state = 20;
else if (isalnum(str[i]) || str[i] == '_')
{
printf("\n< : Relational operator");
i--;
state = 0;
}
break;
case 20:
if (isalnum(str[i]) || str[i] == '_')
{
printf("\n<= : Relational operator");
i--;
state = 0;
}
break;
case 21:
if (str[i] == '=')
state = 22;
else if (isalnum(str[i]) || str[i] == '_')
{
printf("\n> : Relational operator");
i--;
state = 0;
}
break;
case 22:
if (isalnum(str[i]) || str[i] == '_')
{
printf("\n>= : Relational operator");
i--;
state = 0;
}
break;
case 23:
if (str[i] == '=')
state = 24;
else
{
printf("\n= : Assignment operator");
i--;
state = 0;
}
break;
goto END;
}
i++;
}
printf("\nEnd of program");
END:
getch();
}
}
5.OUTPUT:
6.CONCLUSION:
7.DISCUSSION QUESTIONS:
8.FIELD OF APPLICATION:
1.EXPERIMENT VISION:
2.OBJECTIVE:
To understand the concept of top down parser and construct a program for it.
3.THEORY:
Top-down Parsing
When the parser starts constructing the parse tree from the start symbol and then tries to
transform the start symbol to the input, it is called top-down parsing.
4.SOURCECODE:
#include <string.h>
#include <conio.h>
char a[10];
int top = -1, i;
void error()
{
printf("Syntax Error");
}
void push(char k[]) // Pushes The Set Of Characters on to the Stack
{
for (i = 0; k[i] != '\0'; i++)
{
if (top < 9)
a[++top] = k[i];
}
}
char TOS() // Returns TOP of the Stack
{
return a[top];
}
void pop() // Pops 1 element from the Stack
{
if (top >= 0)
a[top--] = '\0';
}
void display() // Displays Elements Of Stack
{
for (i = 0; i <= top; i++)
printf("%c", a[i]);
}
void display1(char p[], int m) // Displays The Present Input String
{
int l;
printf("\t");
for (l = m; p[l] != '\0'; l++)
printf("%c", p[l]);
}
char *stack()
{
return a;
}
int main()
{
char ip[20], r[20], st, an;
int ir, ic, j = 0, k;
char t[5][6][10] = {"$", "$", "TH", "$", "TH", "$",
"+TH", "$", "e", "e", "$", "e",
"$", "$", "FU", "$", "FU", "$",
"e", "*FU", "e", "e", "$", "e",
"$", "$", "(E)", "$", "i", "$"};
// clrscr();
printf("\nEnter any String(Append with $)");
gets(ip);
printf("Stack\tInput\tOutput\n\n");
push("$E");
display();
printf("\t%s\n", ip);
for (j = 0; ip[j] != '\0';)
{
if (TOS() == an)
{
pop();
display();
display1(ip, j + 1);
printf("\tPOP\n");
j++;
}
an = ip[j];
st = TOS();
if (st == 'E')
ir = 0;
else if (st == 'H')
ir = 1;
else if (st == 'T')
ir = 2;
else if (st == 'U')
ir = 3;
else if (st == 'F')
ir = 4;
else
{
error();
break;
}
if (an == '+')
ic = 0;
else if (an == '*')
ic = 1;
else if (an == '(')
ic = 2;
else if (an == ')')
ic = 3;
else if ((an >= 'a' && an <= 'z') || (an >= 'A' && an <= 'Z'))
{
ic = 4;
an = 'i';
}
else if (an == '$')
ic = 5;
strcpy(r, strrev(t[ir][ic]));
strrev(t[ir][ic]);
pop();
push(r);
if (TOS() == 'e')
{
pop();
display();
display1(ip, j);
printf("\t%c->%c\n", st, 238);
}
else
{
display();
display1(ip, j);
printf("\t%c->%s\n", st, t[ir][ic]);
}
if (TOS() == '$' && an == '$')
break;
if (TOS() == '$')
{
error();
break;
}
}
k = strcmp(stack(), "$");
if (k == 0 && i == strlen(ip))
printf("\n Given String is accepted");
else
printf("\n Given String is not accepted");
return 0;
}
5.OUTPUT:
6.CONCLUSION:
7.DISCUSSION QUESTIONS:
8.FIELD OF APPLICATION:
1. EXPERIMENT VISION:
Write a C program for the implementation of symbol table with functions to create, insert,
modify, search and display.
2. OBJECTIVE:
To understand the concept of symbol table and display, search, delete, modify the
contents of table.
3. THEORY:
Symbol table is a data structure containing record for each identifier or which field or
attribute of identifier with data structure allows us to find. The record for each identifier quickly
store data. An identifier in source program is detected by lexical analyzer or the identifier is
entered into symbol:
8. Foreach variable name and its type in the variable is an array it also store dimension
information.
10. For its function and procedure for its formal parameter list.
Algorithm:
1. Start the program for performing insert, display, delete, search and modify option
In symbol table
2. Define the structure of the Symbol Table
3. Enter the choice for performing the operations in the symbol Table
4. If the entered choice is 1, search the symbol table for the symbol to be inserted. If
the symbol is already present, it displays “Duplicate Symbol”. Else, insert the
symbol and the corresponding address in the symbol table.
5. If the entered choice is 2, the symbols present in the symbol table are displayed.
6. If the entered choice is 3, the symbol to be deleted is searched in the symbol
table. If it is not found in the symbol table it displays “Label Not found”. Else, the
symbol is deleted.
7. If the entered choice is 5, the symbol to be modified is searched in the symbol
table. The label or address or both can be modified.
4. Source Code:-
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
// #include <alloc.h>
#include <string.h>
#define null 0
int size = 0;
void insert();
void del();
int search(char lab[]);
void modify();
void display();
struct symbtab
{
char label[10];
int addr;
struct symtab *next;
};
struct symbtab *first, *last;
void main()
{
int op;
int y;
char la[10];
// clrscr();
do
{
printf("\nSYMBOL TABLE IMPLEMENTATION\n");
printf("1. INSERT\n");
printf("2. DISPLAY\n");
printf("3. DELETE\n");
printf("4. SEARCH\n");
printf("5. MODIFY\n");
printf("6. END\n");
printf("Enter your option : ");
scanf("%d", &op);
switch (op)
{
case 1:
insert();
display();
break;
case 2:
display();
break;
case 3:
del();
display();
break;
case 4:
printf("Enter the label to be searched : ");
scanf("%s", la);
y = search(la);
if (y == 1)
{
printf("The label is already in the symbol Table");
}
else
{
printf("The label is not found in the symbol table");
}
break;
case 5:
modify();
display();
break;
case 6:
break;
}
} while (op < 6);
getch();
}
void insert()
{
int n;
char l[10];
printf("Enter the label : ");
scanf("%s", l);
n = search(l);
if (n == 1)
{
printf("The label already exists. Duplicate cantbe inserted\n");
}
else
{
struct symbtab *p;
p = malloc(sizeof(struct symbtab));
strcpy(p->label, l);
printf("Enter the address : ");
scanf("%d", &p->addr);
p->next = null;
if (size == 0)
{
first = p;
last = p;
}
else
{
last->next = p;
last = p;
}
size++;
}
}
void display()
{
int i;
struct symbtab *p;
p = first;
printf("LABEL\tADDRESS\n");
for (i = 0; i < size; i++)
{
printf("%s\t%d\n", p->label, p->addr);
p = p->next;
}
}
int search(char lab[])
{
int i, flag = 0;
struct symbtab *p;
p = first;
for (i = 0; i < size; i++)
{
if (strcmp(p->label, lab) == 0)
{
flag = 1;
}
p = p->next;
}
return flag;
}
void modify()
{
char l[10], nl[10];
int add, choice, i, s;
struct symbtab *p;
p = first;
printf("What do you want to modify?\n");
printf("1. Only the label\n");
printf("2. Only the address of a particular label\n");
printf("3. Both the label and address\n");
printf("Enter your choice : ");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Enter the old label\n");
scanf("%s", l);
printf("Enter the new label\n");
scanf("%s", nl);
s = search(l);
if (s == 0)
{
printf("NO such label");
}
else
{
for (i = 0; i < size; i++)
{
if (strcmp(p->label, l) == 0)
{
strcpy(p->label, nl);
}
p = p->next;
}
}
break;
case 2:
printf("Enter the label whose address is to modified\n");
scanf("%s", l);
printf("Enter the new address\n");
scanf("%d", &add);
s = search(l);
if (s == 0)
{
printf("NO such label");
}
else
{
for (i = 0; i < size; i++)
{
if (strcmp(p->label, l) == 0)
{
p->addr = add;
}
p = p->next;
}
}
break;
case 3:
printf("Enter the old label : ");
scanf("%s", l);
printf("Enter the new label : ");
scanf("%s", nl);
printf("Enter the new address : ");
scanf("%d", &add);
s = search(l);
if (s == 0)
{
printf("NO such label");
}
else
{
for (i = 0; i < size; i++)
{
if (strcmp(p->label, l) == 0)
{
strcpy(p->label, nl);
p->addr = add;
}
p = p->next;
}
}
break;
}
}
void del()
{
int a;
char l[10];
struct symbtab *p, *q;
p = first;
printf("Enter the label to be deleted\n");
scanf("%s", l);
a = search(l);
if (a == 0)
{
printf("Label not found\n");
}
else
{
if (strcmp(first->label, l) == 0)
{
first = first->next;
}
else if (strcmp(last->label, l) == 0)
{
q = p->next;
while (strcmp(q->label, l) != 0)
{
p = p->next;
q = q->next;
}
p->next = null;
last = p;
}
else
{
q = p->next;
while (strcmp(q->label, l) != 0)
{
p = p->next;
q = q->next;
}
p->next = q->next;
}
size--;
}
}
5. OUTPUT:
6.CONCLUSION:
Thus we have studied and implementation of symbol table.
7.DISCUSSION QUESTIONS:
8.FIELD OF APPLICATION:
Compiler operates in various phases each phase transforms the source program from one
representation to another. Every phase takes inputs from its previous stage and feeds its output
to the next phase of the compiler.
There are 6 phases in a compiler. Each of this phase help in converting the high-level langue the
machine code.
Phases of Compiler
All these phases convert the source code by dividing into tokens, creating parse trees, and
optimizing the source code by different phases.
x = y + 10
Tokens
X identifier
= Assignment operator
Y identifier
+ Addition operator
10 Number
Syntax analysis is all about discovering structure in code. It determines whether or not a text
follows the expected format. The main aim of this phase is to make sure that the source code was
written by the programmer is correct or not.
Syntax analysis is based on the rules based on the specific programing language by constructing
the parse tree with the help of tokens. It also determines the structure of source language and
grammar or syntax of the language.
Example
(a+b)*c
In Parse Tree
Interior node: record with an operator filed and two files for children
Leaf: records with 2/more fields; one for token and other information about the token
Ensure that the components of the program fit together meaningfully
Gathers type information and checks for type compatibility
Checks operands are permitted by the source language
Semantic analysis checks the semantic consistency of the code. It uses the syntax tree of the
previous phase along with the symbol table to verify that the given source code is semantically
consistent. It also checks whether the code is conveying an appropriate meaning.
Semantic Analyzer will check for Type mismatches, incompatible operands, a function called
with improper arguments, an undeclared variable, etc.
Helps you to store type information gathered and save it in symbol table or syntax tree
Allows you to perform type checking
In the case of type mismatch, where there are no exact type correction rules which satisfy
the desired operation a semantic error is shown
Collects type information and checks for type compatibility
Checks if the source language permits the operands or not
Example
float x = 20.2;
float y = x*30;
In the above code, the semantic analyzer will typecast the integer 30 to float 30.0 before
multiplication
Once the semantic analysis phase is over the compiler, generates intermediate code for the target
machine. It represents a program for some abstract machine.
Intermediate code is between the high-level and machine level language. This intermediate code
needs to be generated in such a manner that makes it easy to translate it into the target machine
code.
Example
For example,
t1 := int_to_float(5)
t2 := rate * t1
t3 := count + t2
total := t3
Phase 5: Code Optimization
The next phase of is code optimization or Intermediate code. This phase removes unnecessary
code line and arranges the sequence of statements to speed up the execution of the program
without wasting resources. The main goal of this phase is to improve on the intermediate code to
generate a code that runs faster and occupies less space.
The primary functions of this phase are:
Example:
a = intofloat(10)
b=c*a
d=e+b
f=d
Can become
b =c * 10.0
f = e+b
Phase 6: Code Generation
Code generation is the last and final phase of a compiler. It gets inputs from code optimization
phases and produces the page code or object code as a result. The objective of this phase is to
allocate storage and generate relocatable machine code.
It also allocates memory locations for the variable. The instructions in the intermediate code are
converted into machine instructions. This phase coverts the optimize or intermediate code into
the target language.
The target language is the machine code. Therefore, all the memory locations and registers are
also selected and allotted during this phase. The code generated by this phase is executed to take
inputs and generate expected outputs.
Example:
a = b + 60.0
MOVF a, R1
MULF #60.0, R2
ADDF R1, R2
EXPERIMENT NO: 07
1.EXPERIMENT VISION:
2.OBJECTIVE:
3.THEORY:
The letters A, E, I, O, and U are called vowels. The other letters in the alphabet are
called consonants.
4.SOURCECODE:
#include <stdio.h>
#include <string.h>
int main(void)
int vowel_count;
scanf("%20s", word);
/* initialise variables */
word_len = strlen(word);
vowels_len = strlen(vowels);
vowel_count = 0;
if (word[i] == vowels[j])
++vowel_count;
break;
/* indicate success */
return 0;
5.OUTPUT:
6.CONCLUSION:
7.DISCUSSION QUESTIONS:
8.FIELD OF APPLICATION: