#include #include #include #include #define OVERLOW 1000000 // Максимальное значение переменной // Динамически расширяемый стек struct stack { char value[8]; stack *prev; }; // Чтение очередной инструкции из файла stack * read_next_instruction (FILE *f) { if ( feof (f)) // Конец файла return NULL; char buf[8]; stack * instruction = new stack; instruction->prev = NULL; for ( fscanf (f, "%s ", buf); *buf != ';'; fscanf (f, "%s ", buf)) { // Пока не встретился символ ';' // Добавление в стек stack * lex = new stack; lex->prev = instruction; strcpy (lex->value, buf); instruction = lex; } return instruction; } // Загрузка значения переменной int load (int vars[], char var) { int index = toupper (var) - 'A'; // Регистр имен переменных игнорируется if (vars[index] >= OVERLOW) { printf ("Ошибка: переменная %c не инициализирована!\n", var); exit (1); } return vars[index]; } // Сохранение значения переменной void store (int vars[], char var, int val) { if (abs(val) >= OVERLOW) { // Проверка переполнения printf ("Ошибка: переполнение в переменной %c!\n", var); exit (1); } int index = toupper (var) - 'A'; // Регистр имен переменных игнорируется vars[index] = val; } int main ( int argc, char **argv) { FILE *source = fopen (argv[1],"rt"); // Аргумент - исходная программа int * variables = new int[26]; // Значения переменных for (int i = 0; i < 26; i++) variables[i] = OVERLOW; // Считать все переменные неинициализированными stack * instruction = NULL; // Очередная инструкция while (instruction = read_next_instruction (source)) { // Пока инструкции не кончились int res = 0; // Текущее значение правой части char op = 0; // Знак операции stack * unused; // Элемент, готовый к удалению // Обработка очередной лексемы for (; instruction->prev != NULL; unused = instruction, instruction = instruction->prev, delete unused) { char *lex = instruction->value; if (isalpha (*lex)) // Если переменная switch (op) { // Текущее значение правой части загружается из переменной case 0: res = load (variables, *lex); break; // Текущее значение правой части вычисляется, в зависимости от знака операции case '+': res += load (variables, *lex); break; case '-': res = load (variables, *lex) -res; break; case '*': res *= load (variables, *lex); break; // Текущее значение правой части сохраняется в переменной case ':': store (variables, *lex, res); break; } else if (isdigit (*lex)) // Если константа (требуется для инициализации переменных) res = atoi (instruction->value); // Текущее значение правой части равно константе else // Если знак операции op = *lex; } delete instruction; // Освобождаем занятую память } fclose (source); // Вывод значений переменных в файл char * output_name = new char[256]; strcpy (output_name, argv[1]); strcat (output_name, ".out"); FILE *output = fopen (output_name,"wt"); for (int i = 0; i < 26; i++) if (variables[i] < OVERLOW) fprintf (output,"%c = %d\n", i+'A', variables[i]); fclose (output); return 0; }