Модельный язык программирования (1119466), страница 2
Текст из файла (страница 2)
*/try { Parser * M = new Parser (“program.txt”);M -> Analyze (); delete M;}catch (char c){ cout << “Неверный символ при ”“лексическом анализе: ”<< c << endl; }catch (Token * t) { cout << “Неверная лексема при ”“синтаксическом анализе: ” << t << endl; }32}Отладочная информацияvirtual ostream & ProgramObject::print (ostream & s) const = 0;ostream& Ident ::print (ostream& s) const {s << “Имя ” << name << endl; return s; }ostream& Number::print (ostream& s) const {s << “Число=” << value << endl; return s; }ostream & operator << (ostream & s, const Token * t){ ProgramObject * p; int i;s << “(Tип = ”;s.width (2); s << t -> type << “)”;if ((p = t -> get_value ()) != 0) { s << “ ”; p -> print (s); }else { for (i = 0; i < sizeof (KeyWords) / sizeof (KeyWords [0]); i ++)if (LKeyWords [i] == t -> type){ s << “ Слово ” << KeyWords [i] << endl; return s; }for (i = 0; i < sizeof (Delimiters) / sizeof (Delimiters [0]); i ++)if (LDelimiters [i] == t -> type){ s << “ Знак ” << Delimiters [i] << endl; return s; }s << endl;}return s;}33Анализ описаний• Класс идентификаторов:class Ident: public class ProgramObject { /* ...
*/char * name; /* Ссылка на внешнее представление */bool declare; /* Признак описания идентификатора */bool assign; /* Признак значения идентификатора */ };• Таблицы имён TI и констант TC:ObjectTable<Ident> TI (100);ObjectTable<Number> TC (40);• Методы класса программных объектов и производных классов:type_of_lex ProgramObject::get_type () const { return type; }voidProgramObject::set_type (type_of_lex t) { type = t; }boolIdent::get_declare() const { return declare; }voidIdent::set_declare(){ declare = true; }boolIdent::get_assign() const { return assign; }voidIdent::set_assign{ assign = true; 34}Анализ описаний• Раздел описаний в модельном языке:D → I {,I}: [ int | bool ]• Пример конкретного описания: var m, n, p: int;• Стек Names используется для хранения указателей налексемы, содержащие в поле value ссылки на строкитаблицы TI:Stack <Token *, 100> Names;•Шаблон стеков:template <class T, int max_size> class Stack { T s [max_size]; int top;public:Stack(){ reset ();voidreset(){ top = 0;voidpush(T i){ if (! is_full ())s [top ++] = i;else throw “Стек переполнен”;T pop(){ if (! is_empty ())return s [--top];else throw “Стек исчерпан”;boolis_empty() const { return top <= 0;boolis_full() const { return top >= max_size;}}}}}} };Анализ описаний• Занесение в таблицу идентификаторов информации спомощью метода decl () класса Parservoid Parser::decl (type_of_lex type) const{ while (! Names.is_empty ()){ Token * Ident_lex = Names.pop ();Ident * t = dynamic_cast<Ident*> (Ident_lex -> get_value ());delete Ident_lex;if (t -> get_declare ()) throw “Повторное описание”;}}else { t -> set_declare (); t -> set_type (type); }36Анализ описанийD → <Reset ()> I <Push (name)> {, I <Push (name)>} :[ int <Decl (“int”)> | bool <Decl (“bool”)> ]• Процедуры анализа описаний:void Parser::D () { Names.reset ();// D → I {,I}: [int|bool]if (c_type != LEX_ID)throw curr_lex;Names.push (curr_lex);GetL ();while (c_type == LEX_COMMA) {GetL ();if (c_type != LEX_ID) throw curr_lex;Names.push (curr_lex);GetL (); }if (c_type != LEX_COLON) throw curr_lex;GetL ();if (c_type == LEX_INT || c_type == LEX_BOOL) { decl (c_type); GetL (); }elsethrow curr_lex;}void Parser::D1 () {// D1 → var D {,D}if (c_type != LEX_VAR)throw curr_lex;do { GetL (); D (); } while (c_type == LEX_COMMA);}37Обработка ошибок при анализеvoid Parser:: Analyze () { GetL (); P (); } // запуск анализатораint main (int argc, char ** argv) { bool res = false; /* ...
*/try { Parser * M = new Parser (“program.txt”);M -> Analyze (); delete M;}catch (char c){ cout << “Неверный символ при ”“лексическом анализе: ”<< c << endl; }catch (Token * t){ cout << “Неверная лексема при ”“синтаксическом анализе: ” << t << endl; }catch (ProgramObject * l) { cout << “Неверный объект при ”“синтаксическом анализе: ” << l << endl; }catch (const char * source) { cout << source << endl; }cout << “res = ” << (res ? “true ” : “false”) << endl;return 0;38}Анализ выражений• Стек Types хранит типы используемых в выражениях операндови/или промежуточных значений выражений:Stack <type_of_lex, 100> Types;• Семантические процедуры класса Parser:check_op– проверка совпадения типов двухоперандов бинарной операцииcheck_not– проверка типа операнда унарнойоперации отрицанияcheck_id– контроль наличия описанияидентификатораeq_type– сравнение типов двух операндов изстекаcheck_id_in_read – контроль наличия описанияидентификатора в операторе чтения39Анализ выражений• Процедуры анализа выражений:void Parser::check_op () const {type_of_lex t = LEX_INT, r = LEX_BOOL;type_of_lex t2 = Types.pop ();type_of_lex op = Types.pop ();type_of_lex t1 = Types.pop ();if (op == LEX_PLUS || op == LEX_MINUS ||op == LEX_MULT || op == LEX_DIV)r = LEX_INT;if (op == LEX_OR || op == LEX_AND)t = LEX_BOOL;if (t1 == t2 && t1 == t)Types.push (r);else throw “Неверные типы в двухместной операции”;}void Parser::check_not () const {if (Types.pop () != LEX_BOOL) throw “Неверный тип в операции отрицания”;else Types.push (LEX_BOOL);}void Parser::check_id () const {Ident * t = dynamic_cast<Ident*> (curr_lex -> get_value ());if (t -> get_declare ()) Types.push (t -> get_type ()); else throw “Нет описания”;40}Действия для выраженийПравила грамматики модельного языка для выражений:E → E1 E2E1 → T {[ + | - | or ] T}E2 → [ = | < | > | <= | >= |!= ] E1 | εT → F {[ * | / | and ] F}F → I | N | L | not F | (E)• Правила грамматики с учётом семантических процедур:E → E1 E2E1 → T {[ + | - | or] <Push (type)> T <check_op ()>}E2 → [ = | < | > | <= | >= | !=] <Push (type)> E1 <check_op ()> | εT → F {[ * | / | and] <Push (type)> F <check_op ()>}F → I <check_id ()> |N <Push (type=int)> |L <Push (type=bool)> |not F <check_not ()> | (E)41•Анализ выраженийvoid Parser::E ()// E → E1 E2 E2 → [=|<|<=|>=|>|!=] E1 | ε{ E1 (); if (c_type == LEX_EQ || c_type == LEX_LT || c_type == LEX_GT ||c_type == LEX_LE || c_type == LEX_GE || c_type == LEX_NE ){ Types.push (c_type);GetL ();E1 ();check_op (); }}void Parser::E1 ()// E1 → T {[+|-|or] T}{ T (); while (c_type == LEX_PLUS || c_type == LEX_MINUS || c_type == LEX_OR){ Types.push (c_type);GetL ();T ();check_op (); }}void Parser::T ()// T → F {[*|/|and] F}{ F (); while (c_type == LEX_MULT || c_type == LEX_DIV || c_type == LEX_AND){ Types.push (c_type);GetL ();F ();check_op (); }}void Parser::F () {if (c_type == LEX_ID){else if (c_type == LEX_NUM) {else if (c_type == LEX_TRUE) {else if (c_type == LEX_FALSE) {else if (c_type == LEX_NOT) {else if (c_type == LEX_LPAREN) {if (c_type == LEX_RPAREN)else throw curr_lex;}// F → I | N | L | not F | (E)check_id ();delete curr_lex; GetL ();Types.push (LEX_INT); delete curr_lex; GetL ();Types.push (LEX_BOOL);GetL ();Types.push (LEX_BOOL);GetL ();GetL ();F ();check_not ();GetL ();E ();GetL (); else throw curr_lex;42}}}}}}Контроль типов в операторах1.
В операторах присваивания: типом результата должен бытьтип идентификатора, которому осуществляется присваивание;одновременно должна проводиться проверка описания уидентификатора, которому присваивается новое значение2. В условных операторах у выражений, результат вычислениякоторых влияет на выбор альтернативы вычислений, долженбыть только логический тип3.
В операторах цикла у выражений, результат вычислениякоторых влияет на продолжение выполнения операторов телацикла, должен быть только логический тип4. В операторах чтения должна проводиться проверка наличияописания идентификаторов, которые получают значениявводом из внешнего файла• Грамматика: S → I := E | if E then S else S |while E do S | read (I) | write (E) | B43Контроль типов в операторах1. Оператор присваиванияvoid Parser::eq_type () const{ if (Types.pop () != Types.Pop ())throw “Неверные типы в присваивании”; }S → I <check_id ()> := E <eq_type ()>void Parser::S () { /* … */if (c_type == LEX_ID)// S → I := E{ check_id (); delete curr_lex; GetL ();if (c_type == LEX_ASSIGN) { GetL (); E (); eq_type (); }else throw curr_lex;} //end assign/* … */ }44Контроль типов в операторах2. Условный операторvoid Parser::eq_type (type_of_lex token) const{ if (Types.pop () != token) throw “Неверный тип”; }S → if E <eq_type (“bool”)> then S else Svoid Parser::S () { /* … */// S → if E then S else Selse if (c_type == LEX_IF){ GetL (); E (); eq_type (LEX_BOOL);if (c_type != LEX_THEN) throw curr_lex;GetL (); S ();if (c_type != LEX_ELSE) throw curr_lex;GetL (); S ();} //end if/* … */ }45Контроль типов в операторах3.