uconn codeExpression compiler
Expression compiler
CSE 124 · 2000 · C++
A data-structures lab that grew into a toy compiler. Programs are wrapped in curly braces, declare their variables up front (int a), and assign arithmetic like b = ( a + 2 ) / ( 3 + 2 ). Each statement is converted to postfix (b = a 2 + 3 2 + /) with an operator stack, then evaluated against a variable table. The stack is a class template written for the lab.
Source code
5 files, 1,137 lines, exactly as written apart from line endings.
compiler.cpp · 447 lines
// Stephen Bassoli
// CSE 124 Section 01
// Lab 4
#include <fstream.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "Variables.h"
#include "stack.h"
int LinesLeft = 0;
int NumVars = 0;
Variables Vars[20];
int temp = 1;
int main()
{
ofstream outfile("code.txt");
assert(outfile);
char name[100];
bool cont = true;
void WriteOutfile(ofstream& outfile);
void DecVars(ifstream& infile, int i);
void Directions(void);
void GetAssembly(char* equation);
bool CheckDec(char* variable);
int GetDec(char* variable);
Directions();
WriteOutfile(outfile);
outfile.close();
ifstream infile("code.txt");
assert(infile);
for (int i = 0 ; i < NumVars ; i++ )
{
DecVars(infile,i);
}
while (cont)
{
infile.getline(name, 100);
if (name[0] == '}')
cont = false;
else
GetAssembly(name);
}
return 0;
}
// Input: Outfile with code from user
// Precond: None
// Process: Counts variables, lines of code, and removes semicolons
// Output: Modified outfile with semicolons removed
// Postcond: None
void WriteOutfile(ofstream& outfile)
{
char input[100];
bool go = true;
int Length;
while (go)
{
cin.getline(input, 100);
Length = strlen(input);
if (!(Length == 1))
{
if ((input[Length-1] != ';')&&(LinesLeft>0))
{
cerr << "STATEMENT MUST END WITH SEMICOLIN\n";
exit(1);
}
else
{
input[Length-1] = '\0';
}
}
if ((LinesLeft == 0)&&(input[0] != '{'))
{
cerr << "PROGRAM MUST START WITH OPEN CURLY BRACES\n";
exit(1);
}
else if ((LinesLeft == 0)&&(input[0] == '{'))
input[0] = '\0';
outfile << input << endl;
LinesLeft++;
if ((input[0] == 'i')&&(input[1] == 'n')&&(input[2] == 't')&&(input[3] == ' '))
NumVars++;
if ((input[0] == '}')&&((input[1] == '\0')||(input[1] == ' ')))
{
LinesLeft--;
cout << endl << "Lines of Code: " << LinesLeft-1 << endl;
cout << "Number of Variables: " << NumVars << endl << endl;
go = false;
}
}
}
// Input: The infile, and table number of the variable
// Precond: None
// Process: Declares the variables
// Output: None
// Postcond: None
void DecVars(ifstream& infile, int i)
{
static bool getuseless = false;
char input[100];
if (getuseless == false)
{
infile.getline(input,100);
getuseless = true;
}
infile.getline(input,100);
if ((input[0] == 'i')&&(input[1] == 'n')&&(input[2] == 't')&&(input[3] == ' '))
{
Vars[i].Declare(input + 4);
}
}
// Input: None
// Precond: None
// Process: None
// Output: Displays the instructions of using the program
// Postcond: None
void Directions(void)
{
cout << "To use this simple compiler follow these procedures...\n";
cout << "1) Begin and end the code with open and close curly braces\n";
cout << "2) Initialize all variables at the beginning of the code\n";
cout << "3) Seperate all operators, operands, variables, or cout statements with a space\n";
cout << "4) The Increment and Decrement operators are not seperated by a space, ie ++i\n" << endl;
cout << "Enter Code:\n";
}
// Input: Variable name
// Precond: None
// Process: Checks to see if the variable has been declared
// Output: Returns true if variable has been declared
// Postcond: None
bool CheckDec(char* variable)
{
char temp[100];
for (int i = 0 ; i < NumVars ; i++)
{
strcpy(temp, Vars[i].ReturnIdent());
if (strcmp(variable,temp) == 0)
return true;
}
return false;
}
// Input: Variable name
// Precond: None
// Process: Searches for the table number of the variable
// Output: Returns with table number of variable
// Postcond: None
int GetDec(char* variable)
{
char temp[100];
for (int i = 0 ; i < NumVars ; i++)
{
strcpy(temp, Vars[i].ReturnIdent());
if (strcmp(variable,temp) == 0)
return i;
}
return 0;
}
// Input: Equation string to be converted to assembly language
// Precond: Equation must be in postfix notation
// Process: Converts the postfix equation to assembly language
// Output: Displays the pseudo assembly language
// Postcond: None
void GetAssembly(char* equation)
{
char Token[100][100];
int index = 0;
int val;
void Compute(ofstream& outfile);
Operator<char> Op;
ofstream out("BaseEquation.txt");
assert(out);
ofstream out2("equation.txt");
assert(out2);
ofstream out3("FinalEquation.txt");
assert(out3);
out << equation;
out.close();
ifstream in("BaseEquation.txt");
assert(in);
if ((equation[0] == '+')&&(equation[1] == '+'))
{
if (CheckDec(equation+2))
{
val = GetDec(equation+2);
if (Vars[val].CheckInit())
{
cout << "INC(" << Vars[val].ReturnIdent() << ",$TEMP" << temp << ")" << endl;
temp++;
return;
}
else
{
cerr << "UNINITIALIZED VARIABLE\n";
exit(1);
}
}
}
else if ((equation[0] == '-')&&(equation[1] == '-'))
{
if (CheckDec(equation+2))
{
val = GetDec(equation+2);
if (Vars[val].CheckInit())
{
cout << "DEC(" << Vars[val].ReturnIdent() << ",$TEMP" << temp << ")" << endl;
temp++;
return;
}
else
{
cerr << "UNINITIALIZED VARIABLE\n";
exit(1);
}
}
else
{
cout << "UNDECLARED IDENTIFIER\n";
exit(1);
}
}
else if ((equation[0] == 'c')&&(equation[1] == 'o')&&(equation[2] == 'u')&&(equation[3] == 't')&&(equation[4] == ' ')&&(equation[5] == '<')&&(equation[6] == '<')&&(equation[7] == ' '))
{
if (CheckDec(equation+8))
{
val = GetDec(equation+8);
if (Vars[val].CheckInit())
{
cout << "PRN(cout," << Vars[val].ReturnIdent() << ")" << endl;
return;
}
else
{
cerr << "UNINITIALIZED VARIABLE\n";
exit(1);
}
}
else
{
cout << "UNDECLARED IDENTIFIER\n";
exit(1);
}
}
else
{
while (in >> (Token[index]))
{
index++;
}
if (CheckDec(Token[0]))
{
val = GetDec(Token[0]);
if (Token[1][0] == '=')
Vars[val].Initialize();
else
{
cerr << "INCORRECT SYNTAX FOR ASSINGMENT OPERATOR\n";
exit(1);
}
for (int j = 2 ; j < index ; j++)
{
if (isalpha(Token[j][0]))
{
if (!CheckDec(Token[j]))
{
cerr << "UNDECLARED IDENTIFIER\n";
exit(1);
}
}
out2 << Token[j];
out2 << ' ';
}
if ( index > 3 )
{
out3 << Token[0] << ' ' << Token[1] << ' ';
out3 << Op.Convert(out2);
Compute(out3);
return;
}
else
{
out3 << Token[0] << ' ' << Token[1] << ' ' << Token[2];
Compute(out3);
return;
}
}
else
{
cerr << "UNDECLARED IDENTIFIER\n";
exit(1);
}
}
return;
}
// Input: Outfile with postfix equation
// Precond: Is not an INC, DEC, or PRN statement
// Process: Processes each operator
// Output: Generates assembly code for each operator
// Postcond: None
void Compute(ofstream& outfile)
{
outfile.close();
ifstream infile("FinalEquation.txt");
assert(infile);
Operator<char*> Ops;
char* GetTemp();
int index = 0;
bool run = false;
char Op1[20],Op2[20],Op3[20];
char Token[100][100];
while (infile >> (Token[index]))
{
index++;
}
for ( int i = 2 ; i < index ; i++)
{
if (Token[i][0] == '+')
{
strcpy(Op2,Ops.Pop());
strcpy(Op1,Ops.Pop());
strcpy(Op3,GetTemp());
if (Op2[0] == '$' && Op1[0] == '$')
{
cout << "ADD(" << "$TEMP" << temp-2 << "," << Op2 << "," << Op3 << ")\n";
}
else
cout << "ADD(" << Op1 << "," << Op2 << "," << Op3 << ")\n";
Ops.Push(Op3);
temp++;
run = true;
}
else if (Token[i][0] == '-')
{
strcpy(Op2,Ops.Pop());
strcpy(Op1,Ops.Pop());
strcpy(Op3,GetTemp());
if (Op2[0] == '$' && Op1[0] == '$')
{
cout << "SUB(" << "$TEMP" << temp-2 << "," << Op2 << "," << Op3 << ")\n";
}
else
cout << "SUB(" << Op1 << "," << Op2 << "," << Op3 << ")\n";
Ops.Push(Op3);
temp++;
run = true;
}
else if (Token[i][0] == '*')
{
strcpy(Op2,Ops.Pop());
strcpy(Op1,Ops.Pop());
strcpy(Op3,GetTemp());
if (Op2[0] == '$' && Op1[0] == '$')
{
cout << "MUL(" << "$TEMP" << temp-2 << "," << Op2 << "," << Op3 << ")\n";
}
else
cout << "MUL(" << Op1 << "," << Op2 << "," << Op3 << ")\n";
Ops.Push(Op3);
temp++;
run = true;
}
else if (Token[i][0] == '/')
{
strcpy(Op2,Ops.Pop());
strcpy(Op1,Ops.Pop());
strcpy(Op3,GetTemp());
if (Op2[0] == '$' && Op1[0] == '$')
{
cout << "DIV(" << "$TEMP" << temp-2 << "," << Op2 << "," << Op3 << ")\n";
}
else
cout << "DIV(" << Op1 << "," << Op2 << "," << Op3 << ")\n";
Ops.Push(Op3);
temp++;
run = true;
}
else if (Token[i][0] == '%')
{
strcpy(Op2,Ops.Pop());
strcpy(Op1,Ops.Pop());
strcpy(Op3,GetTemp());
if (Op2[0] == '$' && Op1[0] == '$')
{
cout << "MOD(" << "$TEMP" << temp-2 << "," << Op2 << "," << Op3 << ")\n";
}
else
cout << "MOD(" << Op1 << "," << Op2 << "," << Op3 << ")\n";
Ops.Push(Op3);
temp++;
run = true;
}
else if (isalnum(Token[i][0]))
{
Ops.Push(Token[i]);
}
}
if (run)
cout << "ASG(" << Token[0] << "," << Op3 << ")" << endl;
else
cout << "ASG(" << Token[0] << "," << Token[2] << ")" << endl;
}
// Input: None
// Precond: None
// Process: Creates a temp variable character string
// Output: Returns the temp variable string
// Postcond: None
char* GetTemp()
{
int raw = temp + 48;
char Temp[10] = "$TEMP"; // I know there is a warning here, it is intentional
char String[10];
if ( raw > 57 )
{
itoa(temp,String,10);
strcat(Temp,String);
return Temp;
}
else
{
Temp[5] = char(raw);
Temp[6] = '\0';
return Temp;
}
}