.: [предыдущая | оглавление | следующая] :.

15.6 Система-виртуальная машина + транслятор

15.6.1 Эволюция программных систем

Как правило, сложная программная система (ПС) претерпевает несколько стадий своего развития:
1) первоначальная версия;
2) конфигурационная версия;
3) инструментальная версия.
Первоначальная версия системы - это жесткая программа, которая ориентирована на выполнение конкретных функций, при этом модификация функций не предполагается.

Конфигурационная версия предполагает существование специального файла конфигураций, в котором могут быть записаны различные варианты функций и параметров ПС. Как правило, в этом файле записывается последовательность строк, следующей структуры:
< параметр > = < значение >, где < параметр > некоторый параметр ПС или название функции;
< значение > - это числовая константа или строка символов, означающая некоторый вариант функции или параметра.

При таком подходе возможно подстраивать ПС под конкретные нужды потребителей, изменяя значения в конфигурационном файле. Инструментальная версия ПС является дальнейшим развитием конфигурационной ПС, и предполагает наличие некоторого языка, на котором описывается вариант реализации ПС. Этот язык является предметно ориентированным и, в зависимости от особенностей предметной области, может быть декларативным или процедурным. Теперь использование ПС состоит в два этапа: создание конкретной версии ПС и выполнение данной конкретной ПС. Таким образом, инструментальную ПС можно разделить на две части: системная часть, отвечающую за реализацию языка и проблемную часть, в которой содержатся программы реализующие алгоритмы обработки в данной предметной области. Системная часть производит анализ программы (описания конкретной варианта ПС) и генерацию конкретного варианта ПС. Если предметный язык процедурного типа, то создается транслятор, если декларативного - то генератор. Проблемная часть может быть также реализована несколькими способами: библиотека подпрограмм, интерпретатор некоторого внутреннего кода. Библиотека подпрограмм создается в тех случаях, когда состав функций данной предметной области может расширяться. Тогда с внесением новой подпрограммы меняется и системная часть. В настоящее время сложные программные системы строятся по принципу «транслятор - виртуальная машина». Например, так реализована система программирования для интернета - Java[].

15.6.2 Описание языка

Синтаксис языка описывается следующей грамматикой:
<Программа> => program <операторы программы>
<Операторы программы> => <Оператор> < Операторы программы >
<Операторы программы>=> endprog
<Оператор>=> if <Выражение> then <Операторы> endif
<Оператор>=> if <Выражение> then <Операторы> else <Операторы> endif
<Оператор>=> cycle <Выражение> <Операторы> endcycle
<Оператор>=> <Идентификатор>:=<Выражение>
<Оператор>=> output <Список выражений>
<Oператор>=> input < Идентификатор >
<Оператор>=> ;
<Операторы> => <Оператор> < Операторы>

Комментарий в программе оформляется следующим образом: пишется два подряд символа ’-’ и далее до конца строки все символы воспринимаются как комментарий. Например,
– Это комментарий к программе;
– увеличить счетчик

Переменные в программе не объявляются, тип автоматически определяется в зависимости от значения, которое будет присвоено. Типы данных следующие: целый, вещественный, строка символов, точка. Более подробно смотри реализацию.
Примеры программ

Пример №1. Нахождение суммы чисел натурального ряда. Первые две строки комментарий к программе. Затем устанавливаются значения двух переменных i- текущее число натурального ряда и s - сумма. Затем организуется цикл подсчета суммы. В цикле выводится значение текущего натурального числа. По окончанию цикла выводится значение суммы.
// this program count sum
// 15.01.04
program
i:=1; s:=0;
cycle(i<5)
s:=s+i;
i:=i+1;
output i;
endcycle
output s;
endprog

Пример №2. Нахождение значения n! (факториал).
program
// factorial(10)
i:=1; s:=1;
cycle(i<10)
s:=s*i; i:=i+1;
output i;
endcycle
output s;
endprog

15.6.3 Описание языка

Синтаксис языка описывается следующей грамматикой:
<Программа> => program <операторы программы>
<Операторы программы> => <Оператор> < Операторы программы >
<Операторы программы>=> endprog
<Оператор>=> if <Выражение> then <Операторы> endif
<Оператор>=> if <Выражение> then <Операторы> else <Операторы> endif
<Оператор>=> cycle <Выражение> <Операторы> endcycle
<Оператор>=> <Идентификатор>:=<Выражение>
<Оператор>=> output <Список выражений>
<Oператор>=> input < Идентификатор >
<Оператор>=> ;
<Операторы> => <Оператор> < Операторы>

Комментарий в программе оформляется следующим образом: пишется два подряд символа ’-’ и далее до конца строки все символы воспринимаются как комментарий. Например,
– Это комментарий к программе;
– увеличить счетчик

Переменные в программе не объявляются, тип автоматически определяется в зависимости от значения, которое будет присвоено. Типы данных следующие: целый, вещественный, строка символов, точка. Более подробно смотри реализацию.
Примеры программ

