Skip to content
uconn code

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;
	}
}

compiler.cpp as plain text

stack.h · 338 lines

stack.h as plain text

stack.cpp · 242 lines

stack.cpp as plain text

variables.h · 55 lines

variables.h as plain text

variables.cpp · 55 lines

variables.cpp as plain text