Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c_compile(флор_курса) / отчет по компилятору.docx
Скачиваний:
28
Добавлен:
15.06.2014
Размер:
36 Кб
Скачать

Код таблицы символических имен

Данный код находиться в файле SymbolArray.c.

Таблица имен представлена структурой

typedef struct Symbol

{

byte NumberRegister; //Номер регистра где храниться данная переменная

не используеться, нужна для оптимизации

int Value; //Значение идентификатора

Хранит код функции, если тип функция, код ключевого слова для BISONи управляемой памяти если тип ключевое слово, и значение 0 если тип переменная

char TypeValue; //Тип значения идентификатора

хранит буквы VFK, переменная, функция, ключевое слово

char* str; //Название идентификатора

Имя присвоенное переменной или функции

};

Добавление нового значение в таблицу осуществляется следующей функцией

bool AddStructSymbol(int Value, char Type, char* str)

{

struct Symbol * temp;

if (size == 0)

{

Если таблица не содержит определений

temp = (struct Symbol * ) malloc ( 32 * sizeof(struct Symbol) );

if (temp == NULL)

{

perror("Attempt to allocate bytes failed.\n");

return false;

}

else

{

size = 32;

сохраняем значение в таблицу

SymbolArray = temp;

SymbolArray[0].Value = Value;

SymbolArray[0].TypeValue = Type;

SymbolArray[0].str = strdup(str);

SymbolArray[0].NumberRegister = Mem;

currentsize = 0;

return true;

}

}

else

{

Таблица уже содержит обозначения

if(currentsize>= (size- 1))

{

Проверяем нужно ли выделить больше памяти для таблицы

Выделяем память для таблицы в 2 раза больше чем было, и если память выделилась удачно сохроняем переменную в таблицу, иначе выделяем память ровно под одну переменную и сохроняем её

temp = realloc(SymbolArray, sizeof(struct Symbol) * 2 * size);

if (temp == NULL)

{

temp = realloc(SymbolArray, sizeof(struct Symbol) * size + sizeof(struct Symbol));

if (temp == NULL)

{

perror("Attempt to allocate bytes failed.\n");

return false;

}

else

{

++size;

++currentsize;

SymbolArray = temp;

SymbolArray[currentsize].Value = Value;

SymbolArray[currentsize].TypeValue = Type;

SymbolArray[currentsize].str = strdup(str);

SymbolArray[currentsize].NumberRegister = Mem;

return true;

}

}

else

{

SymbolArray = temp;

size *= 2;

++currentsize;

SymbolArray[currentsize].Value = Value;

SymbolArray[currentsize].TypeValue = Type;

SymbolArray[currentsize].str = strdup(str);

SymbolArray[currentsize].NumberRegister = Mem;

return true;

}

}

else

{

Если таблица символов не пустая, и памяти хватает для размещения очередной переменной, то просто сохроняем её.

++currentsize;

SymbolArray[currentsize].Value = Value;

SymbolArray[currentsize].TypeValue = Type;

SymbolArray[currentsize].str = strdup(str);

SymbolArray[currentsize].NumberRegister = Mem;

return true;

}

}

}

Код генератора ассемблерного кода

Данный код находиться в файле GenCodev0.c.

Функция writeSegmentData(); - обьявляет и выделяет память, в начала ассембленого файла генерируемого кода, для всех переменных в программе.

VoidwriteSegmentData()

{

int i = 0;

Запись служебных переменны

fprintf(Fasm, "STD_OUTPUT_HANDLE equ -11\nSTD_INPUT_HANDLE equ -10\n__actlen dd 0\n__hstdout dd 0\n");

fprintf(Fasm, "_Error\tdb\t'Error during execution of the program. Error code '\n");

fprintf(Fasm, "_ErrorCode\tdd\t 0\n");

fprintf(Fasm, "_LenError\tequ\t$-_Error\n");

Определения всех поьзовательских переменных

for(i=StartPointValue;i<=currentsize; ++i)

{

fprintf(Fasm, "%s\tdd\t%d\n", SymbolArray[i].str, SymbolArray[i].Value);

}

}

