
Код таблицы символических имен
Данный код находиться в файле 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
}