Пример №1. Нахождение суммы чисел натурального ряда. Первые две строки комментарий к программе. Затем устанавливаются значения двух переменных i- текущее число натурального ряда и s - сумма. Затем организуется цикл подсчета суммы. В цикле выводится значение текущего натурального числа. По окончанию цикла выводится значение суммы.
--this program count sum
--15.01.04
program
i:=1; s:=0;
cycle(i<5)
s:=s+i;
i:=i+1;
output i;
endcycle
output s;
endprog

Пример №2. Нахождение значения n! (факториал).
program
--factorial(10)
i:=1; s:=1;
cycle(i<10)
s:=s*i; i:=i+1;
output i;
endcycle
output s;
endprog

15.6.4 Стековая виртуальная машина

Стековая виртуальная машина является удобным инструментом в сочетании с транслятором, основанном на методе рекурсивного спуска. В стековой ВМ операнды операции берутся и з стека и результаты операций также заносятся в стек (см. раздел использование стека для вычисления арифметических выражений). Стек используется для хранения промежуточных результатов. Сами объекты хранятся в специальной памяти и есть команду Push и Pull - которые вставляют в стек объект из памяти и выталкивают объект из стека и запоминают его адресу в памяти.

Ниже приведено описание заголовочного файла с описанием параметров стековой виртуальной машины.

Таблица 15.6: Команды виртуальной машины
#defineIN 1 //ввод числа
#define OUT 2 //вывод числа
#define ADD 3 //сложить
#define SUB 4 //вычесть
#define MULT 5 //умножить
#define DIV 6 //разделить
#define JUMP 7 //безусловный переход
#define GRT 8 //проверка на больше
#define LST 9 //проверка на меньше
#define BEQ 10//перейти если флаг установлен
#define STOP 11 //останов
#define EQU 12 //проверка на равно
#define MOV 13 //переслать данные
#define ILOAD 14 //косвенная загрузка данных
#define ISAVE 15 //косвенное соранение данных
#define INC 16 //увеличить на единицу
#define DEC 17 //уменьшить на единицу
#define PUSH 18 //втолкнуть в стек
#define PULL 19 //вытащить из стека
#define TOP 20 //взять вершину стека
#define BNE 21 //не равно


Параметры размера памяти под объекты и стека
#define SIZEMEMORY 256
#define SIZESTACK 256

Ключ установки отладочного режима
#define DEBUG_SVM

Описание типа объекта
#define INT 1 //целый
#define
DOUBLE 2 //вещественный
#define STRING 3 //строка
#define
POINT 4 //точка

Описание структуры точки
typedef struct PointTag {
      int x;
      int y;
} Point;

Описание объекта
typedef struct ObjectTag {
     
unsigned char type; //тип хранимого объекта
      union { //объединение различных типов
            int int_number; //целое число
           
double float_number; //вещественное число
            char string[20]; //строка
            Point p; //структура ТО
      } m;
} Object; //это все может храниться в стеке

Стек для хранения объектов
Object Stack[SIZESTACK];
int Topp; //указатель стека
Object Mem[SIZEMEMORY]; //память под данные

Функция заносит значение объекта в стек.
int Push(Object *obj){
      if(Topp<SIZESTACK){
           
Stack[Topp++]=*obj;
            return 1; //нормальное завершение
      }
      return -1; //стек переполнен
}

Функция выталкивает значение объекта из стека
int Pull(Object *obj)
{ //
забрать из стека
      if(Topp>0){
            *obj=Stack[--Topp];
           
return 1; //нормальное завершение
      }
      return -1; //стек пуст
}

Функция взятие значения из вершины стека
int Top(Object *obj) {
      if(Topp>0){
           
*obj=Stack[Topp-1];
            return 1; //нормальное завершение
      }
      return -1; //стек пуст
}

