Модельный язык программирования (1119466), страница 3
Текст из файла (страница 3)
Оператор циклаvoid Parser::eq_type (type_of_lex token) const{ if (Types.pop () != token) throw “Неверный тип”; }S → while E <eq_type (“bool”)> do Svoid Parser::S () { /* … */// S → while E do Selse if (c_type == LEX_WHILE){ GetL (); E (); eq_type (LEX_BOOL);if (c_type != LEX_DO) throw curr_lex;GetL (); S ();} //end while/* … */ }46Контроль типов в операторах4. Оператор чтения данныхvoid Parser::check_id_in_read () const{ Ident * t = dynamic_cast<Ident*> (curr_lex -> get_value ());if (! t -> get_declare ()) throw “Не описанное имя”; }S → read (I <check_id_in_read ()>)void Parser::S () { /*…*/else if (c_type == LEX_READ)// S → read (I){ GetL ();if (c_type != LEX_LPAREN) throw curr_lex;GetL ();if (c_type != LEX_ID)throw curr_lex;check_id_in_read ();delete curr_lex;GetL ();if (c_type != LEX_RPAREN) throw curr_lex;GetL ();} //end read/* … */ }47Контроль типов в операторах5.
Оператор вывода данныхS → write (E <Pop ()>)void Parser::S () { /* … */else if (c_type == LEX_WRITE)// S → write (E){ GetL ();if (c_type == LEX_LPAREN){ GetL (); E ();Types.pop (); /* убрать тип выражения из стека */if (c_type == LEX_RPAREN) GetL (); else throw curr_lex;}else throw curr_lex;} //end write// S → Belse B ();}48Объекты для генерации ПОЛИЗ• Производные классы Label и Address для класса ProgramObjectclass Label: public ProgramObject { public: Label (int n); ...};class Address: public ProgramObject { public: Address (int n); ...};• Операции “безусловный переход” и “условный переход по лжи”с внешним представлением в виде строк “!” и “!F” в таблице TWили в виде строк “goto” и “go_if_not” в таблице TD:enum type_of_lex { /* ... */PLZ_GO, /*40: лексема ! - “безусловный переход” */PLZ_FGO /*41: лексема !F - “условный переход”*/ };• Таблица меток TL и таблица адресов TA:ObjectTable<Label>TL (100);ObjectTable<Address> TA (sizeof (TI) / sizeof (TI [0]));• Массив указателей на программные объекты PLZ:ObjectTable<ProgramObject> PLZ (1000);49Методы для генерации ПОЛИЗ• Функция put_obj () записывает в массив обратной польской PLZзаписи указатели на объекты, а также резервирует место дляотложенной записи указателей на объекты:template<class Object>Object * ObjectTable<Object>::put_obj (Object * t, int i) { p [i]= t; return t; }template<class Object>Object * ObjectTable<Object>::put_obj (Object * t = 0){ p [free ++] = t; return t; }template<class Object>Object * ObjectTable<Object>::operator [] (int k){ return p [k]; }template<class Object>intObjectTable<Object>::get_place () const{ return free; }void Parser::check_op (){ /* ...
*/ PLZ.put_obj (TO [TO.get_index (op)]); }50Выражения и присваивание• Правила грамматики с учётом процедургенерации:E → E 1 E2E1 → T {[ + | - | or] <Push (type)> T <check_op ()>}E2 → [ = | < | > | <= | >= | !=] <Push (type)>E1 <check_op ()> | εT → F {[ * | / | and] <Push (type)> F <check_op ()>}Put (I)> |F → I <check_id ();N <Push (type=int); Put (N)> |L <Push (type=bool); Put (L)> |not F <check_not ()>|(E)51Выражения и присваивание• Действия для оператора присваивания:S → I <check_id (); Put (&I)> := E <eq_type (); Put (“:=”)>void Parser::S () { ProgramObject * Oper; /* ...
*/if (c_type == LEX_ID) {check_id (); PLZ.put_obj (CrAddrObject (curr_lex));delete curr_lex;GetL ();Oper = curr_lex -> get_value ();if (c_type == LEX_ASSIGN) { GetL ();E (); eq_type (); PLZ.put_obj (Oper); }else throw curr_lex;} // assign-end/* ... */}52Условный оператор• Семантика условного оператораif E then S1 else S2if (! (E)) goto Lab1; S1; goto Lab2; Lab1: S2; Lab2: …• ПОЛИЗ условного оператора:E p1 !F S1 p2 ! S2 ...гдеpi – номер элемента, с которого начинаетсяПОЛИЗ оператора с меткой Labi, i = 1, 2Ep1!FS1p2!S253Перевод условного оператора• Действия для условного оператора:S→if E <eq_type (bool); Put (“&”, lab1); Put (“!F”)>then S <Put (“&”, lab2); Put (“!”); Put (“p”, lab1)>else S <Put (“p”, lab2)>void S () { ProgramObject * Oper; int lab1, lab2;if (c_type == LEX_IF){ GetL (); E (); eq_type (LEX_BOOL);lab1=PLZ.get_place (); PLZ.put_obj (); PLZ.put_obj (TO [ind_FGO]);if (c_type != LEX_THEN) throw curr_lex;GetL (); S ();lab2=PLZ.get_place (); PLZ.put_obj (); PLZ.put_obj (TO [ind_GO]);PLZ.put_obj (CrLabelObject (PLZ.get_place ()), lab1);if (c_type != LEX_ELSE) throw curr_lex;GetL (); S ();PLZ.put_obj (CrLabelObject (PLZ.get_place ()), lab2);} // end if/* ...
*/}54Оператор цикла с предусловием• Семантика оператора цикла с предусловиемwhile (E) do SL1: if (! (E)) goto L2; S; goto L1; L2: ...• ПОЛИЗ оператора цикла:E p2 !F S p1 ! ...гдеpi – номер элемента, с которого начинаетсяПОЛИЗ оператора с меткой Li, i = 1, 2Ep2!FSp1!55Перевод оператора цикла• Действия для оператора цикла:S→while <Place (lab1)>E <eq_type (bool); Put (“&”, lab2); Put (“!F”)>do S <Put (lab1); Put (“!”); Put (“p”, lab2)>void S () { /* … */else if (c_type == LEX_WHILE){ GetL (); lab1 = PLZ.get_place (); E (); eq_type (LEX_BOOL);lab2 = PLZ.get_place (); PLZ.put_obj ();PLZ.put_obj (TO [ind_FGO]);if (c_type != LEX_DO) throw curr_lex;GetL (); S();PLZ.put_obj (CrLabelObject (lab1));PLZ.put_obj (TO [ind_GO]);PLZ.put_obj (CrLabelObject (PLZ.get_place ()), lab2);} // end while/* ...
*/}56Создание новых объектов• Процедуры создания новых меток и адресов:Address * Parser::CrAddrObject (Token * t){ int Ident_index = TI.get_index (t);int Adr_index = TA.get_index (Ident_index);return Adr_index >= 0 ? TA [Adr_index] :TA.put_obj (new Address(Ident_index));}Label * Parser::CrLabelObject (int label){ int Label_index = TL.get_index (label);return Label_index >= 0 ? TL [Label_index] :TL.put_obj (new Label (label));}57Интерпретация ПОЛИЗ• Чистая виртуальная функция в классе ProgramObject:virtual void ProgramObject::exec (int & i) const = 0;ObjectTable<ProgramObject> PLZ (1000);Stack<int, 100> Values;void Simulator::Simulate (){ int size = PLZ.get_place (); Values.reset ();for (int index = 0; index < size; ++index)PLZ [index] -> exec (index);}int main () { /* ...
*/try { Simulator * S = new Simulator (); S -> Simulate (); }catch (const char * source) { cout << source << endl; }58}Функции интерпретации ПОЛИЗvoidIdent::exec (int&) const { if (get_assign ()) Values.push (get_value ());else throw “PLZ: неопределённое значение имени”; }voidNumber::exec (int&) const { Values.push (get_value ());}voidAddress::exec (int&) const { Values.push (get_value ());}voidLabel::exec (int&) const { Values.push (get_value ());}void TrueObject::exec (int&) const { Values.push (1);}void FalseObject::exec (int&) const { Values.push (0);}voidNotObject::exec (int&) const { Values.push (1 - Values.pop ());}voidOrObject::exec (int&) const { Values.push (Values.pop () || Values.pop ());}voidEqObject::exec (int&) const { Values.push (Values.pop () == Values.pop ());}voidLeObject::exec (int&) const { Values.push (Values.pop () > Values.pop ());}void PlusObject::exec (int&) const { Values.push (Values.pop () + Values.pop ());}void MinusObject::exec (int&) const { int k = Values.pop (); Values.push (Values.pop () - k); }voidDivObject::exec (int&) const { int k = Values.pop ();if (k) Values.push (Values.pop () / k); else throw “PLZ: деление на нуль”; }void AssignObject::exec (int&) const { int k = Values.pop (); Ident * t = TI [Values.pop ()];t -> set_value (k); t -> set_assign ();}void WriteObject::exec (int&) const { cout << Values.pop () << endl;}void GoToObject::exec (int& i) const { i = Values.pop () - 1;}voidGoIfNotObject::exec (int& i) const { int k = Values.pop (); if (! Values.pop ()) i = k - 1; 59 }.