From c001ccb12ac466df39264a1fd8cadaca538401e9 Mon Sep 17 00:00:00 2001 From: Arity-T Date: Wed, 28 May 2025 14:19:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BB=D0=B0=D0=B1=204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab4/cmilan/test/incdec/inc.mil | 7 + lab4/cmilan/test/incdec/incif.mil | 6 + lab4/cmilan/test/incdec/incxy.mil | 13 + lab4/cmilan/test/incdec/invalid.mil | 5 + lab4/report/img/result1.png | Bin 0 -> 2466 bytes lab4/report/img/result2.png | Bin 0 -> 2017 bytes lab4/report/img/result3.png | Bin 0 -> 3014 bytes lab4/report/img/result4.png | Bin 0 -> 1917 bytes lab4/report/report.tex | 555 ++++++++++++++++++++++++++-- 9 files changed, 565 insertions(+), 21 deletions(-) create mode 100644 lab4/cmilan/test/incdec/inc.mil create mode 100644 lab4/cmilan/test/incdec/incif.mil create mode 100644 lab4/cmilan/test/incdec/incxy.mil create mode 100644 lab4/cmilan/test/incdec/invalid.mil create mode 100644 lab4/report/img/result1.png create mode 100644 lab4/report/img/result2.png create mode 100644 lab4/report/img/result3.png create mode 100644 lab4/report/img/result4.png diff --git a/lab4/cmilan/test/incdec/inc.mil b/lab4/cmilan/test/incdec/inc.mil new file mode 100644 index 0000000..b73fbc5 --- /dev/null +++ b/lab4/cmilan/test/incdec/inc.mil @@ -0,0 +1,7 @@ +BEGIN + x := 0; + write(x++); + write(x); + write(++x); + write(x) +END \ No newline at end of file diff --git a/lab4/cmilan/test/incdec/incif.mil b/lab4/cmilan/test/incdec/incif.mil new file mode 100644 index 0000000..120c991 --- /dev/null +++ b/lab4/cmilan/test/incdec/incif.mil @@ -0,0 +1,6 @@ +BEGIN + i := 1; + j := 2; + + IF i < --j THEN WRITE(100) ELSE WRITE(-100) FI +END \ No newline at end of file diff --git a/lab4/cmilan/test/incdec/incxy.mil b/lab4/cmilan/test/incdec/incxy.mil new file mode 100644 index 0000000..f31ce47 --- /dev/null +++ b/lab4/cmilan/test/incdec/incxy.mil @@ -0,0 +1,13 @@ +BEGIN + y := x++; + write(y); + write(x); + + y := 10 - --x; + write(y); + write(x); + + y := 10 -++x; + write(y); + write(x) +END \ No newline at end of file diff --git a/lab4/cmilan/test/incdec/invalid.mil b/lab4/cmilan/test/incdec/invalid.mil new file mode 100644 index 0000000..03ab663 --- /dev/null +++ b/lab4/cmilan/test/incdec/invalid.mil @@ -0,0 +1,5 @@ +BEGIN + x := 10; + y := 10 - --x; /* Корректно: минус и декремент разделены пробелом */ + y := 10 ---x; /* Некорректно: три минуса подряд */ +END \ No newline at end of file diff --git a/lab4/report/img/result1.png b/lab4/report/img/result1.png new file mode 100644 index 0000000000000000000000000000000000000000..80a0504df02320d62d51483e4d8b0be0df1cff17 GIT binary patch literal 2466 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 JR+_lR{~OB5uYUjl literal 0 HcmV?d00001 diff --git a/lab4/report/img/result2.png b/lab4/report/img/result2.png new file mode 100644 index 0000000000000000000000000000000000000000..27f4991cb524e079bd0430ac4fdb2a40dca7fd7b GIT binary patch literal 2017 zcmV<72Oju|P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&2X;wBK~#8N?VZ1G z)JPP^=k9L^&C!JDq~nKl(Y0ZvtxgdXD3n=g1;r{9sgdBeK#>R_rA~1X4O%G?LIOk) zgs6~q(@>xw5rrnugyP6Qa93RJz4>8}yO*PBj(M_g7-+;&0;7uHHB3_)8bpbi{lxjCh6 z!-)cAPZ=S#q!u$_wXq|*O$^)X!!$-jpmdx~wuR*u{oN7U{isRsaw%gJ6}K5jjI`L? z2-2{*pyMSOb|)i8brgRjK1R+pWWo&P$Alcp)>D3*(@;+%uN?#N*3*-mHGy_BPogHB`T#gtW+OV&f@xO02FKi znN|CIx9G81cQ^DiOkH1BrrqQ4?sRA4n%+{(c2>k?YoxXNm^6B0MQmK3lKVwzZ&}XQ z+1rBsW(NoATFN)lid;*L{5HonE0LBTLwoB(AXiSa+7P0*J$#2BD|B6Bp1)h2qll=< zZr3w&dG&21u5pEq>3^2nFW0H9w4X%etl9>ZYu(&6cf{b_Es~8&Gw4rS=i3qc-}Gh{ zbXQ)dp%rD?h$)?O#4{m0=k;nQRNI%FMD&vGc5?BG0KlWg3y zp&$!>5HmofZLGI_VtfhXtXv;t4#juZ5=WUyvMe2HD_1EWNj{ZPW=IjHW>}%5_y9}D zk6*Wg!li%Z>N~*<*zjyF+k>!h-){{U^6p*=LH*l`kZhs69TNv3AHKcwhNZL?;hg zU&w^CpKztd!n0nzMV)4mj@Wyv{CY8l!&GBlE2?DYb*2m*C|Y)=R?Cm@LtQ;GA>(Em z-{o38x?8?0_kAs{9Mv%_1q3P!>TCSCkC6WFkhyq3|B`Hd>C^)NOq}{CBpL$qPEe{|XTj;VhDCQW@55^;xZa?56wp?OaTe(D%g{{T!JEMW@(s0_6lAproY4HOap zpfW%q0RSok6cPZSGC&~#04f6%5&)nw6jw;WTg1uh{W6g?e_hrEPB|9<;Pg^RA;|^E zyFx6>B~KGDZ}(eEeyA7tEQRBe1^`eCPOOmlh1BgU>IvtwIxdb`^VeP%ICvvHwk~j5 z8UR2&II%)vrIED;Oya^-yKAB=m*;#VcU{r|0P4Z`oZ9;B`Wb62W4RUzujjMHU;6m! zlm=!S0QF&f3MmHro8$sgd$+}?HJ@D4002%eBNbBcRZ1(IZ1q9)wM*%5viw9*T+#pl zPCFwN68nhEtd|M7)(zI{5A_yr2(cAC_UM4uwVrlLgEfi(s1IW`*{<;7*$H1AvA_1< zk_G@!55}sH%$E~vQ;$u-Za@4)uuB>MKs`9|0&Qx+^Vo8*274iWe(1JQle2A00000NkvXXu0mjfb&JNX literal 0 HcmV?d00001 diff --git a/lab4/report/img/result3.png b/lab4/report/img/result3.png new file mode 100644 index 0000000000000000000000000000000000000000..90f83c84f74b88c9cc05fba99788ad6e2d1b9c48 GIT binary patch literal 3014 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 literal 0 HcmV?d00001 diff --git a/lab4/report/img/result4.png b/lab4/report/img/result4.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1327f279e3d85f99891fa38069d62d0745455e GIT binary patch literal 1917 zcmV-@2ZH#CP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&2NFp{K~#8N?VT}e z8%Y$$-`!_$8ee0piSfaiw30y8VeG;Mq;Gn{&5DBDKVPiOqKrUlaIG9uh z$?c(lgVV@v;wJtAcg5YkH#57M*rIECb-VZj`uGTxVGyi$>-kUM`>ED0;{tp<2 zVVKPFv--&}48vp;Hq;EmFd2spHN!AW#u?sFfByix%P-*9<#+1BZ1Hx2@9wOupwIkc z56-`<@1}{W*V~Rdcf{lSJ^OY`(sQ`oc0Z^u#>*r%W<%EM^Q1|sdG@Gh1rkQ-5Zc}; z+A3A&w%^wG0kFE0tud9f_ zzsEQdqJ>Fno-z5MJZchQLw#oASYQwO2f{n^BctANu%f;sih1bPlhZVX+9%`pYjB7L zJ0mGECLq0`w#e6s+#p_mgwMvT9p~kq?`qE)MIczOI$CM(>=crsQ&ArWImXRn6!!6k zIvX#OD$De+%)aQC@1@`I`!!9!8)Z>SMqRf-_X^|C>qK;t>f<>7>`c$d$o;;!3hQv0 zst#192iH)kMBBlI4wKqP_EEIW^y|)TOE@}F*#xO~d5xUEcI9{DzHoUqW$E=ztNHYX z+BRR;I)u{l5iDKFdvDIl;$`(vj4EDP?Bz_aY5b|b#UCF)}Vu5c^zbnJ2mvwVhg@XFphF_NQSk6~<7EdlW zr#>~Iyu1zId!M2{hrRxHn16PuXE!WBaSiKmVv)+!*r`$bx*sEh+UG#%04E8pzA{SA zL+wgiPZ1gm_i1|DA}0K;rWu*6UyA3np*nbtOLdlpYq)(-A01%TJ~U~f(S^pgG`i?Oltq*rUGxt3snF_$ ze2!IFK?EL37vZyv^8whD4dW(hHD|MF4 z0U4+Xr7WHVDAC5xT&-eb7)+WFy`Uy}uI-S}UWgeq4I(reakg@e2&qEv6&@%y_e_#pkSYk%Gl-c1J+GYa z@liUZ`ZW!bEA*f6Pn zpPHd|5fXMTFf^jYhmtv)(PZYY(uTcMO8k$yvj0PYgLoaq=I8fx`h|4?296{x76Z?G#Y}-e! zH<9zT4+nc?6yc#&q^YMDY|4`99lOaZPP0BXWu?-*T6hfau$r2oUfHQa0XxC!k8Ao6 z=ateyVUxc~Yj~-?VVRX(AC_#=fWYug7i}DrdGE$i(Ee0T`7WPo z1)QJ((ynYn1=PYYEfS)h%Cue)lW!k4F7!NBXu<972YuQqn+#2|Nul!LKuRTi}eIVfA9ygt?;Y`ldr)-`0HnZGN&|s#Yv$E^M7Hk*V;-oK5l`0E3(V4q9 zXy-_9&lXDQ%O@fBG|-B8)9Xb+rQ1I+M65$jeQ%2hT@iheW=$qG6Y}j*Z1ilU`6=i* zx|o<;7H!pQQ%+UG*dL5WIw$hpWBBXLLG446gqZky2A7ceYSN2tP|aG6#4Zl)zBK)wM)S0uAPu;gdgA{$fMJ*?15KLJi5SCVl3}Kn`d}D_ zVeDW-%`gm;aoA8Z48vp`&QUWA!(<%xs2PS~G7Z50&!OZC3F-t(00000NkvXXu0mjf DJ^-&# literal 0 HcmV?d00001 diff --git a/lab4/report/report.tex b/lab4/report/report.tex index 1518846..227ce6d 100644 --- a/lab4/report/report.tex +++ b/lab4/report/report.tex @@ -391,45 +391,558 @@ \phantom{text} \section{Особенности реализации} - \subsection{Token} + \subsection{Изменения в лексическом анализаторе} + \subsubsection{Файл \texttt{Scanner.h}} + В перечисление \texttt{Token} в файле \texttt{Scanner.h} были добавлены новые токены: \texttt{INC}, \texttt{DEC}. Код обновлённого перечисления представлен в листинге~\ref{lst:token}, добавлены строки 24-25. +\begin{lstlisting}[language=C++, caption=Обновлённое перечисление \texttt{Token}, label=lst:token] +enum Token { + T_EOF, // Конец текстового потока + T_ILLEGAL, // Признак недопустимого символа + T_IDENTIFIER, // Идентификатор + T_NUMBER, // Целочисленный литерал + T_BEGIN, // Ключевое слово "begin" + T_END, // Ключевое слово "end" + T_IF, // Ключевое слово "if" + T_THEN, // Ключевое слово "then" + T_ELSE, // Ключевое слово "else" + T_FI, // Ключевое слово "fi" + T_WHILE, // Ключевое слово "while" + T_DO, // Ключевое слово "do" + T_OD, // Ключевое слово "od" + T_WRITE, // Ключевое слово "write" + T_READ, // Ключевое слово "read" + T_ASSIGN, // Оператор ":=" + T_ADDOP, // Сводная лексема для "+" и "-" (операция типа сложения) + T_MULOP, // Сводная лексема для "*" и "/" (операция типа умножения) + T_CMP, // Сводная лексема для операторов отношения + T_LPAREN, // Открывающая скобка + T_RPAREN, // Закрывающая скобка + T_SEMICOLON, // ";" + T_INC, // Оператор инкремента + T_DEC // Оператор декремента +}; +\end{lstlisting} + + \subsubsection{Файл \texttt{Scanner.cpp}} + В массив названий токенов \texttt{tokenNames\_} были добавлены новые строки, соответствующие инкременту и декременту: \texttt{"++"} и \texttt{"\textminus\textminus"}, соответственно. Код обновлённого массива представлен в листинге~\ref{lst:token_names}, добавлены строки 24-25. + +\begin{lstlisting}[language=C++, caption=Обновлённый массив \texttt{tokenNames\_}, label=lst:token_names] + static const char * tokenNames_[] = { + "end of file", + "illegal token", + "identifier", + "number", + "'BEGIN'", + "'END'", + "'IF'", + "'THEN'", + "'ELSE'", + "'FI'", + "'WHILE'", + "'DO'", + "'OD'", + "'WRITE'", + "'READ'", + "':='", + "'+' or '-'", + "'*' or '/'", + "comparison operator", + "'('", + "')'", + "';'", + "'++'", + "'--'", + }; +\end{lstlisting} + + Также была обновлена функция \texttt{nextToken()}. В ней были добавлены новые условия для распознавания инкремента и декремента. Код обновлённой функции представлен в листинге~\ref{lst:next_token}, изменения коснулись строк 158-181. + +\begin{lstlisting}[language=C++, caption=Обновлённая функция \texttt{nextToken()}, label=lst:next_token] +void Scanner::nextToken() +{ + skipSpace(); + + // Пропускаем комментарии + // Если встречаем "/", то за ним должна идти "*". Если "*" не встречена, считаем, что встретили операцию деления + // и лексему - операция типа умножения. Дальше смотрим все символы, пока не находим звездочку или символ конца файла. + // Если нашли * - проверяем на наличие "/" после нее. Если "/" не найден - ищем следующую "*". + while(ch_ == '/') { + nextChar(); + if(ch_ == '*') { + nextChar(); + bool inside = true; + while(inside) { + while(ch_ != '*' && !input_.eof()) { + nextChar(); + } + + if(input_.eof()) { + token_ = T_EOF; + return; + } + + nextChar(); + if(ch_ == '/') { + inside = false; + nextChar(); + } + } + } + else { + token_ = T_MULOP; + arithmeticValue_ = A_DIVIDE; + return; + } + + skipSpace(); + } + + //Если встречен конец файла, считаем за лексему конца файла. + if(input_.eof()) { + token_ = T_EOF; + return; + } + //Если встретили цифру, то до тех пока дальше идут цифры - считаем как продолжение числа. + //Запоминаем полученное целое, а за лексему считаем целочисленный литерал + + if(isdigit(ch_)) { + int value = 0; + while(isdigit(ch_)) { + value = value * 10 + (ch_ - '0'); //поразрядное считывание, преобразуем символьное значение к числу. + nextChar(); + } + token_ = T_NUMBER; + intValue_ = value; + } + //Если же следующий символ - буква ЛА - тогда считываем до тех пор, пока дальше буквы ЛА или цифры. + //Как только считали имя переменной, сравниваем ее со списком зарезервированных слов. Если не совпадает ни с одним из них, + //считаем, что получили переменную, имя которой запоминаем, а за текущую лексему считаем лексему идентификатора. + //Если совпадает с каким-либо словом из списка - считаем что получили лексему, соответствующую этому слову. + else if(isIdentifierStart(ch_)) { + string buffer; + while(isIdentifierBody(ch_)) { + buffer += ch_; + nextChar(); + } + + transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower); + + map::iterator kwd = keywords_.find(buffer); + if(kwd == keywords_.end()) { + token_ = T_IDENTIFIER; + stringValue_ = buffer; + } + else { + token_ = kwd->second; + } + } + //Символ не является буквой, цифрой, "/" или признаком конца файла + else { + switch(ch_) { + //Признак лексемы открывающей скобки - встретили "(" + case '(': + token_ = T_LPAREN; + nextChar(); + break; + //Признак лексемы закрывающей скобки - встретили ")" + case ')': + token_ = T_RPAREN; + nextChar(); + break; + //Признак лексемы ";" - встретили ";" + case ';': + token_ = T_SEMICOLON; + nextChar(); + break; + //Если встречаем ":", то дальше смотрим наличие символа "=". Если находим, то считаем что нашли лексему присваивания + //Иначе - лексема ошибки. + case ':': + nextChar(); + if(ch_ == '=') { + token_ = T_ASSIGN; + nextChar(); + + } + else { + token_ = T_ILLEGAL; + } + break; + //Если встретили символ "<", то либо следующий символ "=", тогда лексема нестрогого сравнения. Иначе - строгого. + case '<': + token_ = T_CMP; + nextChar(); + if(ch_ == '=') { + cmpValue_ = C_LE; + nextChar(); + } + else { + cmpValue_ = C_LT; + } + break; + //Аналогично предыдущему случаю + case '>': + token_ = T_CMP; + nextChar(); + if(ch_ == '=') { + cmpValue_ = C_GE; + nextChar(); + } + else { + cmpValue_ = C_GT; + } + break; + //Если встретим "!", то дальше должно быть "=", тогда считаем, что получили лексему сравнения + //и знак "!=" иначе считаем, что у нас лексема ошибки + case '!': + nextChar(); + if(ch_ == '=') { + nextChar(); + token_ = T_CMP; + cmpValue_ = C_NE; + } + else { + token_ = T_ILLEGAL; + } + break; + //Если встретим "=" - лексема сравнения и знак "=" + case '=': + token_ = T_CMP; + cmpValue_ = C_EQ; + nextChar(); + break; + //Знаки операций. Для "+"/"-" получим лексему операции типа сложнения, и соответствующую операцию. + //для "*" - лексему операции типа умножения + case '+': + nextChar(); + + // Ищем оператор инкремента + if(ch_ == '+') { + token_ = T_INC; + nextChar(); + } + else { + token_ = T_ADDOP; + arithmeticValue_ = A_PLUS; + } + break; + + case '-': + nextChar(); + + // Ищем оператор декремента + if(ch_ == '-') { + token_ = T_DEC; + nextChar(); + } + else { + token_ = T_ADDOP; + arithmeticValue_ = A_MINUS; + } + break; + + case '*': + token_ = T_MULOP; + arithmeticValue_ = A_MULTIPLY; + nextChar(); + break; + //Иначе лексема ошибки. + default: + token_ = T_ILLEGAL; + nextChar(); + break; + } + } +} +\end{lstlisting} + + \subsection{Изменения в компиляторе} + + \subsubsection{Файл \texttt{Parser.cpp}} + В метод \texttt{factor()} объекта \texttt{Parser} была добавлена логика генерации команд для префиксного и постфиксного инкремента и декремента. Код обновлённого метода представлен в листинге~\ref{lst:parser_cpp}, изменения коснулись строк 20-27 (постфиксный инкремент и декремент) и строк 29-41 (префиксный инкремент и декремент). + + Для постфиксного инкремента и декремента генерируется следующая последовательность команд виртуальной машины языка MiLan: + \begin{itemize} + \item \texttt{LOAD <адрес переменной>} - загрузка значения переменной на вершину стека. + \item \texttt{DUP} - дублирование значения на вершине стека до выполнения операции инкремента или декремента, так как постфиксная операция возвращает старое значение переменной. + \item \texttt{PUSH 1} - загрузка константы 1 на вершину стека + \item \texttt{ADD} или \texttt{SUB} - сложение или вычитание значения на вершине стека с константой 1. + \item \texttt{STORE <адрес переменной>} - сохранение результата на вершине стека по адресу переменной. + \end{itemize} + + Для префиксного инкремента и декремента генерируется следующая последовательность команд виртуальной машины языка MiLan: + \begin{itemize} + \item \texttt{LOAD <адрес переменной>} - загрузка значения переменной на вершину стека. + \item \texttt{PUSH 1} - загрузка константы 1 на вершину стека + \item \texttt{ADD} или \texttt{SUB} - сложение или вычитание значения на вершине стека с константой 1. + \item \texttt{DUP} - дублирование значения на вершине стека после выполнения операции инкремента или декремента, так как префиксная операция возвращает новое значение переменной. + \item \texttt{STORE <адрес переменной>} - сохранение результата на вершине стека по адресу переменной. + \end{itemize} + + +\begin{lstlisting}[language=C++, caption=Обновлённый метод \texttt{factor()}, label=lst:parser_cpp] +void Parser::factor() +{ + /* + Множитель описывается следующими правилами: + -> number | identifier | - | () | READ + | ++ identifier | -- identifier | identifier++ | identifier-- + */ + if(see(T_NUMBER)) { + int value = scanner_->getIntValue(); + next(); + codegen_->emit(PUSH, value); + //Если встретили число, то преобразуем его в целое и записываем на вершину стека + } + else if(see(T_IDENTIFIER)) { + int varAddress = findOrAddVariable(scanner_->getStringValue()); + next(); + codegen_->emit(LOAD, varAddress); + //Если встретили переменную, то выгружаем значение, лежащее по ее адресу, на вершину стека + + // Постфиксный инкремент или декремент + if(see(T_INC) || see(T_DEC)) { + codegen_->emit(DUP); + codegen_->emit(PUSH, 1); + codegen_->emit(see(T_INC) ? ADD : SUB); + codegen_->emit(STORE, varAddress); + next(); + } + } + // Префиксный инкремент или декремент + else if(see(T_INC) || see(T_DEC)) { + bool isIncrement = see(T_INC); + next(); + mustBe(T_IDENTIFIER); + int varAddress = findOrAddVariable(scanner_->getStringValue()); + + codegen_->emit(LOAD, varAddress); + codegen_->emit(PUSH, 1); + codegen_->emit(isIncrement ? ADD : SUB); + codegen_->emit(DUP); + codegen_->emit(STORE, varAddress); + } + else if(see(T_ADDOP) && scanner_->getArithmeticValue() == A_MINUS) { + next(); + factor(); + codegen_->emit(INVERT); + //Если встретили знак "-", и за ним то инвертируем значение, лежащее на вершине стека + } + else if(match(T_LPAREN)) { + expression(); + mustBe(T_RPAREN); + //Если встретили открывающую скобку, тогда следом может идти любое арифметическое выражение и обязательно + //закрывающая скобка. + } + else if(match(T_READ)) { + codegen_->emit(INPUT); + //Если встретили зарезервированное слово READ, то записываем на вершину стека идет запись со стандартного ввода + } + else { + reportError("expression expected."); + } +} +\end{lstlisting} \newpage \section{Результаты работы программы} - Результаты работы программы представлены на Рис.~\ref{fig:result1}. + \subsection*{Программа №1} + Исходный код программы представлен в листинге~\ref{lst:program1}. - % \begin{figure}[h!] - % \centering - % \includegraphics[width=1\linewidth]{img/result1.png} - % \caption{Результаты работы программы.} - % \label{fig:result1} - % \end{figure} +\begin{lstlisting}[caption=Исходный код программы №1, label=lst:program1] +BEGIN + x := 0; + write(x++); + write(x); + write(++x); + write(x) +END +\end{lstlisting} - % % \newpage + Последовательность команд, сгенерированная компилятором для данной программы, представлена в листинге~\ref{lst:program1_commands}. - % \begin{figure}[h!] - % \centering - % \includegraphics[width=0.5\linewidth]{img/wrong.png} - % \caption{Реакция программы на некорректный пользовательский ввод.} - % \label{fig:wrong} - % \end{figure} - На Рис.~\ref{fig:wrong} представлена реакция программы на некорректный пользовательский ввод. +\begin{lstlisting}[caption={Последовательность команд, сгенерированная компилятором для программы №1.}, label={lst:program1_commands}, numbers=none] +0: PUSH 0 +1: STORE 0 +2: LOAD 0 +3: DUP +4: PUSH 1 +5: ADD +6: STORE 0 +7: PRINT +8: LOAD 0 +9: PRINT +10: LOAD 0 +11: PUSH 1 +12: ADD +13: DUP +14: STORE 0 +15: PRINT +16: LOAD 0 +17: PRINT +18: STOP +\end{lstlisting} + + Результаты работы виртуальной машины для программы №1 представлены на Рис.~\ref{fig:result1}. + + \begin{figure}[h!] + \centering + \includegraphics[width=0.4\linewidth]{img/result1.png} + \caption{Результаты работы виртуальной машины для программы №1.} + \label{fig:result1} + \end{figure} + + \subsection*{Программа №2} + Исходный код программы представлен в листинге~\ref{lst:program2}. + +\begin{lstlisting}[caption=Исходный код программы №2, label=lst:program2] +BEGIN + i := 1; + j := 2; + + IF i < --j THEN WRITE(100) ELSE WRITE(-100) FI +END +\end{lstlisting} + + Последовательность команд, сгенерированная компилятором для данной программы, представлена в листинге~\ref{lst:program2_commands}. + + +\begin{lstlisting}[caption={Последовательность команд, сгенерированная компилятором для программы №2.}, label={lst:program2_commands}, numbers=none] +0: PUSH 1 +1: STORE 0 +2: PUSH 2 +3: STORE 1 +4: LOAD 0 +5: LOAD 1 +6: PUSH 1 +7: SUB +8: DUP +9: STORE 1 +10: COMPARE 2 +11: JUMP_NO 15 +12: PUSH 100 +13: PRINT +14: JUMP 18 +15: PUSH 100 +16: INVERT +17: PRINT +18: STOP +\end{lstlisting} + + Результаты работы виртуальной машины для программы №2 представлены на Рис.~\ref{fig:result2}. + + \begin{figure}[h!] + \centering + \includegraphics[width=0.4\linewidth]{img/result2.png} + \caption{Результаты работы виртуальной машины для программы №2.} + \label{fig:result2} + \end{figure} + + \subsection*{Программа №3} + Исходный код программы представлен в листинге~\ref{lst:program3}. + +\begin{lstlisting}[caption=Исходный код программы №3, label=lst:program3] + BEGIN + y := x++; + write(y); + write(x); + + y := 10 - --x; + write(y); + write(x); + + y := 10 -++x; + write(y); + write(x) +END +\end{lstlisting} + + Последовательность команд, сгенерированная компилятором для данной программы, представлена в листинге~\ref{lst:program3_commands}. + +\begin{lstlisting}[caption={Последовательность команд, сгенерированная компилятором для программы №3.}, label={lst:program3_commands}, numbers=none] +0: LOAD 1 +1: DUP +2: PUSH 1 +3: ADD +4: STORE 1 +5: STORE 0 +6: LOAD 0 +7: PRINT +8: LOAD 1 +9: PRINT +10: PUSH 10 +11: LOAD 1 +12: PUSH 1 +13: SUB +14: DUP +15: STORE 1 +16: SUB +17: STORE 0 +18: LOAD 0 +19: PRINT +20: LOAD 1 +21: PRINT +22: PUSH 10 +23: LOAD 1 +24: PUSH 1 +25: ADD +26: DUP +27: STORE 1 +28: SUB +29: STORE 0 +30: LOAD 0 +31: PRINT +32: LOAD 1 +33: PRINT +34: STOP +\end{lstlisting} + + Результаты работы виртуальной машины для программы №3 представлены на Рис.~\ref{fig:result3}. + + \begin{figure}[h!] + \centering + \includegraphics[width=0.4\linewidth]{img/result3.png} + \caption{Результаты работы виртуальной машины для программы №3.} + \label{fig:result3} + \end{figure} + + \subsection*{Программа №4} + Исходный код программы представлен в листинге~\ref{lst:program4}. + +\begin{lstlisting}[caption=Исходный код программы №4, label=lst:program4] + BEGIN + x := 10; + y := 10 - --x; /* Корректно: минус и декремент разделены пробелом */ + y := 10 ---x; /* Некорректно: три минуса подряд */ +END +\end{lstlisting} + + Результат запуска компилятора для данной программы представлен на Рис.~\ref{fig:result4}. + + \begin{figure}[h!] + \centering + \includegraphics[width=0.5\linewidth]{img/result4.png} + \caption{Результат запуска компилятора для программы №4.} + \label{fig:result4} + \end{figure} \newpage \section*{Заключение} \addcontentsline{toc}{section}{Заключение} - В ходе выполнения лабораторной работы была построена контекстно-свободная грамматика для подмножества немецкого языка, описывающая простое прошедшее время Претерит. На основе разработанной грамматики была реализована программа, которая проверяет принадлежность входной строки заданному языку и генерирует случайные корректные предложения. Для анализа предложений использовался алгоритм LL(1)-разбора, основанный на построении множеств FIRST и FOLLOW для всех нетерминалов грамматики и создании таблицы синтаксического анализа. + В ходе выполнения лабораторной работы была успешно реализована поддержка операций инкремента и декремента в компиляторе языка MiLan. Были добавлены как префиксные (\texttt{++i}, \texttt{--i}), так и постфиксные (\texttt{i++}, \texttt{i--}) операторы с корректной семантикой их выполнения. Модификации затронули как лексический анализатор (добавление новых токенов \texttt{T\_INC} и \texttt{T\_DEC}), так и синтаксический анализатор (расширение метода \texttt{factor()} для обработки новых конструкций). - Из достоинств выполнения лабораторной работы можно выделить возможность задания грамматики в отдельном текстовом файле, что позволяет легко изменять и расширять её без модификации программного кода. Также программа автоматически проверяет, что введенная грамматика является LL(1)-грамматикой. В противном случае, программа выводит сообщение об ошибке, в указывается на конкретные правила грамматики, между выбором которых возникает неоднозначность. + Расширенная грамматика языка MiLan сохранила свойство LL(1), что позволило избежать значительных изменений в существующей архитектуре компилятора. Было добавлено лишь несколько новых правил в определение нетерминала \texttt{}. - К недостаткам текущей реализации можно отнести ограниченность словарного запаса, что сужает разнообразие генерируемых предложений. Также алгоритм генерации не контролирует длину предложений, что может приводить к избыточно длинным или коротким конструкциям. В текущей версии система не учитывает некоторые грамматические особенности немецкого языка, например, склонение прилагательных и согласование артиклей с родом существительных. + Из достоинств реализации можно отметить минимальность вносимых изменений в существующую архитектуру компилятора и сохранение всех ранее реализованных функций. При этом реализация выполняет поставленные задачи, корректно обрабатывая возможные случаи использования операторов инкремента и декремента. - Функционал программы несложно масштабировать. Грамматику легко расширять, добавляя новые слова и правила в текстовый файл без необходимости изменения программного кода. Класс Grammar может служить хорошей основой для создания полноценного LL(k) анализатора. + К недостаткам текущей реализации можно отнести отсутствие каких-либо оптимизаций при генерации команд виртуальной машины, что может приводить к избыточному количеству инструкций. Также в коде наблюдается некоторое дублирование логики между обработкой инкремента и декремента. - На выполнение лабораторной работы ушло около 12 часов. Работа была выполнена в среде разработки Visual Studio Code. Программа написана на Python версии 3.13. + В качестве направлений масштабирования можно предложить добавление составных операторов присваивания (\texttt{+=}, \texttt{-=}, \texttt{*=}, \texttt{/=}), для которых генерируется схожая последовательность низкоуровневых команд. Также возможна реализация оптимизаций генерируемого кода, таких как устранение избыточных команд в простых случаях. + + На выполнение лабораторной работы ушло около 6 часов. Работа была выполнена в среде разработки Visual Studio Code. \newpage \section*{Список литературы}