Функция Vipolni() начинает разбор управляемой памяти и генерации ассемблерного файла.

int Vipolni()

{

int saveIP = 0;

int code = 0;

inti= 0;

Открывает асм. файл и записывает в него пользовательские и служебные переменные

Fasm = fopen("asm\\test.txt", "w");

if (Fasm == NULL)

{

perror("Error opening the file test.txt");

return 0;

}

fprintf(Fasm, ";\n; Project file is created:\n; %s;\n", getTime());

fprintf(Fasm, "EXTERN GetStdHandle, WriteFile, ReadFile, ExitProcess, Fitoa, Fatoi\n");

fprintf(Fasm, "SEGMENT .data USE32\n");

writeSegmentData();

fprintf(Fasm, "SEGMENT .text USE32 CLASS=CODE\n..start:\n");

В цикле разбираеться управляющая память

while(iP< _IndexContMem)

{

code= _ContMem[iP];

Выбираем функцию в зависимости от кода операции в управляющей памяти.

switch (code)

{

case CONST:

break;

case VARBL:

break;

case SETVAL:

printf("*\tSETVAL\n");

funcSETVAL();

break;

case ASSIGN:

printf("*\tASSIGN\n");

funcASSIGN();

break;

default:

perror("Unrealized control commands.\n");

printf("Unrealized control - %d\n", code);

iP = _IndexContMem;

break;

}

++iP;

}

printf("\n\nEXIT #3");

fclose(Fasm);

}

Для каждого кода опрерации етсть своя функция. После выполнения каждой функции результат операции находиться в регистре EAX. Каждая функция генерирует код, который не влияет на работу другой функции.

Пример функции генерирующей асм код выполняющей сложения двух чисел

voidfuncADD()

{

Определяем тип первого операнда и в зависимости от него либо записываем в регистр сразу значение, либо заносим в регистр адрес в памяти данных

if (_ContMem[i - 2] == CONST)

{

fprintf(Fasm, "mov EAX, %d\n", _ContMem[i + 2]);

}

else

{

if (_ContMem[i + 2] < 0)

{

fprintf(Fasm, "mov EAX, [%s]\n", SymbolArray[-_ContMem[i + 2]].str);

fprintf(Fasm, "neg EAX\n");

}

else

{

fprintf(Fasm, "mov EAX, [%s]\n", SymbolArray[_ContMem[i + 2]].str);

}

}

Определяем тип второго операнда и в зависимости от него либо записываем в регистр сразу значение, либо заносим в регистр адрес в памяти данных

if (_ContMem[i - 1] == CONST)

{

fprintf(Fasm, "add EAX, %d\n", _ContMem[i + 1]);

}

else

{

if (_ContMem[i + 1] < 0)

{

fprintf(Fasm, "mov EBX, [%s]\n", SymbolArray[-_ContMem[i + 1]].str);

fprintf(Fasm, "neg EBX\n");

}

else

{

fprintf(Fasm, "mov EBX, [%s]\n", SymbolArray[_ContMem[i + 1]].str);

}

Собственно код сложения двух операндов

fprintf(Fasm, "addEAX,EBX\n");

}

iP += 3;

}

Пример кода для цикла с пост условием

void funcREPEAT()

{

fprintf(Fasm, "LablE%d:\n", LastNameLable);

сохроняем в «стек» адреса меток для выхода из цикла и возврат на начало цикла

//метка конца цикла

PushLoop(LastNameLable+ 1);

//иетка начало цикла

PushLoop(LastNameLable);

LastNameLable+= 2;

}

Условия вычисляется в конце цикла, по этому при вычислении условия проверяется усправляющая память на наличие кода конца цикла идущего после условия, и если код встретился то ставиться метка из стека

void funcUNTIL()

{

#if DebugFileMode == 1

fprintf(Fasm, ";Until\n");

#endif

}

Соседние файлы в папке c_compile(флор_курса)