
Добавил:
Studfiles2
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Курсовая работа2 / CodeGen
.cpp
// File: CodeGen.cpp
#include "stdafx.h"
#include "CodeGen.h"
#include "Types.h"
#include "ErrorHandler.h"
#include <cstring>
#include <cstdio>
#include <cstring>
#include "Utilities.h"
//-----------------------------------------------------------------------------
CCodeGen::CCodeGen()
{
m_NextName = 0;
m_NextLabel = 0;
m_NextTempNameInt = 0;
m_NextTempNameReal = 0;
m_NextTempNameBool = 0;
m_NextTempNameStr = 0;
m_NextTempNameChar = 0;
m_NameTable.clear();
}
//-----------------------------------------------------------------------------
bool CCodeGen::Analyze(CTokenStream::iterator it_token, CTokenStream::iterator it_end,
const char *FileName)
{
m_Tetrads.clear();
if (CSyntAnalyzer::Analyze(it_token, it_end))
{
FILE *pFile = fopen(FileName, "w");
if (pFile)
{
char Buffer[TET_STRING_LEN+1];
UTIL::GetTimeStr(Buffer, TET_STRING_LEN);
fprintf(pFile, " Файл сгенерирован: %s", Buffer);
fprintf(pFile, "\n------------------------------------------\n\n");
fprintf(pFile, " Таблица имен \n------------------------------------------\n");
for (CNameTable::iterator i = m_NameTable.begin(); i != m_NameTable.end(); ++i)
{
i->second.Print(Buffer);
fprintf(pFile, "\n %16s %s", i->first.c_str(), Buffer);
}
fprintf(pFile, "\n\n Промежуточный код\n------------------------------------------\n");
for (CTetradStream::iterator it = m_Tetrads.begin(); it != m_Tetrads.end(); ++it)
{
it->Print(Buffer);
fprintf(pFile, "\n%s", Buffer);
}
fclose(pFile);
}
else assert(false);
}
return false;
}
//-----------------------------------------------------------------------------
bool CCodeGen::IsTypeArithm(TYPES typ)
{
return ((typ == TYPE_INTEGER) || (typ == TYPE_REAL));
}
//-----------------------------------------------------------------------------
bool CCodeGen::AreTypesArithm(TYPES typ1, TYPES typ2)
{
return (IsTypeArithm(typ1) && IsTypeArithm(typ2));
}
//-----------------------------------------------------------------------------
std::string CCodeGen::NewName(VarInfo vi)
{
char buffer[INTERNAL_NAME_LEN+1];
sprintf(buffer, "v%d", m_NextName++);
// Горе нам, если имя получится длиннее, чем мы можем хранить... :)
assert(strlen(buffer) <= INTERNAL_NAME_LEN);
vi.bTemp = false;
m_NameTable[buffer] = vi;
return std::string(buffer);
}
//-----------------------------------------------------------------------------
SAttrSet CCodeGen::ProcessLiter(TYPES t, unsigned TableIndex)
{
SAttrSet res;
res.SExpr.type = t;
strcpy(res.SExpr.name, NewName(VarInfo(t, true, TableIndex, false)).c_str());
return res;
}
//-----------------------------------------------------------------------------
std::string CCodeGen::NewNameTemp(VarInfo vi)
{
bool bFound = false;
CNameTable::iterator it = m_NameTable.begin();
for (; (!bFound) && (it != m_NameTable.end()); ++it)
{
bFound = ((vi.type == it->second.type) && (it->second.bTemp) && (it->second.bFree));
}
--it;
if (bFound) // Если есть уже использованная временная переменная
{
vi.bTemp = true;
vi.bFree = false;
m_NameTable[it->first] = vi;
return (it->first);
}
char buffer[INTERNAL_NAME_LEN+1];
switch (vi.type)
{
case TYPE_INTEGER: sprintf(buffer, "vInt%d", m_NextTempNameInt++); break;
case TYPE_REAL: sprintf(buffer, "vReal%d", m_NextTempNameReal++); break;
case TYPE_BOOLEAN: sprintf(buffer, "vBool%d", m_NextTempNameBool++); break;
case TYPE_STRING: sprintf(buffer, "vStr%d", m_NextTempNameStr++); break;
case TYPE_CHAR: sprintf(buffer, "vCh%d", m_NextTempNameChar++); break;
default:
assert(false);
}
// Горе нам, если имя получится длиннее, чем мы можем хранить... :)
assert(strlen(buffer) <= INTERNAL_NAME_LEN);
vi.bTemp = true;
vi.bFree = false;
m_NameTable[buffer] = vi;
return std::string(buffer);
}
//-----------------------------------------------------------------------------
std::string CCodeGen::NewLabel()
{
char buffer[INTERNAL_NAME_LEN+1];
sprintf(buffer, "Label%u", m_NextLabel++);
return std::string(buffer);
}
//-----------------------------------------------------------------------------
void CCodeGen::VarHasBeenUsed(std::string name)
{
if (name.length() == 0) return;
if (!m_NameTable.find(name)) return;
m_NameTable[name].bFree = true;
}
//-----------------------------------------------------------------------------
SAttrSet CCodeGen::PerformBoolOperBin(ENUM_TOKENS op, SAttrSet &left, SAttrSet &right)
{
SAttrSet resAttr;
std::string sOp1 = left.SExpr.name;
std::string sOp2 = right.SExpr.name;
if ((left.SExpr.type != TYPE_BOOLEAN) || (right.SExpr.type != TYPE_BOOLEAN))
{
unsigned i = m_Stack[1].Attributes().pToken->Line();
g_ErrorHandler.Error(CError(ERR_NON_BOOLEAN_TYPE, i));
}
resAttr.SExpr.type = TYPE_BOOLEAN;
std::string sRes = NewNameTemp(VarInfo(TYPE_BOOLEAN, false, 0, true));
WriteBoolOperationBin(op, sOp1, sOp2, sRes);
strcpy(resAttr.SExpr.name, sRes.c_str());
resAttr.SExpr.bConst = left.SExpr.bConst && right.SExpr.bConst;
return resAttr;
}
//-----------------------------------------------------------------------------
void CCodeGen::WriteBoolOperationBin(ENUM_TOKENS op, std::string op1, std::string op2, std::string res)
{
TET_OPERATION tet_op;
switch (op)
{
case TKN_AND: tet_op = TET_OP_AND; break;
case TKN_OR: tet_op = TET_OP_OR; break;
default: assert(false);
}
AddTet(tet_op, op1, op2, res);
}
//-----------------------------------------------------------------------------
void CCodeGen::AddTet(TET_OPERATION op, std::string op1, std::string op2, std::string res)
{
m_Tetrads.Add(STetrad(op, op1, op2, res));
VarHasBeenUsed(op1);
VarHasBeenUsed(op2);
}
//-----------------------------------------------------------------------------
std::string CCodeGen::ITOF(std::string operand)
{
std::string res;
res = NewNameTemp(VarInfo(TYPE_REAL, false, 0, true));
AddTet(TET_OP_ITOF, operand, "", res);
return res;
}
//-----------------------------------------------------------------------------
std::string CCodeGen::CharToStr(std::string operand)
{
std::string res;
res = NewNameTemp(VarInfo(TYPE_STRING, false, 0, true));
AddTet(TET_OP_CHAR_TO_STR, operand, "", res);
return res;
}
//-----------------------------------------------------------------------------
SAttrSet CCodeGen::PerformArithmOperBin(SAttrSet &left, SAttrSet &right)
{
SAttrSet res;
std::string op1, op2, sRes;
ENUM_TOKEN_VAL operation = g_TableMgr.GetOperation(m_Stack[1].Attributes().pToken->Index());
res.SExpr.type = ArithmCast(operation, left, right, op1, op2);
sRes = NewNameTemp(VarInfo(res.SExpr.type, false, 0, true));
WriteArithmOperBin(operation, res.SExpr.type, op1, op2, sRes);
strcpy(res.SExpr.name, sRes.c_str());
res.SExpr.bConst = left.SExpr.bConst && right.SExpr.bConst;
return res;
}
//-----------------------------------------------------------------------------
void CCodeGen::WriteArithmOperBin(ENUM_TOKEN_VAL op, TYPES TypeOfOperands,
std::string op1, std::string op2, std::string res)
{
TET_OPERATION tet_op;
switch (TypeOfOperands)
{
case TYPE_INTEGER:
switch (op)
{
case VAL_PLUS_P: tet_op = TET_OP_ADD; break;
case VAL_PLUS_M: tet_op = TET_OP_SUBTRACT; break;
case VAL_MULT_M: tet_op = TET_OP_MULT; break;
case VAL_MULT_D: tet_op = TET_OP_DIV; break;
case VAL_REL_E: tet_op = TET_OP_REL_E; break;
case VAL_REL_G: tet_op = TET_OP_REL_G; break;
case VAL_REL_GE: tet_op = TET_OP_REL_GE; break;
case VAL_REL_NE: tet_op = TET_OP_REL_NE; break;
case VAL_REL_L: tet_op = TET_OP_REL_L; break;
case VAL_REL_LE: tet_op = TET_OP_REL_LE; break;
default: assert(false);
}
break;
case TYPE_REAL:
switch (op)
{
case VAL_PLUS_P: tet_op = TET_OP_ADD_F; break;
case VAL_PLUS_M: tet_op = TET_OP_SUBTRACT_F; break;
case VAL_MULT_M: tet_op = TET_OP_MULT_F; break;
case VAL_MULT_D: tet_op = TET_OP_DIV_F; break;
case VAL_REL_E: tet_op = TET_OP_REL_E_F; break;
case VAL_REL_G: tet_op = TET_OP_REL_G_F; break;
case VAL_REL_GE: tet_op = TET_OP_REL_GE_F; break;
case VAL_REL_NE: tet_op = TET_OP_REL_NE_F; break;
case VAL_REL_L: tet_op = TET_OP_REL_L_F; break;
case VAL_REL_LE: tet_op = TET_OP_REL_LE_F; break;
default: assert(false);
}
break;
}
AddTet(tet_op, op1, op2, res);
}
//-----------------------------------------------------------------------------
TYPES CCodeGen::ArithmCast(ENUM_TOKEN_VAL op, SAttrSet &left, SAttrSet &right,
std::string &op1, std::string &op2)
{
#pragma REMINDER("Пока что тут не рассматриваются перечислимые типы")
if (!AreTypesArithm(left.SExpr.type, right.SExpr.type))
{
unsigned i = m_Stack[1].Attributes().pToken->Line();
g_ErrorHandler.Error(CError(ERR_TYPE_MISMATCH, i));
}
if (left.SExpr.type != right.SExpr.type)
{
if (left.SExpr.type == TYPE_INTEGER)
{
op1 = ITOF(left.SExpr.name);
op2 = right.SExpr.name;
}
else
{
op1 = left.SExpr.name;
op2 = ITOF(right.SExpr.name);
}
return TYPE_REAL;
}
if ((VAL_MULT_D == op) && (left.SExpr.type == TYPE_INTEGER))
{ // При делении оба операнда должны быть вещественными
op1 = ITOF(left.SExpr.name);
op2 = ITOF(right.SExpr.name);
return TYPE_REAL;
}
// оба операнда одинакового типа
op1 = left.SExpr.name;
op2 = right.SExpr.name;
return left.SExpr.type;
}
//-----------------------------------------------------------------------------
SAttrSet CCodeGen::PerformComparisonArithm(SAttrSet &left, SAttrSet &right)
{
SAttrSet res;
std::string op1, op2, sRes;
ENUM_TOKEN_VAL operation = m_Stack[1].Attributes().Operation;
TYPES TypeOfOperands = ArithmCast(operation, left, right, op1, op2);
sRes = NewNameTemp(VarInfo(TYPE_BOOLEAN, false, 0, true));
WriteArithmOperBin(operation, TypeOfOperands, op1, op2, sRes);
strcpy(res.SExpr.name, sRes.c_str());
res.SExpr.type = TYPE_BOOLEAN;
res.SExpr.bConst = left.SExpr.bConst && right.SExpr.bConst;
return res;
}
//-----------------------------------------------------------------------------
void CCodeGen::PerformAssignment(SAttrSet &id, SAttrSet &expr)
{
const unsigned IDindex = id.pToken->Index();
const TYPES IDtype = g_TableMgr.IDType(IDindex);
const TYPES ExprType = expr.SExpr.type;
std::string sRes, sOp;
if (!IsIdDeclared(id))
ErrorIdUndeclared(id);
if (g_TableMgr.IDConst(IDindex))
{
CError err(ERR_CONST_ASSIGN,
m_Stack[2].Attributes().pToken->Line(),
g_TableMgr.IDLexem(IDindex));
g_ErrorHandler.Error(err);
}
sRes = g_TableMgr.IDInternalName(IDindex);
if (IDtype == ExprType) // Типы одинаковые - всё хорошо
{
sOp = expr.SExpr.name;
}
else if ((IDtype == TYPE_REAL) && (ExprType == TYPE_INTEGER))
{
sOp = ITOF(expr.SExpr.name);
}
else if ((IDtype == TYPE_STRING) && (ExprType == TYPE_CHAR))
{
sOp = CharToStr(expr.SExpr.name);
}
else
{
CError err(ERR_TYPE_MISMATCH,
m_Stack[2].Attributes().pToken->Line());
g_ErrorHandler.Error(err);
}
switch (IDtype)
{
case TYPE_INTEGER: AddTet(TET_OP_ASSIGN_INT, sOp, "", sRes); break;
case TYPE_REAL: AddTet(TET_OP_ASSIGN_FP, sOp, "", sRes); break;
case TYPE_BOOLEAN: AddTet(TET_OP_ASSIGN_BOOL, sOp, "", sRes); break;
case TYPE_STRING: AddTet(TET_OP_ASSIGN_STR, sOp, "", sRes); break;
case TYPE_CHAR: AddTet(TET_OP_ASSIGN_CH, sOp, "", sRes); break;
case TYPE_STACK: AddTet(TET_OP_ASSIGN_STACK, sOp, "", sRes); break;
default: assert(false);
}
}
//-----------------------------------------------------------------------------
bool CCodeGen::IsIdDeclared(SAttrSet &attr)
{
return (TYPE_UNDEFINED != g_TableMgr.IDType(attr.pToken->Index()));
}
//-----------------------------------------------------------------------------
void CCodeGen::ErrorIdRedefinition(SAttrSet &attr)
{
unsigned index = attr.pToken->Index();
CError err(ERR_ID_REDEFINITION, attr.pToken->Line(), g_TableMgr.IDLexem(index));
g_ErrorHandler.Error(err);
}
//-----------------------------------------------------------------------------
void CCodeGen::ErrorIdUndeclared(SAttrSet &attr)
{
unsigned index = attr.pToken->Index();
CError err(ERR_ID_UNDECLARED, attr.pToken->Line(), g_TableMgr.IDLexem(index));
g_ErrorHandler.Error(err);
}
//-----------------------------------------------------------------------------
SAttrSet CCodeGen::PerformStrConcat(SAttrSet &left, SAttrSet &right)
{
SAttrSet res;
std::string sRes, sOp1, sOp2;
if (left.SExpr.type == right.SExpr.type)
{
sOp1 = left.SExpr.name;
sOp2 = right.SExpr.name;
}
else if (TYPE_CHAR == left.SExpr.type)
{
sOp1 = CharToStr(left.SExpr.name);
sOp2 = right.SExpr.name;
}
else if (TYPE_CHAR == right.SExpr.type)
{
sOp1 = left.SExpr.name;
sOp2 = CharToStr(right.SExpr.name);
}
else
{
CError err(ERR_TYPE_MISMATCH, m_Stack[1].Attributes().pToken->Line());
g_ErrorHandler.Error(err);
}
sRes = NewNameTemp(VarInfo(TYPE_STRING, false, 0, true));
AddTet(TET_OP_STR_CONCAT, sOp1, sOp2, sRes);
strcpy(res.SExpr.name, sRes.c_str());
res.SExpr.type = TYPE_STRING;
res.SExpr.bConst = left.SExpr.bConst && left.SExpr.bConst;
return res;
}
//-----------------------------------------------------------------------------
void CCodeGen::ErrorTypeUnsupported(unsigned line)
{
CError err(ERR_TYPE_UNSUPPORTED, line);
g_ErrorHandler.Error(err);
}
Соседние файлы в папке Курсовая работа2