Here is my C program implementing a Macro Processor. We know that Macro is a single line abbreviation for a group of statements. We should define that sentence - cluster before using them in actual program. Macro processor will analyse the program and on encountering macro variable, it will replace that 'Macro invocation' to corresponding Macro definition. It should also take care the number and position of arguments used in Macro invocation.
MACROPROCESSOR
- EXPANDING=FALSE.
- Read each line and call GETLINE() and PROCESSLINE() until END encounters.
PROCESSLINE ( )
- If OPCODE is a macroname then EXPAND ( ).
- Else if OPCODE is MACRO ,then DEFINE ( ).
- Else write line to expanded file as such.
DEFINE( )
- Enter Macro name into NMATAB.
- Enter macro prototype into DEFTAB.
- Set LEVEL=1.
- Substitute parameters with positional notations and enter to DEFTAB.
- If OPCODE=MACRO, LEVEL++;
- If OPCODE=MEND, LEVEL--;
- Continue this until LEVEL=0
- Store beginning and end of definition as pointers within NAMTAB
EXPAND ( )
- EXPANDING = TRUE
- Set up arguments from macro invocation in ARGTAB.
- Write macro invocation statement to expanded file as a comment line.
- Call GETLINE() and PROCESSLINE() till macro definition ends.
- Set EXPANDING=FALSE.
GETLINE ( )
- If EXPANDING is TRUE, read from DEFTAB (data structure where macro body is stored) and substitute arguments for positional notations.
- If EXPANDING is FALSE , read next line from input file.
AIM: TO IMPLEMENT MACRO PROCESSOR.
INPUT : "INPUT.TXT"
OUTPUT: "EXPANDED.TXT"
DATE: 07/28/2011
*/
#include<stdio.h>
#include<string.h>
void GETLINE();
void PROCESSLINE();
void DEFINE();
void EXPAND();
FILE *expanded;
FILE *input;
char label[10],opcode[10],operand[25];
char line[20];
int namcount=0, defcount=0;
int EXPANDING;
int curr;
struct namtab
{
char name[10];
int start,end;
}mynamtab[15];
struct deftab
{
char macroline[25];
}mydeftab[25];
struct argtab
{
char arg[3][9];
}myargtab;
///MACRO MAIN
int main()
{
EXPANDING=0;
input =fopen("input.txt","r");
expanded=fopen("expanded.txt","w");
GETLINE();
while(strcmp(opcode,"END")!=0)
{
PROCESSLINE();
GETLINE();
}
fprintf(expanded,"%s",line);
getch();
return 1;
}
// GETLINE
void GETLINE()
{ char word1[10],word2[10],word3[10],buff[10];
int count=0,i,j=0;
if(EXPANDING)strcpy(line,mydeftab[curr++].macroline);
else fgets(line,20,input);
opcode[0]='\0';label[0]='\0';operand[0]='\0';word1[0]='\0';word2[0]='\0';word3[0]='\0';
for(i=0;line[i]!='\0';i++)
{
if(line[i]!=' ')
buff[j++]=line[i];
else
{
buff[j]='\0';
strcpy(word3,word2);
strcpy(word2,word1);
strcpy(word1,buff);
j=0;count++;
}
}
buff[j-1]='\0';
strcpy(word3,word2);
strcpy(word2,word1);
strcpy(word1,buff);
switch(count)
{
case 0:strcpy(opcode,word1);break;
case 1:{strcpy(opcode,word2);strcpy(operand,word1);}break;
case 2:{strcpy(label,word3);strcpy(opcode,word2);strcpy(operand,word1);}break;
}
}
// PROCESSLINE
void PROCESSLINE()
{
int i;
for( i=0;i<namcount;i++)
if(!strcmp(opcode,mynamtab[i].name))
{
EXPAND();return;
}
{
if(!strcmp(opcode,"MACRO"))
DEFINE();
else fprintf(expanded,"%s",line);
}
}
void DEFINE()
{
int LEVEL,i=0,j=0,k=0;
char param[5][9];
char s[3];
strcpy(s,"123");
strcpy(mynamtab[namcount].name,label);
mynamtab[namcount].start=defcount;
strcpy(mydeftab[defcount].macroline,line);
while(operand[i]!='\0')
{
if(operand[i]!=',')
param[j][k++]=operand[i];
else
{
param[j++][k]='\0';
k=0;
}
i++;
}
param[j][k]='\0';
LEVEL=1;
while(LEVEL>0)
{
GETLINE();
if(operand[0]!='\0')
{
for(i=0;i<3;i++)
{
if(!strcmp(operand,param[i]))
{
operand[0]='?';
operand[1]=s[i];
operand[2]='\0';
}
}
}
if(!strcmp(opcode,"MACRO"))
LEVEL++;
else if(!strcmp(opcode,"MEND"))
LEVEL--;
strcpy(mydeftab[defcount].macroline,opcode);
if(operand[0]!='\0')
{
strcat(mydeftab[defcount].macroline," ");
strcat(mydeftab[defcount].macroline,operand);
strcat(mydeftab[defcount].macroline,"\n");
}
strcat(mydeftab[defcount++].macroline,"\n");
}
mynamtab[namcount++].end=defcount;
}
//Expand
void EXPAND()
{
int i,end=0,j=0,k=0;
EXPANDING=1;
int arg=0;
fprintf(expanded,"//%s",line);
for(i=0;i<namcount;i++)
{
if(!strcmp(opcode,mynamtab[i].name))
{
curr=mynamtab[i].start;
end=mynamtab[i].end;
while(operand[i]!='\0')
{
if(operand[i]!=',')
myargtab.arg[j][k++]=operand[i];
else
{
myargtab.arg[j++][k]='\n';
k=0;
}
i++;
}
myargtab.arg[j][k]='\n';
}
}
while(curr<(end-1))
{
GETLINE();
if(operand[0]=='?')
strcpy(operand,myargtab.arg[operand[1]-'0'-1]);
fprintf(expanded,"%s %s %s",label,opcode,operand);
}
EXPANDING=0;
}
/*************************************************************************************/
Let us have a look on what will be the output of the program for a sample input.
input.txt
COPY START 1000
RDBUFF MACRO P,Q,R
CLEAR A
CLEAR S
CLEAR X
+LDT #4096
TD P
JEQ *-3
RD P
STCH Q
JLT *-19
LDA R
COMP #0
STX R
MEND
//main program
FIRST STL RETADR
RDBUFF F1,BUFF1,L1
CLEAR X
RDBUFF F2,BUFF2,L2
RDBUFF F3,BUFF3,L3
JLT *-19
STA
END
The output produced will be,
expanded.txt
COPY START 1000
//main program
FIRST STL RETADR
//RDBUFF F1,BUFF1,L1
CLEAR A
CLEAR S
CLEAR X
+LDT #4096
TD F1
JEQ *-3
RD F1
STCH BUFF1
JLT *-19
LDA L1
COMP #0
STX L1
CLEAR X
//RDBUFF F2,BUFF2,L2
CLEAR A
CLEAR S
CLEAR X
+LDT #4096
TD F2
JEQ *-3
RD F2
STCH BUFF2
JLT *-19
LDA L2
COMP #0
STX L2
//RDBUFF F3,BUFF3,L3
CLEAR A
CLEAR S
CLEAR X
+LDT #4096
TD F3
JEQ *-3
RD F3
STCH BUFF3
JLT *-19
LDA L3
COMP #0
STX L3
JLT *-19
STA
END