Функция проверки отношения a > b . Отношение проверяется в зависимости
от типа. Если отношение выполняется, то результат равен единице. В противном случае
0.
int Grt(Object *op1, Object *op2){
      char buf[20];
      if(op1->type==INT && op2->type==INT ){
            if(op1->m.int_number > op2->m.int_number) return 1;
            else return 0;
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  if(op1->m.float_number > op2->m.int_number) return 1;
                  else return 0;
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE {
                        if(op1->m.int_number>op2->m.float_number) return 1;
                        else return 0;
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             if(op1->m.float_number>op2->m.float_number) return 1;
                             else return 0;
                        }
                        else
                             if(op1->type==STRING && op2->type==STRING ){
                                   if(strcmp(op1->m.string,op2->m.string)>0) return 1;
                                   else return 0;
                             }
                             else return 0; //
можно дальше продолжить
}

Функция проверки отношения a < b . Отношение проверяется в зависимости
от типа. Если отношение выполняется, то результат равен единице. В противном случае
0.
int Lst(Object *op1, Object *op2){
      char buf[20];
      if(op1->type==INT && op2->type==INT ){
            if(op1->m.int_number < op2->m.int_number) return 1;
            else return 0;
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  if(op1->m.float_number < op2->m.int_number) return 1;
                  else return 0;
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        if(op1->m.int_number < op2->m.float_number) return 1;
                        else return 0;
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             if(op1->m.float_number < op2->m.float_number) return 1;
                             else return 0;
                        }
                        else
                             if(op1->type==STRING && op2->type==STRING ){
                                   if(strcmp(op1->m.string,op2->m.string)<0) return 1;
                                   else return 0;
                             }
                             else return 0; //
можно дальше продолжить
}
//
равно a==b
int Equ(Object *op1, Object *op2){
      char buf[20];
      if(op1->type==INT && op2->type==INT ){
            if(op1->m.int_number == op2->m.int_number) return 1;
            else return 0;
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  if(op1->m.float_number == op2->m.int_number) return 1;
                  else return 0;
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        if(op1->m.int_number == op2->m.float_number)
                             return 1;
                        else return 0;
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             if(op1->m.float_number == op2->m.float_number) return 1;
                             else return 0;
                        }
                        else
                             if(op1->type==STRING && op2->type==STRING ){
                                   if(strcmp(op1->m.string,op2->m.string)==0) return 1;
                                   else return 0;
                             }
                             else return 0;//
можно дальше продолжить
}
//
функция сложения с учетом типа операнда
void Add(Object *op1, Object *op2, Object *res){
      char buf[20];
      if(op1->type==INT && op2->type==INT ){
            res->type=INT;
            res->m.int_number=op1->m.int_number+op2->m.int_number;
            //int=int+int
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  res->type=DOUBLE;
                  res->m.float_number=op1->m.float_number+op2->m.int_number
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        res->type=DOUBLE;
                        res->m.float_number=op1->m.int_number+op2->m.float_number
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             res->type=DOUBLE;
                             res->m.float_number=op1->m.float_number+op2->m.float_numb
                        }
                        else
                             if(op1->type==STRING && op2->type==STRING ){
                                   res->type=STRING;
                                   strcpy(res->m.string,op1->m.string);
                                   strcat(res->m.string,op2->m.string);
                             }
                             else
                                   if(op1->type==STRING && op2->type==INT ){
                                         res->type=STRING;
                                         strcpy(res->m.string,op1->m.string);
                                         itoa(op2->m.int_number,buf,10);
                                         strcat(res->m.string,buf);
                                   }
                                   else
                                         if(op1->type==STRING && op2->type==DOUBLE ){
                                               res->type=STRING;
                                               strcpy(res->m.string,op1->m.string);
                                               sprintf(buf,"%f",op2->m.float_number);
                                               strcat(res->m.string,buf);
                                         }
                                         else ; //
можно дальше продолжить
}
//
функция вычитания с учетом типа операнда
void Sub(Object *op1, Object *op2, Object *res){
      if(op1->type==INT && op2->type==INT ){
            res->type=INT;
            res->m.int_number=op1->m.int_number-op2->m.int_number;
            //int=int-int
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  res->type=DOUBLE;
                  res->m.float_number=op1->m.float_number-op2->m.int_number
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        res->type=DOUBLE;
                        res->m.float_number=op1->m.int_number-op2->m.float_number
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             res->type=DOUBLE;
                             res->m.float_number=op1->m.float_number-op2->m.float_numb
                        }
                        else ;//
можно дальше продолжить
}
//
функция умножения с учетом типа операнда
void Mult(Object *op1, Object *op2, Object *res){
      if(op1->type==INT && op2->type==INT ){
            res->type=INT;
            res->m.int_number=op1->m.int_number*op2->m.int_number;
            //int=int*int
      }
      else
            if(op1->type==DOUBLE && op2->type==INT ){
                  res->type=DOUBLE;
                  res->m.float_number=op1->m.float_number*op2->m.int_number
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        res->type=DOUBLE;
                        res->m.float_number=op1->m.int_number*op2->m.float_number
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             res->type=DOUBLE;
                             res->m.float_number=op1->m.float_number*op2->m.float_numb
                        }
                        else ;//
можно дальше продолжить
}

void Div(Object *op1, Object *op2, Object *res){
      if(op1->type==INT && op2->type==INT ){
            res->type=INT;
            res->m.int_number=op1->m.int_number/op2->m.int_number;
            //int=int/int
      }
      else
            if(op1->type==DOUBLE && op2->type==INT )
                  res->type=DOUBLE;
                  res->m.float_number=op1->m.float_number/op2->m.int_number
            }
            else
                  if(op1->type==INT && op2->type==DOUBLE ){
                        res->type=DOUBLE;
                        res->m.float_number=op1->m.int_number/op2->m.float_number
                  }
                  else
                        if(op1->type==DOUBLE && op2->type==DOUBLE ){
                             res->type=DOUBLE;
                             res->m.float_number=op1->m.float_number/op2->m.float_numb
                        }
                        else ; //
можно дальше продолжить
}
//
печать первых 10 ячеек памяти
void PrintMemory(){
      printf("dump memory ------------------\n");
      for(int i=0; i<10; i++)
            PrintObjectAddr(i,&Mem[i]);
}
//
ввод объекта
void InputObject(Object *res){
      int ch;
      char buf[40];
      while(1){
            printf("Input type (int-’1’, float-’2’, string-’3’,
            point-’4’)\n");
            printf("type>");
            ch=getch();
            printf("%c\n",ch);
            ch-=’0’;
            if(ch>0&&ch<5) res->type=ch;
            else {
                  puts("Error type\n");
                  continue;
            }
            switch(ch){
                  case 1: printf("int>");
                        gets(buf);
                        res->m.int_number=atoi(buf);
                  return;
                  case 2: printf("float>");
                        gets(buf);
                        res->m.float_number=atof(buf);
                  return;
                  case 3: printf("string>");
                        gets(buf);
                        strcpy(res->m.string,buf);
                  return;
                  case 4: printf("point>");
                        gets(buf);
                  return;
            }
      }
}
//
печать объекта
void OutputObject(Object *res){
      switch(res->type){
            case 1: printf("out->int>");
                  printf("%d\n",res->m.int_number);
            return;
            case 2: printf("out->float>");
                  printf("%g\n",res->m.float_number);
            return ;
            case 3: printf("out->string>");
                  printf("%s\n",res->m.string);
            return;
            case 4: puts("out->point>");
                  return;
      }    
}
//
печать объекта для дампа
void PrintObjectAddr(int Addr,Object *res){
      switch(res->type){
            case 1: printf("%03d (int)%d\n",Addr,res->m.int_number);
            return;
            case 2: printf("%03d (float)%g\n",Addr,res->m.float_numbe
            return ;
            case 3: printf("%03d (string)%20s\n",Addr,res->m.string);
            return;
            case 4: puts("point>");
            return;
      }
}
//
вывод команды на терминал
int PrintCommand(unsigned char *prog){
      int Addr,Addr2,Addr3;
      int pc=0;
      switch (*prog){
            case IN:
                  Addr=prog[pc+1]; //
ввод числа
                  printf("IN %3d\n",Addr);
                  pc+=2;
            break;
            case OUT: //
вывод числа
                  Addr=prog[pc+1];
                  printf("OUT %3d\n",Addr);
                  pc+=2;
            break;
            case PUSH:
                  Addr=prog[pc+1];
                  printf("PUSH %3d\n",Addr);
                  pc+=2;
            break;
            case PULL:
                  Addr=prog[pc+1];
                  printf("PULL %3d\n",Addr);
                  pc+=2;
            break;
            case TOP:
                  Addr=prog[pc+1];
                  printf("TOP %3d\n",Addr);
                  pc+=2;
            break;
            case ADD: //
сложить два числа
                  printf("ADD\n");
                  pc++;
            break;     
            case SUB://
вычитание
                  printf("SUB\n");
                  pc++;
            break;
            case MULT://
умножение
                  printf("MULT\n");
                  pc++;
            break;
            case DIV: //
деление
                  printf("DIV\n");
                  pc++;
            break;
            case JUMP://
безусловный переход
                  Addr=prog[pc+1]; //ввод числа
                  printf("JUMP %3d\n",Addr);
                  pc+=2;
            break;
            case EQU: //
проверка на равно
                  printf("EQU\n");
                  pc++;
            break;
            case GRT: //
проверка a>b
                  printf("GRT \n");
                  pc++;
            break;
            case LST://
проверка a<b
                  printf("LST \n");
                  pc++;
            break;
            case BEQ://
условный переход
                  Addr=prog[pc+1];
                  printf("BEQ %3d\n",Addr);
                  pc+=2;
            break;
            case BNE://
условный переход
                  Addr=prog[pc+1];
                  printf("BNE %3d\n",Addr);
                  pc+=2;
            break;
            case INC://
Инкримент
                  Addr=prog[pc+1];
                  printf("INC %3d\n",Addr);
                  pc+=2;
            break;
            case DEC: //
Декримент
                  Addr=prog[pc+1];
                  printf("DEC %3d\n",Addr);
                  pc+=2;
            break;
            case MOV: //
переслать данные
                  Addr=prog[pc+1];
                  Addr2=prog[pc+2];
                  printf("MOV %3d, %3d\n",Addr,Addr2);
                  pc+=3;
            break;
            case ILOAD: //
косвенная загрузка данных
                  Addr=prog[pc+1];
                  Addr2=prog[pc+2];
                  Addr3=prog[pc+3];
                  printf("ILOAD %3d, %3d, %3d\n",Addr,Addr2,Addr3);
                  pc+=4;
            break;
            case ISAVE: //
косвенное сохрание данных
                  Addr=prog[pc+1];
                  Addr2=prog[pc+2];
                  Addr3=prog[pc+3];
                  printf("ILOAD %3d,%3d, %3d\n",Addr,Addr2,Addr3);
                  pc+=4;
            break;
            case STOP: printf("STOP\n");
            return 0;
            default: printf("Error command\n");
            return -1;
      }
      return pc;
}
//
программа моделирования стековой виртуальной машины
int StackVirtualMachine(unsigned char *prog,Object Mem[])
{
      int com, //
код команды
      Addr,Addr2,Addr3, //вспомогательные ячейки для хранения адресов
      pc=0; //счетчик команд (program counter)
      Object obj1,obj2,obj3,res;
      while(1) //
цикл выполнения программы
      {
            #ifdef DEBUG_SVM //
для отладки
                  PrintMemory();
                  PrintCommand(&prog[pc]);
                  if(getch()==27) exit(0); //
если нажата ESC завершить программу
            #endif
            com=prog[pc]; //
выделяем код операции
            switch (com)
            {
                 
case IN: Addr=prog[pc+1];
                       
InputObject(&Mem[Addr]);
                       
pc=pc+2; //смещаем счетчик команд
                 
break;
                 
case OUT: //вывод числа
                       
Addr=prog[pc+1];
                       
OutputObject(&Mem[Addr]);
                       
pc=pc+2; //смещаем счетчик команд
                 
break;
                 
case PUSH:
                       
Addr=prog[pc+1];
                       
Push(&Mem[Addr]);
                       
pc=pc+2;
                 
break;
                 
case PULL:
                       
Addr=prog[pc+1];
                       
Pull(&Mem[Addr]);
                       
pc=pc+2;
                 
break;
                 
case TOP:
                       
Addr=prog[pc+1];
                       
Top(&Mem[Addr]);
                       
pc=pc+2;
                 
break;
                 
case ADD: //сложить два числа
                       
Pull(&obj1);
                       
Pull(&obj2);
                       
Add(&obj1,&obj2,&res);
                       
Push(&res);
                       
pc=pc+1;
                 
break;
                 
case SUB: //вычитание
                       
Pull(&obj1);
                       
Pull(&obj2);
                       
Sub(&obj1,&obj2,&res);
                       
Push(&res);
                       
pc=pc+1;
                 
break;
                 
case MULT: //умножение
                       
Pull(&obj1);
                       
Pull(&obj2);
                       
Mult(&obj1,&obj2,&res);
                       
Push(&res);
                       
pc=pc+1;
                 
break;
                 
case DIV: //деление
                       
Pull(&obj2);
                       
Pull(&obj1);
                       
Div(&obj1,&obj2,&res); //res=ob1/ob2;
                        Push(&res);
                       
pc=pc+1;
                 
break;
                 
case JUMP: //безусловный переход
                       
pc=prog[pc+1];
                 
break;
                 
case EQU: //проверка на равно
                       
Pull(&obj1);
                       
Pull(&obj2);
                       
res.type=INT;
                       
res.m.int_number=Equ(&obj1,&obj2);
                       
Push(&res);
                       
pc=pc+2;
                 
break;
                 
case GRT: //проверка a > b
                        Pull(&obj2);
                       
Pull(&obj1);
                       
res.type=INT;    
                       
res.m.int_number=Grt(&obj1,&obj2)
                       
pc++;
                 
break;
                 
case LST: //проверка a < b
                        Pull(&obj2);
                       
Pull(&obj1);
                       
res.type=INT;
                       
res.m.int_number=Lst(&obj1,&obj2);
                        Push(&res);
                        pc++;
                  break;
                  case BEQ: //
условный переход если истина
                        Addr=prog[pc+1];
                        Pull(&res);
                        if(res.m.int_number) pc=Addr;
                        else pc=pc+2;
                  break;
                  case BNE: //
условный переход если ложь
                        Addr=prog[pc+1];
                        Pull(&res);
                        if(!res.m.int_number) pc=Addr;
                        else pc=pc+2;
                  break;
                  case INC: //
Инкримент
                        Addr=prog[pc+1];
                        Mem[Addr].m.int_number++;
                        pc=pc+2;
                  break;
                  case DEC: //
Декримент
                        Addr=prog[pc+1];
                        Mem[Addr].m.int_number++;
                        pc=pc+2;
                  break;
                  case MOV: //
переслать данные
                        Addr=prog[pc+1];
                        Addr2=prog[pc+2];
                        Mem[Addr]=Mem[Addr2];
                        pc=pc+3;
                  break;
                 
case ILOAD: //косвенная загрузка данных
                        Addr=prog[pc+1];
                        Addr2=prog[pc+2];
                        Addr3=prog[pc+3];
                        Mem[Addr]=Mem[Addr2+Mem[Addr3].m.int_number];
                        pc=pc+4;
                  break;
                  case ISAVE: //
косвенное сохрание данных
                        Addr=prog[pc+1];
                        Addr2=prog[pc+2];
                        Addr3=prog[pc+3];
                        Mem[Addr2+Mem[Addr3].m.int_number]=Mem[Addr];
                        pc=pc+4;
                  break;
                  case STOP: return 1;
                  default: printf("Error command\n");
                        return -1;
            }
      }
}
#define X 0
#define Y 1
#define Z 2
unsigned char prog[]={
IN, X,
IN, Y,
PUSH, Y,
PUSH, X,
DIV, //x/y
PULL, Z,
OUT, Z,
STOP
};
void main() {
      StackVirtualMachine(prog,Mem); //
выполение первой программы
      SetMemory();
      StackVirtualMachine(prog2,Mem); //выполение второй программы
      getch();
}

15.6.5 Транслятор для стековой виртуальной машины

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <conio.h>
#include "stack_vm.h"

extern Object Mem[]; //
внешняя ссылка на пямять по объекты
#define SIZEPROGRAM 500 //размер программы
#define SIZETABLVAR 30 //размер таблицы символов

struct //описание таблицы символов
{
      int length; //
длина имени
      char Name[10]; //имя переменной
}TablVar[SIZETABLVAR];

void SkipBlanks();
void ExpressAdd(void);
void ExpressTest();
void Statement();

int TopVar; //
номер свобоной ячейки таблицы
char *ch; //указатель для разбора вводимой строки
char in_line[800]; //вводимая строка (буфер для хранения исходного текста)

unsigned char program[SIZEPROGRAM]; //буфер для хранения выходного кода программы
int CurPos; //текщая позиция для записи кода

void OutCode(unsigned char Code) //записать байта в выходной код программы
{
      if(CurPos<SIZEPROGRAM) program[CurPos++]=Code;
}

int GetCurrentPosition() { return CurPos; } //
взять текущую позицию
void SetBrench(int pos, int addr) //установть значение операнда
{
      program[pos]=addr;
}
//
Печать ошибки
void Error(char *soo) {
      printf("%s\n",soo);
}
//
функция поиска имени в таблице символов
int FindNameVar(char *var, int *num)
{
      int i;
      int len;
      len=strlen(var);
      for(i=0; i<SIZETABLVAR; i++)
      {
            *num=i;
            if(TablVar[i].length==0) return -1;
            if(TablVar[i].length==len)
            if(strcmp(TablVar[i].Name,var)==0) return i;
      }
      return -1;
}
//
функция добавления нового имени в таблицу символов
int AddNameVar(char *var)
{
      int num;
      int len;
      char *ptr;
      if(FindNameVar(var,&num)==-1)
      {
            if(TopVar<SIZETABLVAR)
            {
                  num=TopVar;
                  len=strlen(var);
                  TablVar[TopVar].length=len;
                  strncpy(TablVar[TopVar].Name,var,9);
                  TopVar++;
            }
            else Error("
Переполнена таблица символов");
      }
      return num;
}
//
функция взять имя во входной строке
int GetName(char *name, int max) //здесь используются функции ctype.h
{
      int i;
      SkipBlanks(); //
пропустить пробелы
      if(isalpha(*ch)) *name++=*ch++; //первый символ должен быть буквой
      else { *name=0; return 0;}
      for(i=1; i<max; i++) //
взять остальные символы (буква или цифра)
      {
            if(isalnum(*ch)) *name++=*ch++;
            else
            {
                  *name=0; return 1; //
имя нормальное
            }
      }
      *name=0;
      Error("
Большое имя");
      return 0;
}
//
функция пропуска служебных символов
void SkipBlanks()
{
      while(1)
      {
            switch (*ch)
            {
                  case 8: //
табуляция
                  case 26: //конец файла
                  case 10: //возврат каретки
                  case 13: //перевод строки
                  case ’ ’: //пробел
                        ch++; break;
                  default:
                        return;
            }
      }
}
//
проверка вхождения строки str во входной строке
int match(char *str)
{
      char *chv;
      SkipBlanks(); //
пропустить служебные символы и пробелы
      chv=ch;
      while(*str)
      {
            if((*str++)!=(*chv++)) return 0; //
если не совпала строка то ноль
      }
      ch=chv; //
если совпала, то двигаем указатель
      return 1;
}
//
проверка вхождения строки без сдвига указателя ch
int wait(char *str)
{
      char *chv;
      SkipBlanks();
      chv=ch;
      while(*str)
      {
            if((*str++)!=(*chv++)) return 0;
      }
      return 1;
}
//
функция проверки конца строки
int eof() {
      SkipBlanks();
      if(*ch==’\0’) return 1;
      else return 0;
}
//
функция пропуска одного символа
void skipchar() { if(*ch!=’\0’) ch++; }
//
функция взятия числа во входной строки и преобразования к double
double getfloat(char *num, int max) //используются функции <ctype.h>
{
      int i=0, j;
      SkipBlanks(); //
пропустить пробелы
      if(*ch==’-’|| *ch==’+’) //взять знак
            num[i++]=*ch++;
      SkipBlanks(); //
пропусить пробелы
      for( ; i<max; i++) //взять целую часть числа
      {
            if(isdigit(*ch)) num[i]=*ch++;
            else break;
      }
      j=i;
      if(*ch==’.’) //
взять дробную часть числа
      {
            num[i]=*ch++;
            for(j=i+1; j<max; j++)
            {
                  if(isdigit(*ch)) num[j]=*ch++;
                  else break;
            }
      }
      num[j]=0;
      return atof(num);
}
//
функция разбора первичного выражения
void ExpressFunc(void)
{
      int num;
      char name[30];
      double f;
      int max=29;
      if(match("(")) //
вычисление выражения в скобках
      {
            ExpressTest();
            if(match(")")==0) Error("Missmatch )");
      }
      else //
вычисление функций
      {
      //if(match("sin")) TranSin();
      //else
      // if(match("cos")) TranCos();
      //else
      // if(match("atan")) TranAtan();
      //else
      // if(match("log")) TranLog();
      //else
      // if(match("abs")) TranAbs();
      //else
            {
                  if(GetName(name,max)==1)//
взятие значения переменной
                  {
                        num=AddNameVar(name); //
найти переменную в таблице
                        OutCode(PUSH); //сгенерировать команду Push <Addr>
                        OutCode(num);
                  }
                  else //
взять значение константы
                        f=getfloat(name,max);
                  if(name[0]==’\0’) { skipchar(); return; }
                  num=AddNameVar(name); //
найти или записать константу
                  Mem[num].type=DOUBLE; //занести значение в память
                  Mem[num].m.float_number=f;
                  OutCode(PUSH); //
сгенерировать команду Push <Addr>
                  OutCode(num);
                  }
            }
      }
}
//
Функция разбора выражение для умножения и деления
void ExpressMult(void)
{
      ExpressFunc(); //
вычислить первичное
      while(1)
      {
            if(match("*")) //
если знак умножения
            {
                  ExpressFunc(); //
вычислить второе первичное
                  OutCode(MULT); //сгенерировать команду умножить
            }
            else
                  if(match("/")) //
если знак деления
                  {
                        ExpressFunc(); //
вычислить второе первичное
                        OutCode(DIV); //сгенерировать команду разделить
                  }
                  else break;
      }
}
//
функция разбора выражения для сложения и вычитания
void ExpressAdd(void)
{
      ExpressMult(); //
вычислить значение первого операнда
      while(1)
      {
            if(match("+")) //
если знак плюс
            {
                  ExpressMult(); //
вычислить значение для второго опреанда
                  OutCode(ADD);
            }
            else
                  if(match("-")) //
если это минус
                  {
                        ExpressMult(); //
взять значение второго операнда
                        OutCode(SUB);
                  }
                  else break;
      }
}
//
функция разбора логических выражений
void ExpressTest(void)
{
      ExpressAdd(); //
вычислить значение первого операнда
      while(1)
      {
            if(match(">")) //
если знак больше
            {
                  ExpressAdd(); //
вычислить значение для второго опреанда
                  OutCode(GRT);
            }
            else
                  if(match("<")) //
если это меньше
                  {
                        ExpressAdd(); //
взять значение второго операнда
                        OutCode(LST);
                  }
                  else
                        if(match("=")) //
если равно
                        {
                             ExpressAdd(); //
взять значение второго операнда
                             OutCode(EQU);
                        }
                        else break;
      }
}
//
функция разьора оператора присваивания
void AssignOp(void)
{
      char name[10];
      int max=9;
      int num;
      if(GetName(name,max)==1) //
взять имя переменной
      {
            num=AddNameVar(name); //
записать имя в таблицу
      }
      else
      {
            printf("uncorect symbol %c\n",*ch);
            skipchar();
            return;
      }
      if(match(":=")) //
имеется операция присваивания
      {
            ExpressTest(); //
разбрать выражение
            OutCode(PULL); //сгнерировать команду PULL
            OutCode(num);
      }
}
//
функция разбора условного оператора if<>then<>else<>endif
void trans_if()
{
      int pos_else;
      int pos_end;
      ExpressTest(); //
разбор условия в стеке результат сравнения
      OutCode(BNE); //если ложь переход на else или на endif
      pos_else=GetCurrentPosition(); //запомнить позицию для будущего заполения
      OutCode(0); //выделить место под будущее значение
      if(match("then")){
            do //
разбор операторов в блоке then
            {
                  Statement();
            }
            while(!wait("else")&&!wait("endif")&&!eof()); //
ждать пока
            OutCode(JUMP); //переход на конец цикла
            pos_end=GetCurrentPosition(); //запомнить позицию для будущего заполения
            OutCode(0); //выделить место под будущее значение адреса перехода
      }
      else Error("absent then"); //
сообщение об ошибке
            if(match("else")) //разбор блока else
            {
                  SetBrench(pos_else,GetCurrentPosition());
                  //
установить адрес перехода на else блок
                  do //разбор операторов else блока
                  {
                        Statement();
                  }
                  while(!wait("endif")&&!eof()); //
ждать конца endif или буфера
                  SetBrench(pos_end,GetCurrentPosition()); //устанвить переход на конец оператора if
            }
            else //
если else блока нет
                  SetBrench(pos_else,GetCurrentPosition());
                  //
устанвить переход на конец оператора if
            if(match("endif"))
}
//
функция разбора операторы цикла cycle<условие> <тело> endcycle
void trans_while()
{
      int pos_beg=GetCurrentPosition();
      int pos_end;
      ExpressTest(); //
разбор условия, в стеке результат сравнения
      OutCode(BNE); //если ложь переход
      pos_end=GetCurrentPosition();
      OutCode(0); //
заполнить
      do
      {
            Statement(); //
разбор операторов тела цикла
      }
      while(!wait("endcycle")&&!eof()); //
ожидаем конца цикла
      if(match("endcycle"))
      {
            OutCode(JUMP); //
переход в начало цикла
            OutCode(pos_beg);
            SetBrench(pos_end,GetCurrentPosition());
            //
выход за цикл
      }
      else Error("Missmatch endcycle");
}
//
функция рабора оператора ввода input <список переменных>
void trans_input()
{
      char name[20];
      int max=19, num;
      do
      {
            if(GetName(name,max)==1) //
взятие значения переменной
            {
                  num=AddNameVar(name); //
найти переменную в таблице
                  OutCode(IN);
                  OutCode(num);
            }
      }    
      while(match(",")); //
продолжить если есть запятая
}
//
функция разбора оператора вывода
void trans_output() //output <список переменных>
{
      char name[20];
      int max=19, num;
      do{
            if(GetName(name,max)==1) //
взятие значения переменной
            {
                  num=AddNameVar(name); //
найти переменную в таблице
                  OutCode(OUT);
                  OutCode(num);
            }
      }
      while(match(",")); //
продолжить если есть запятая
}
//
функция разбора одного из операторов
void Statement()
{
      char *beg=ch;
      if(match("cycle")) trans_while(); //
разбор оператора цикла
      else
      if(match("if")) trans_if(); //
разбор условногооператора
      else
      if(match("input")) trans_input(); //
разбор оператора ввода
      else
      if(match("output")) trans_output(); //
разбор оператора вывода
      else
      if(match(";")); //
пустой оператор
      else
            AssignOp(); //
разбор оператора присваивания
      for(;beg!=ch; beg++) printf("%c",*beg); printf("\n");
}
//
функция пропуска комментариев
void SkipCommentary()
{
      while(match("--")) while(*ch!=’\n’&&!eof()) skipchar();
}
//
функция разбора текста программы вместе с крмментариями
void trans_program()
{
      SkipCommentary(); //
пропуск комментариев в начале программы
      if(match("program"))
      {
            do
            {
                  SkipCommentary(); //
пропуск коментариев в теле программы
                  Statement();
            }
            while((!wait("endprog"))&&(!eof()));
      }
      if(match("endprog")) OutCode(STOP); //
генерация команды останова
      else Error("Missmatch endprog\n");
      SkipCommentary(); //
пропуск комментариев в конце программы
}
//
Функция вывода таблицы символов
PrintTablVar()
{
      int i;
      for(i=0; i<TopVar; i++)
      {
            printf("%2d%10s\n",i,TablVar[i].Name);
      }
}
//
функция дезассемлирования программного кода виртуальной машины
void Disassembler(unsigned char *program)
{
      int next,pc=0;
      printf("Disassembler for stack vm (ver 1.00)\n");
      printf("---------------------\n");
      do
      {
            printf("%03d ",pc); //
вывод адреса команды
            next=PrintCommand(&program[pc]); //вывод команды
            pc+=next;
      }
      while(next!=0&&next!=-1);
      printf("--------- end -----------\n");
}
//
примеры программ
char example1[]= "program input x; x:=10/x; output x; endpro
//
программа вычисления суммы=(1+2+3+4+5)
char example2[]= "\ –this programm count sum \n\]–15.01.04\n\ program \ i:=1; s:=0; \ cycle(i<5) \ s:=s+i; i:=i+1; \ output i;\ endcycle \ output s;\ endprog";
//
программа вычисления факториала
char example3[]= "program \ –factorial(10)\n\ i:=1; s:=1;\ cycle(i<10) \ s:=s*i; i:=i+1;\ output i;\ endcycle\ output s;\ endprog";
void main()
{
      TopVar=0; //
инициализация стека и таблицы переменных
      printf("trans>"); //вывод подсказки
      gets(in_line); //ввод строки символов
      strcpy(in_line,"program x:=10/x if(c>20) then c:=5 else
      c:=6
      endif endprog");
      strcpy(in_line,"program x:=10/x cycle(c>20) c:=c+1
      endcycle endprog");
      strcpy(in_line,example2);
      ch=&in_line[0]; //
инициализация указателя разбора
      printf("%s\n",in_line);
      trans_program();
      Disassembler(program);
      PrintTablVar();
      StackVirtualMachine(program,Mem);
      getch();
}
.: [предыдущая | оглавление | следующая] :.