КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Лекция 12. Заполнение таблицы команд
Заполнение таблицы команд
Эта таблица заполняется расширенными функциями body(), stat(), expr(), term(), fact(). Заполнение осуществляется вызовом специально предназначенной для этого функцией gen()/. Предварительно нужно в программе интерпретатора добавить следующие глобальные переменные: int cgv=0, clv=0; //количество глобальных и количество локальных переменных int tc=0; //счетчик количества команд, занесенных в TCD int out=1 //если out=1, то переменная глобальная. Если out=0, то- локальная
Программа занесения команд в таблицу команд
int gen(int co, int op) { if (tc>=300) { puts(“Переполнение TCD”); exit(1); } TCD[tc].cod=co; TCD[tc].opd=op; return tc + +; } Следует обратить внимание на return tc + +. Возвращается адрес в TCD, куда будет заноситься следующая команда.
Расширенная функция body()
int body() { int st; //Адрес точки входа в функцию exam(BEGINL); clv=0;//Обнулить количество локальных переменных. while(lex = = INTL|| lex = = CONSTL) if (lex = = CONSTL) dconst(); else dvarb();// Возвращает значение clv st = gen(INI, clv); //Адрес команды в TCD является точкой входа в функцию stml(); exam(ENDL); gen(OPR, 10); //Генерация команды «останов» return st;//Возвращает точку входа в функцию. } По сравнению с нерасширенной функцией body() имеет место определение точки входа в функцию и вызов функции gen() для занесения в TCD определенных команд.
Расширенная функция stat()
void stat() { int t1, t2; odc*p; switch(lex) { case IDEN: p= findob((char*)lval); get(); exam(‘=’); expr(); if(p→what = =1); { printf(“%s- константа. Нельзя присваивать \n”,p→name); exit(1) } gen (p->what == 2? STE: STI, p->val); break; case READL: get(); p = findob ((char *)lval); gen (OPR, 1); if (p->what == 1) { printf ("%s константа\n", p->name); exit(1); } gen (p->what == 2? STE: STI, p->val); exam (IDEN); break; case IFL: get(); expr(); exam (THENL); t1 = gen (JMC, 0); stml(); exam (ENDL); TCD[t1].opd = tc; break; case WHILEL: get(); t1 = tc; expr(); exam (DOL); t2 = gen (JMC, 0); stml(); gen (JMP, t1); TCD[t2].opd = tc; exam (ENDL); break; case PRITL: get(); expr(); gen (OPR, 2); break; case RETRL: get(); expr(); gen (OPR, 9); break; default: printf(“Недопустимая лексема lex=%i в строке nst=%i \n”, lex, nst); } return; }
По case IDEN вначале происходит поиск объекта в TOB по имени (char*) lval. Напомним, что lval - значение лексемы. Для константы это число, а для переменных – адрес в таблице идентификаторов TNM. Используется явное преобразование типа int lval на указатель (char*,) поскольку для функции findob(char*name) параметром является именно указатель char*. Эта функция возвращает указатель odc*p. Если р→what равен 1, то это означает, что найденный объект – константа, а значит присваивать нельзя. Программа по еxit(1) прекращает работу. Если р→what равен 2, то объект является глобальной переменной. Тогда генерируется команда занесения глобальной переменной gen (STЕ, p->val). Иначе заносится локальная переменная gen (STI, p->val). Напомним, что p->val определяет смещение обьекта в стеке. Например, в рассмотренной выше программе смещение для локальной переменной c равно 1. Соответственно команда присваивания числа из вершины стека переменной c имеет вид gen (STI, 1). По case READL также ищется объект в ТОВ, и в таблицу команд TCD записывается команда OPR 1 занесения из файла stdin, связанного с клавиатурой, в вершину стека. Далее - всё подобно рассмотренному выше. По case IFL после получения «свежей» лексемы (get()) и вызова expr() проверяется наличие служебного слова thenl. Затем в t1 заносится значение счетчика tc команд в TCD, соответствующего команде gen (JMC,0)- условной передачи управления команде под номером 0 в TCD. Затем по stml() заносится в TCD последовательность команд. Естественно, что при этом изменяется значение tc. Затем реальное значение tc заносится вместо нуля в качестве операнда в команду, находящуюся под номером t1 в TCD TCD[t1].opd=tc. Подобным образом программа работает по case WHILEL. После get() запоминается адрес команды TCD, по которой будет получен результат выражения в вершине стека. Вспомним последовательность промежуточных команд, обеспечивающую цикл: lb:<e>{JMC l}<s>{JMP lb} l. Присваивание t1=tc соответствует получению метки lb <e>. t2=gen(JMC,0) - запоминание номера команды JMC0 в TCD. После выполнения последовательности команд <s>, чему соответствует stml(), выполняется (JMP,t1)- безусловная передача на команду, по которой будет получено новое значение <e> в вершину стека. Как и в случае case IFL, присваивание TCD[t2].opd=tc позволяет заменить условную передачу (JMC,0) на (JMC,tc).
Дата добавления: 2015-06-27; Просмотров: 352; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |