Скачиваний:
12
Добавлен:
01.05.2014
Размер:
15.55 Кб
Скачать

// 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