Компилятор и вм милана
This commit is contained in:
4
lab4/.gitignore
vendored
Normal file
4
lab4/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.zip
|
||||||
|
*.cmil
|
||||||
|
cmilan/src/cmilan.exe
|
||||||
|
!cmilan/doc/cmilan.pdf
|
||||||
10
lab4/cmilan/doc/Makefile
Normal file
10
lab4/cmilan/doc/Makefile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
cmilan.pdf: cmilan.tex
|
||||||
|
pdflatex cmilan.tex
|
||||||
|
pdflatex cmilan.tex
|
||||||
|
pdflatex cmilan.tex
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f cmilan.aux
|
||||||
|
rm -f cmilan.toc
|
||||||
|
rm -f cmilan.log
|
||||||
|
|
||||||
BIN
lab4/cmilan/doc/cmilan.pdf
Normal file
BIN
lab4/cmilan/doc/cmilan.pdf
Normal file
Binary file not shown.
956
lab4/cmilan/doc/cmilan.tex
Normal file
956
lab4/cmilan/doc/cmilan.tex
Normal file
@@ -0,0 +1,956 @@
|
|||||||
|
\documentclass[a4paper,12pt]{article}
|
||||||
|
\usepackage{ucs}
|
||||||
|
\usepackage{cmap}
|
||||||
|
\usepackage[utf8x]{inputenc}
|
||||||
|
\usepackage[T2A]{fontenc}
|
||||||
|
\usepackage[english,russian]{babel}
|
||||||
|
\usepackage[hmargin=2cm,vmargin=2cm]{geometry}
|
||||||
|
\usepackage{indentfirst}
|
||||||
|
\usepackage{listings}
|
||||||
|
\usepackage{syntax}
|
||||||
|
\usepackage[section]{placeins}
|
||||||
|
|
||||||
|
\setlength{\grammarparsep}{10pt plus 1pt minus 1pt}
|
||||||
|
\setlength{\grammarindent}{9em}
|
||||||
|
|
||||||
|
\lstset{
|
||||||
|
frame=TB,
|
||||||
|
morekeywords={begin,end,if,then,else,fi,while,do,od,write,read}
|
||||||
|
}
|
||||||
|
|
||||||
|
\title{Компилятор \textsc{CMilan}}
|
||||||
|
\author{Э. Ф. Аллахвердиев, Д. А. Тимофеев}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\maketitle
|
||||||
|
\tableofcontents
|
||||||
|
|
||||||
|
\section{Обзор языка Милан}
|
||||||
|
|
||||||
|
Язык Милан --- учебный язык программирования, описанный в
|
||||||
|
учебнике~\cite{karpov05}.
|
||||||
|
|
||||||
|
Программа на Милане представляет собой последовательность операторов,
|
||||||
|
заключенных между ключевыми словами \texttt{begin} и \texttt{end}. Операторы
|
||||||
|
отделяются друг от друга точкой с запятой. После последнего оператора в блоке
|
||||||
|
точка с запятой не ставится. Компилятор \textsc{CMilan} не учитывает регистр
|
||||||
|
символов в именах переменных и ключевых словах.
|
||||||
|
|
||||||
|
В базовую версию языка Милан входят следующие конструкции: константы,
|
||||||
|
идентификаторы, арифметические операции над целыми числами, операторы чтения
|
||||||
|
чисел со стандартного ввода и печати чисел на стандартный вывод, оператор
|
||||||
|
присваивания, условный оператор, оператор цикла с предусловием.
|
||||||
|
|
||||||
|
Программа может содержать комментарии, которые могут быть многострочными.
|
||||||
|
Комментарий начинается символами `\texttt{/*}' и заканчивается символами
|
||||||
|
`\texttt{*/}'. Вложенные комментарии не допускаются.
|
||||||
|
|
||||||
|
Грамматика языка Милан в расширенной форме Бэкуса-Наура приведена на
|
||||||
|
рисунке~\ref{milan-grammar}.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{grammar}
|
||||||
|
|
||||||
|
<program> ::= `begin' <statementList> `end'
|
||||||
|
|
||||||
|
<statementList> ::= <statement> `;' <statementList>
|
||||||
|
\alt $\epsilon$
|
||||||
|
|
||||||
|
<statement> ::= <ident> `:=' <expression>
|
||||||
|
\alt `if' <relation> `then' <statementList> [`else' <statementList>] `fi'
|
||||||
|
\alt `while' <relation> `do' <statementList> `od'
|
||||||
|
\alt `write' `(' <expression> `)'
|
||||||
|
|
||||||
|
<expression> ::= <term> \{<addop> <term>\}
|
||||||
|
|
||||||
|
<term> ::= <factor> \{<mulop> <factor>\}
|
||||||
|
|
||||||
|
<factor> ::= <ident> | <number> | `(' <expression> `)'
|
||||||
|
|
||||||
|
<relation> ::= <expression> <cmp> <expression>
|
||||||
|
|
||||||
|
<addop> ::= `+' | `-'
|
||||||
|
|
||||||
|
<multop> ::= `*' | `/'
|
||||||
|
|
||||||
|
<cmp> ::= `=' | `!=' | `<' | `<=' | `>' | `>='
|
||||||
|
|
||||||
|
<ident> ::= <letter> \{<letter> | <digit>\}
|
||||||
|
|
||||||
|
<letter> ::= `a' | `b' | `c' | \ldots | `z' | `A' | `B' | `C' | \ldots | `Z'
|
||||||
|
|
||||||
|
<digit> ::= `0' | `1' | `2' | `3' | `4' | `5' | `6' | `7' | `8' | `9'
|
||||||
|
|
||||||
|
\end{grammar}
|
||||||
|
\label{milan-grammar}
|
||||||
|
\caption{Грамматика языка Милан}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\subsection{Константы}
|
||||||
|
|
||||||
|
В языке реализована поддержка знаковых целочисленных констант. Синтаксически
|
||||||
|
константы представляют собой последовательность цифр, перед которой может
|
||||||
|
находиться знак `-'. Примеры констант: \texttt{0}, \texttt{9}, \texttt{1234},
|
||||||
|
\texttt{-19}, \texttt{-0}.
|
||||||
|
|
||||||
|
\subsection{Идентификаторы}
|
||||||
|
|
||||||
|
Идентификаторы представляют собой последовательность букв латинского алфавита и
|
||||||
|
цифр. Первым символом идентификатора должна быть буква. Максимальная длина
|
||||||
|
идентификатора ограничена 63 символами. Регистр символов не учитывается.
|
||||||
|
Идентификаторы не должны совпадать с ключевыми словами \texttt{begin},
|
||||||
|
\texttt{end}, \texttt{if}, \texttt{then}, \texttt{else}, \texttt{fi},
|
||||||
|
\texttt{do}, \texttt{od}, \texttt{while}, \texttt{read}, \texttt{write}.
|
||||||
|
|
||||||
|
Примеры идентификаторов: \texttt{a}, \texttt{X}, \texttt{GCD}, \texttt{Milan23}.
|
||||||
|
Цепочки символов, недопустимые в качестве идентификаторов: \texttt{12a} (первый
|
||||||
|
символ не является буквой), \texttt{Begin} (цепочка символов совпадает с
|
||||||
|
ключевым словом), \texttt{a\_1} (цепочка содержит символ подчеркивания).
|
||||||
|
|
||||||
|
\subsection{Арифметические выражения}
|
||||||
|
|
||||||
|
\begin{grammar}
|
||||||
|
<expression> ::= <term> \{<addop> <term>\}
|
||||||
|
|
||||||
|
<term> ::= <factor> \{<mulop> <factor>\}
|
||||||
|
|
||||||
|
<factor> ::= <ident> | <number> | `(' <expression> `)'
|
||||||
|
\end{grammar}
|
||||||
|
|
||||||
|
Арифметические выражения строятся по традиционным для языков программирования
|
||||||
|
правилам. Элементами арифметических выражений могут быть константы,
|
||||||
|
идентификаторы, знаки арифметических операций `\texttt{+}' (сложение),
|
||||||
|
`\texttt{-}' (вычитание), `\texttt{*}' (умножение), `\texttt{/}'
|
||||||
|
(деление), скобки и ключевое слово \texttt{read}, которое обозначает операцию
|
||||||
|
чтения числа со стандартного ввода.
|
||||||
|
|
||||||
|
Примеры правильных выражений: \texttt{12 + 4}, \texttt{i}, \texttt{(x+1)*y},
|
||||||
|
\texttt{2*x+1}, \texttt{read}, \texttt{read * (x - read)}.
|
||||||
|
|
||||||
|
Операции `\texttt{*}' и `\texttt{/}' имеют более высокий приоритет, чем
|
||||||
|
операции `\texttt{+}' и `\texttt{-}'. Все эти операции левоассоциативны.
|
||||||
|
|
||||||
|
Значения арифметических выражений вычисляются слева направо с учетом приоритета
|
||||||
|
операций. Порядок вычисления важен из-за присутствия операции \texttt{read},
|
||||||
|
благодаря которой вычисление значения выражения имеет побочный эффект.
|
||||||
|
|
||||||
|
\subsection{Печать чисел на стандартный вывод}
|
||||||
|
|
||||||
|
\begin{grammar}
|
||||||
|
<statement> ::= `write' `(' <expression> `)'
|
||||||
|
\end{grammar}
|
||||||
|
|
||||||
|
Печать чисел осуществляется с помощью оператора \texttt{write}, аргументом
|
||||||
|
которого является произвольное арифметическое выражение. Примеры использования
|
||||||
|
оператора \texttt{write}: \texttt{write(5)},
|
||||||
|
\texttt{write(n+7)}, \texttt{write((2+read)*3)}, \texttt{write(read)}.
|
||||||
|
|
||||||
|
\subsection{Оператор присваивания}
|
||||||
|
|
||||||
|
\begin{grammar}
|
||||||
|
<statement> ::= <ident> `:=' <expression>
|
||||||
|
\end{grammar}
|
||||||
|
|
||||||
|
При выполнении оператора присваивания сначала вычисляется значение выражения,
|
||||||
|
записанного в его правой части. Затем результат записывается в ячейку памяти,
|
||||||
|
соответствующую переменной в левой части оператора присваивания.
|
||||||
|
|
||||||
|
Последовательность символов `\texttt{:=}' является неделимой и не может
|
||||||
|
содержать пробелов между символами `\texttt{:}' и `\texttt{=}'.
|
||||||
|
|
||||||
|
Примеры корректных операторов присваивания: \texttt{a := b + 1}, \texttt{c :=
|
||||||
|
read}.
|
||||||
|
|
||||||
|
\subsection{Условный оператор}
|
||||||
|
|
||||||
|
\begin{grammar}
|
||||||
|
<statement> ::= `if' <relation> `then' <statementList> [`else' <statementList>] `fi'
|
||||||
|
|
||||||
|
<relation> ::= <expression> <cmp> <expression>
|
||||||
|
|
||||||
|
<cmp> ::= `=' | `!=' | `<' | `<=' | `>' | `>='
|
||||||
|
\end{grammar}
|
||||||
|
|
||||||
|
Условный оператор включает:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item условие, которое представляет собой проверку на равенство или неравенство
|
||||||
|
двух арифметических выражений,
|
||||||
|
\item последовательность операторов, которая должна быть выполнена, если условие
|
||||||
|
истинно (блок \texttt{then}),
|
||||||
|
\item необязательную последовательность операторов, которая должна быть
|
||||||
|
выполнена, если условие ложно (блок \texttt{else}).
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Проверка условия $a ? b$, где $a$ и $b$ --- арифметические выражения, а <<$?$>>
|
||||||
|
--- один из операторов сравнения, производится следующим образом:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item вычисляется значение выражения $a$;
|
||||||
|
\item вычисляется значение выражения $b$;
|
||||||
|
\item проверяется выполнение условия.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Поддерживаются следующие отношения: `\texttt{=}' (<<равно>>), `\texttt{!=}'
|
||||||
|
(<<не равно>>), `\texttt{<}' (<<меньше>>), `\texttt{<=}' (<<меньше или равно>>),
|
||||||
|
`\texttt{>}' (<<больше>>), `\texttt{>=}' (<<больше или равно>>).
|
||||||
|
|
||||||
|
Условный оператор завершается ключевым словом \texttt{fi}. Оно используется,
|
||||||
|
чтобы избежать известной проблемы <<висячего else>>, которая встречается, в
|
||||||
|
частности, в языках C, C++ и Java. Наличие <<закрывающей скобки>> \texttt{fi}
|
||||||
|
позволяет однозначно интерпретировать вложенные условные операторы.
|
||||||
|
|
||||||
|
Примеры использования условного оператора приведены на рисунках~\ref{ifthen} и
|
||||||
|
\ref{ifthenelse}. Обе эти программы считывают со стандартного ввода два числа.
|
||||||
|
Программа на рисунке~\ref{ifthen} печатает наибольшее из двух чисел. Программа
|
||||||
|
на рисунке~\ref{ifthenelse} печатает числа в порядке возрастания.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{lstlisting}
|
||||||
|
begin
|
||||||
|
x := read;
|
||||||
|
y := read;
|
||||||
|
max := x;
|
||||||
|
if y > max then
|
||||||
|
max := y
|
||||||
|
fi;
|
||||||
|
write (max)
|
||||||
|
end
|
||||||
|
\end{lstlisting}
|
||||||
|
\label{ifthen}
|
||||||
|
\caption{Пример условного оператора \texttt{if..then..fi}}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{lstlisting}
|
||||||
|
begin
|
||||||
|
x := read;
|
||||||
|
y := read;
|
||||||
|
if x <= y then
|
||||||
|
write (x);
|
||||||
|
write (y)
|
||||||
|
else
|
||||||
|
write (y);
|
||||||
|
write (x)
|
||||||
|
fi
|
||||||
|
end
|
||||||
|
\end{lstlisting}
|
||||||
|
\label{ifthenelse}
|
||||||
|
\caption{Пример условного оператора \texttt{if..then..else..fi}}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\subsection{Цикл с предусловием}
|
||||||
|
|
||||||
|
\begin{grammar}
|
||||||
|
<statement> ::= `while' <relation> `do' <statementList> `od'
|
||||||
|
|
||||||
|
<relation> ::= <expression> <cmp> <expression>
|
||||||
|
|
||||||
|
<cmp> ::= `=' | `!=' | `<' | `<=' | `>' | `>='
|
||||||
|
\end{grammar}
|
||||||
|
|
||||||
|
При выполнении цикла с предусловием сначала проверяется, истинно ли условие.
|
||||||
|
Если оно истинно, последовательно выполняются операторы, составляющие тело
|
||||||
|
цикла. После того, как последний оператор будет выполнен, управление снова
|
||||||
|
возвращается к проверке условия. Если условие оказывается ложным, выполнение
|
||||||
|
цикла завершается. Вычисление выражений, необходимых для проверки условия,
|
||||||
|
производится так же, как и при выполнении условного оператора.
|
||||||
|
|
||||||
|
Пример программы, использующей цикл, приведен на рисунке~\ref{while}. Эта
|
||||||
|
программа считывает со стандартного ввода число и печатает его факториал.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{lstlisting}
|
||||||
|
begin
|
||||||
|
n := read;
|
||||||
|
factorial := 1;
|
||||||
|
x := 1;
|
||||||
|
while x <= n do
|
||||||
|
factorial := factorial * x;
|
||||||
|
x := x + 1
|
||||||
|
od;
|
||||||
|
write (factorial)
|
||||||
|
end
|
||||||
|
\end{lstlisting}
|
||||||
|
\label{while}
|
||||||
|
\caption{Пример цикла с предусловием}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\section{Использование компилятора}
|
||||||
|
|
||||||
|
Компилятор \textsc{CMilan} преобразует программы на языке Милан в
|
||||||
|
последовательность команд виртуальной машины Милана. Общее описание виртуальной
|
||||||
|
машины можно найти в учебнике~\cite{karpov05}, а более детальное
|
||||||
|
описание --- или в документации, прилагаемой к исходным текстам виртуальной
|
||||||
|
машины.
|
||||||
|
|
||||||
|
Исполняемый файл компилятора называется \texttt{cmilan} (в операционных системах
|
||||||
|
семейства Unix) или \texttt{cmilan.exe} (в Windows). Компилятор имеет интерфейс
|
||||||
|
командной строки. Чтобы скомпилировать программу, записанную в файле
|
||||||
|
<<program.mil>>, нужно выполнить команду <<\texttt{cmilan program.mil}>>.
|
||||||
|
Результатом работы компилятора является либо последовательность команд для
|
||||||
|
виртуальной машины Милана, которая печатается на стандарный вывод, либо набор
|
||||||
|
сообщений о синтаксических ошибках, которые выводятся в стандартный поток
|
||||||
|
ошибок.
|
||||||
|
|
||||||
|
При вызове программы \texttt{cmilan} без параметров компилятор печатает краткую
|
||||||
|
информацию о порядке его вызова.
|
||||||
|
|
||||||
|
Чтобы сохранить генерируемую компилятором программу для виртуальной машины в
|
||||||
|
файл, достаточно перенаправить в этот файл стандартный поток вывода.
|
||||||
|
|
||||||
|
На рисунке~\ref{cmilan-usage} приведен пример сеанса работы с компилятором.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{verbatim}
|
||||||
|
bash$ cat factorial.mil
|
||||||
|
BEGIN
|
||||||
|
n := READ;
|
||||||
|
factorial := 1;
|
||||||
|
i := 1;
|
||||||
|
WHILE i <= n DO
|
||||||
|
factorial := factorial * i;
|
||||||
|
i := i + 1
|
||||||
|
OD;
|
||||||
|
WRITE(factorial)
|
||||||
|
END
|
||||||
|
bash$ cmilan factorial.mil > factorial.out
|
||||||
|
bash$ milanvm factorial.out
|
||||||
|
Reading input from factorial.out
|
||||||
|
> 5
|
||||||
|
120
|
||||||
|
\end{verbatim}
|
||||||
|
\label{cmilan-usage}
|
||||||
|
\caption{Пример использования компилятора \textsc{CMilan}}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\subsection{Сборка компилятора в Unix}
|
||||||
|
|
||||||
|
Для сборки компилятора в операционных системах семейства Unix (в частности,
|
||||||
|
GNU/Linux и FreeBSD) необходим компилятор C++, в качестве которого рекомендуется
|
||||||
|
использовать GCC, и GNU Make. Для сборки компилятора достаточно перейти в
|
||||||
|
каталог \texttt{src}, в котором расположены исходные тексты компилятора
|
||||||
|
\textsc{CMilan}, и выполнить команду \texttt{make}.
|
||||||
|
|
||||||
|
\subsection{Сборка компилятора в Windows}
|
||||||
|
|
||||||
|
Для сборки компилятора \textsc{CMilan} в Windows можно использовать компилятор
|
||||||
|
GCC или Microsoft Visual Studio. При использовании GCC (Cygwin, MinGW) сборка
|
||||||
|
производится так же, как и в Unix. Для сборки компилятора с помощью Visual
|
||||||
|
Studio 2010 в дистрибутив компилятора включены файлы проекта (каталог
|
||||||
|
\texttt{src\\cmilan\_vs2011}). Если необходимо использовать другие версии Visual
|
||||||
|
Studio, достаточно создать пустой проект консольного приложения Win32 и добавить
|
||||||
|
в проект существующие исходные тексты из каталога \texttt{src}.
|
||||||
|
|
||||||
|
\section{Устройство компилятора}
|
||||||
|
|
||||||
|
\subsection{Архитектура компилятора}
|
||||||
|
Компилятор \textsc{CMilan} включает три компонента:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item лексический анализатор;
|
||||||
|
\item синтаксический анализатор;
|
||||||
|
\item генератор команд виртуальной машины Милана.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Лексический анализатор посимвольно читает из входного потока текст программы и преобразует
|
||||||
|
группы символов в лексемы (терминальные символы грамматики языка Милан). При
|
||||||
|
этом он отслеживает номер текущей строки, который используется синтаксическим
|
||||||
|
анализатором при формировании сообщений об ошибках. Также лексический анализатор
|
||||||
|
удаляет пробельные символы и комментарии. При формировании лексем анализатор
|
||||||
|
идентифицирует ключевые слова и последовательности символов (например, оператор
|
||||||
|
присваивания), а также определяет значения числовых констант и имена переменных.
|
||||||
|
Эти значения становятся значениями атрибутов, связанных с лексемами.
|
||||||
|
|
||||||
|
Синтаксический анализатор читает сформированную лексическим анализатором
|
||||||
|
последовательность лексем и проверяет ее соответствие грамматике языка Милан.
|
||||||
|
Для этого используется метод рекурсивного спуска. Если в процессе
|
||||||
|
синтаксического анализа обнаруживается ошибка, анализатор формирует сообщение об
|
||||||
|
ошибке, включающее сведения об ошибке и номер строки, в которой она возникла.
|
||||||
|
В процессе анализа программы синтаксический анализатор генерирует набор машинных
|
||||||
|
команд, соответствующие каждой конструкции языка.
|
||||||
|
|
||||||
|
Генератор кода представляет собой служебный компонент, ответственный за
|
||||||
|
формирование внешнего представления генерируемого кода. Генератор поддерживает
|
||||||
|
буфер команд и предоставляет синтаксическому анализатору набор функций,
|
||||||
|
позволяющий записать указанную команду по определенному адресу. После того, как
|
||||||
|
синтаксический анализатор заканчивает формирование программы, генератор кода
|
||||||
|
используется для печати на стандартный вывод отсортированной по возрастанию
|
||||||
|
адресов последовательности инструкций. Использование генератора кода несколько
|
||||||
|
упрощает устройство компилятора, поскольку синтаксический анализатор может
|
||||||
|
генерировать команды не в порядке их следования в программе, а по мере получения
|
||||||
|
всей необходимой информации для их формирования. Это особенно важно при
|
||||||
|
трансляции таких инструкций, как условные операторы или циклы.
|
||||||
|
|
||||||
|
Все три компонента объединяются <<драйвером>> --- управляющей программой
|
||||||
|
компилятора. Драйвер анализирует аргументы командной строки, инициализирует
|
||||||
|
синтаксический анализатор и вызывает его метод \texttt{parse()}, запуская
|
||||||
|
процесс трансляции.
|
||||||
|
|
||||||
|
\textsc{CMilan} является примером простейшего однопроходного компилятора,
|
||||||
|
в котором синтаксический анализ и генерация кода выполняются совместно. При этом
|
||||||
|
компилятор никак не оптимизирует код. Реальные компиляторы
|
||||||
|
обычно выполняют трансляцию и оптимизацию кода в несколько проходов, используя
|
||||||
|
несколько видов внутреннего представления программы. Сведения об архитектуре
|
||||||
|
таких компиляторов можно найти, в частности, в классической <<книге
|
||||||
|
дракона>>~\cite{dragonbook11}. В случае \textsc{CMilan}, тем не менее,
|
||||||
|
предпочтение было отдано не качеству генерируемого кода, а простоте реализации и
|
||||||
|
легкости расширения.
|
||||||
|
|
||||||
|
\subsection{Генератор кода}
|
||||||
|
|
||||||
|
Основной задачей генератора кода является хранение и заполнение буфера
|
||||||
|
инструкций последовательностью команд для виртуальной машины Милана. Генератор
|
||||||
|
кода не отвечает за правильность этой последовательности и не выполняет никаких
|
||||||
|
семантических преобразований. Тем не менее, генератор кода вполне мог бы быть
|
||||||
|
расширен для того, чтобы выполнять простые оптимизации на уровне машинных
|
||||||
|
команд.
|
||||||
|
|
||||||
|
Генератор кода описан в файлах \texttt{codegen.h} и \texttt{codegen.cpp}. Его
|
||||||
|
реализация состоит из двух классов. Класс \texttt{Command} описывает машинные
|
||||||
|
инструкций и отвечает за их вывод. В классе Codegen реализованы функции добавления
|
||||||
|
инструкций в буфер, получения текущего адреса в буфере, резервирования ячейки
|
||||||
|
для инструкции, которая должна быть добавлена в код позднее, и печати
|
||||||
|
последовательности инструкций из буфера на стандартный вывод.
|
||||||
|
|
||||||
|
Приведем краткое описание методов генератора кода.
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{void Command::print(int address, ostream\& os)}
|
||||||
|
|
||||||
|
Печать инструкции с указанием адреса \texttt{address} в поток вывода \texttt{os}.
|
||||||
|
|
||||||
|
\item \texttt{void CodeGen::emit(Instruction instruction)}
|
||||||
|
|
||||||
|
Добавление инструкции \texttt{instruction} без аргументов в конец буфера.
|
||||||
|
|
||||||
|
\item \texttt{void CodeGen::emit(Instruction instruction, int arg)}
|
||||||
|
|
||||||
|
Добавление инструкции \texttt{instruction} с аргументом \texttt{arg} в конец буфера.
|
||||||
|
|
||||||
|
\item \texttt{void CodeGen::emitAt(int address, Instruction instruction)}
|
||||||
|
|
||||||
|
Запись инструкции \texttt{instruction} без аргументов в буфер со смещением
|
||||||
|
\texttt{address}.
|
||||||
|
|
||||||
|
\item \texttt{void CodeGen::emitAt(int address, Instruction instruction, int
|
||||||
|
arg)}
|
||||||
|
|
||||||
|
Запись инструкции \texttt{instruction} с аргументом \texttt{arg} в буфер
|
||||||
|
со смещением \texttt{address}
|
||||||
|
|
||||||
|
\item \texttt{int CodeGen::getCurrentAddress()}
|
||||||
|
|
||||||
|
Возврат адреса, по которому будет записана очередная инструкция.
|
||||||
|
|
||||||
|
\item \texttt{int CodeGen::reserve()}
|
||||||
|
|
||||||
|
Резервирование ячейки памяти для инструкции. Метод добавляет в конец
|
||||||
|
буфера инструкцию \texttt{NOP} и возвращает ее адрес.
|
||||||
|
|
||||||
|
\item \texttt{void CodeGen::flush()}
|
||||||
|
|
||||||
|
Вывод последовательности инструкций в выходной поток.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection{Лексический анализатор}
|
||||||
|
|
||||||
|
Лексический анализатор преобразует считываемые из входного потока символы в
|
||||||
|
лексемы языка Милан. Например, последовательность символов `\texttt{B}',
|
||||||
|
`\texttt{E}', `\texttt{G}', `\texttt{I}', `\texttt{N}' соответствует ключевому
|
||||||
|
слову `\texttt{begin}'. Каждой лексеме соответствует отдельный элемент
|
||||||
|
перечислимого типа \texttt{Token}. В частности, ключевому слову `\texttt{begin}'
|
||||||
|
соответствует константа \texttt{T\_BEGIN}. С некоторыми лексемами связана
|
||||||
|
дополнительная информация --- значение атрибута. Так, с лексемой
|
||||||
|
\texttt{T\_NUMBER} (целочисленная константа) связано число, равное значению этой
|
||||||
|
константы, а с лексемой \texttt{T\_IDENTIFIER} (идентификатор) --- строка,
|
||||||
|
содержащая имя переменной.
|
||||||
|
|
||||||
|
В таблице~\ref{lexemes} приведен полный список лексем и значений связанных с ними
|
||||||
|
атрибутов.
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{|l|l|p{6cm}|}
|
||||||
|
\hline
|
||||||
|
\hline
|
||||||
|
Имя лексемы & Значение & Атрибут \\
|
||||||
|
\hline
|
||||||
|
\hline
|
||||||
|
\texttt{T\_EOF} & Конец текстового потока & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_ILLEGAL} & Недопустимый символ & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_IDENTIFIER}& Идентификатор & Имя переменной \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_NUMBER} & Константа & Значение константы \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_BEGIN} & Ключевое слово `\texttt{begin}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_END} & Ключевое слово `\texttt{end}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_IF} & Ключевое слово `\texttt{if}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_THEN} & Ключевое слово `\texttt{then}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_ELSE} & Ключевое слово `\texttt{else}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_FI} & Ключевое слово `\texttt{fi}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_WHILE} & Ключевое слово `\texttt{while}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_DO} & Ключевое слово `\texttt{do}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_OD} & Ключевое слово `\texttt{od}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_WRITE} & Ключевое слово `\texttt{write}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_READ} & Ключевое слово `\texttt{read}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_ASSIGN} & Оператор `\texttt{:=}' & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_ADDOP} & Операция типа сложения &
|
||||||
|
\texttt{A\_PLUS}~(`\texttt{+}'), \texttt{A\_MINUS}~(`\texttt{-}') \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_MULOP} & Операция типа умножения &
|
||||||
|
\texttt{A\_MULTIPLY}~(`\texttt{*}'), \texttt{A\_DIVIDE}~(`\texttt{/}') \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_CMP} & Оператор отношения &
|
||||||
|
\texttt{C\_EQ}~(`\texttt{=}'), \texttt{C\_NE}~(`\texttt{!=}'),
|
||||||
|
\texttt{C\_LT}~(`\texttt{<}'), \texttt{C\_LE}~(`\texttt{<=}'),
|
||||||
|
\texttt{C\_GT}~(`\texttt{>}'), \texttt{C\_GE}~(`\texttt{=}') \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_LPAREN} & Открывающая скобка & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_RPAREN} & Закрывающая скобка & \\
|
||||||
|
\hline
|
||||||
|
\texttt{T\_SEMICOLON} & `\texttt{;}' & \\
|
||||||
|
\hline
|
||||||
|
\hline
|
||||||
|
\end{tabular}
|
||||||
|
\end{center}
|
||||||
|
\caption{Лексемы языка Милан}
|
||||||
|
\label{lexemes}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
Все ключевые слова перечислены в ассоциативном массиве \texttt{keywords\_}. При
|
||||||
|
этом ключом является строка, соответствующая ключевому слову в нижнем регистре,
|
||||||
|
а значением --- соответствующая лексема. С помощью массива \texttt{tokenNames\_}
|
||||||
|
каждой лексеме сопоставлено ее строковое внешнее представление, которое
|
||||||
|
используется при формировании сообщений об ошибках. Последовательность
|
||||||
|
символов, не соответствующая ни одной из лексем, считается ошибочной. В этом
|
||||||
|
случае лексический анализатор возвращает значение \texttt{T\_ILLEGAL}.
|
||||||
|
|
||||||
|
Исходный текст лексического анализатора находится в файлах \texttt{scanner.h} и
|
||||||
|
\texttt{scanner.cpp}. Алгоритм лексического анализа реализован в классе
|
||||||
|
\texttt{Scanner}. Он содержит следующие открытые методы:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{Token token()}
|
||||||
|
|
||||||
|
Получение текущей лексемы. Одна и та же лексема может быть прочитана
|
||||||
|
многократно.
|
||||||
|
|
||||||
|
\item \texttt{void nextToken()}
|
||||||
|
|
||||||
|
Переход к следующей лексеме.
|
||||||
|
|
||||||
|
\item \texttt{int getIntValue()}
|
||||||
|
|
||||||
|
Получение целочисленного атрибута текущей лексемы. В базовой версии Милана
|
||||||
|
этот метод используется только для получения значений целочисленных
|
||||||
|
констант.
|
||||||
|
|
||||||
|
\item \texttt{string getStringValue()}
|
||||||
|
|
||||||
|
Получение строкового атрибута текущей лексемы. В базовой версии Милана
|
||||||
|
этот метод используется для получения имен идентификаторов.
|
||||||
|
|
||||||
|
\item \texttt{Cmp getCmpValue()}
|
||||||
|
|
||||||
|
Получение кода операции сравнения текущей лексемы (используется только
|
||||||
|
вместе с лексемой \texttt{T\_CMP}).
|
||||||
|
|
||||||
|
\item \texttt{Arithmetic getArithmeticValue()}
|
||||||
|
|
||||||
|
Получение кода арифметической операции (используется вместе с лексемами
|
||||||
|
\texttt{T\_ADDOP} и \texttt{T\_MULOP}).
|
||||||
|
|
||||||
|
\item \texttt{const int getLineNumber()}
|
||||||
|
|
||||||
|
Получение номера текущей строки в исходном файле (используется при
|
||||||
|
формировании сообщений об ошибках).
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Поля класса описывают состояние лексического анализатора:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{const string fileName\_}
|
||||||
|
|
||||||
|
Имя входного файла.
|
||||||
|
|
||||||
|
\item \texttt{int lineNumber\_}
|
||||||
|
|
||||||
|
Номер текущей строки в анализируемой программе.
|
||||||
|
|
||||||
|
\item \texttt{Token token\_}
|
||||||
|
|
||||||
|
Текущая лексема.
|
||||||
|
|
||||||
|
\item \texttt{int intValue\_}
|
||||||
|
|
||||||
|
Целочисленный атрибут лексемы.
|
||||||
|
|
||||||
|
\item \texttt{string stringValue\_}
|
||||||
|
|
||||||
|
Строковый атрибут лексемы.
|
||||||
|
|
||||||
|
\item \texttt{Cmp cmpValue\_}
|
||||||
|
|
||||||
|
Код оператора сравнения.
|
||||||
|
|
||||||
|
\item \texttt{Arithmetic arithmeticValue\_}
|
||||||
|
|
||||||
|
Код арифметической операции.
|
||||||
|
|
||||||
|
\item \texttt{map<string, Token> keywords\_}
|
||||||
|
|
||||||
|
Ассоциативный массив, описывающий ключевые слова языка Милан. Используется
|
||||||
|
при обнаружении цепочки символов, которая может быть как идентификатором,
|
||||||
|
так и ключевым словом.
|
||||||
|
|
||||||
|
\item \texttt{ifstream input\_}
|
||||||
|
|
||||||
|
Входной поток для чтения из файла.
|
||||||
|
|
||||||
|
\item \texttt{char ch\_}
|
||||||
|
|
||||||
|
Очередной символ программы.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Закрытые методы класса (служебные функции):
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{bool isIdentifierStart(char c)}
|
||||||
|
|
||||||
|
Метод возвращает значение \texttt{true}, если символ \texttt{c} может быть
|
||||||
|
первым символом идентификатора (в базовой версии языка Милан это означает,
|
||||||
|
что символ является буквой латинского алфавита).
|
||||||
|
|
||||||
|
\item \texttt{bool isIdentifierBody(char c)}
|
||||||
|
|
||||||
|
Метод возвращает значение \texttt{true}, если символ \texttt{c} может
|
||||||
|
быть частью идентификатора. В базовой версии языка Милан эт означает, что
|
||||||
|
символ является буквой латинского алфавита или цифрой.
|
||||||
|
|
||||||
|
\item \texttt{void skipSpace()}
|
||||||
|
|
||||||
|
Пропуск всех пробельных символов (символов пробела, табуляции, перевода
|
||||||
|
строки). При чтении символа перевода строки увеличивается номер текущей
|
||||||
|
строки \texttt{lineNumber\_}.
|
||||||
|
|
||||||
|
\item \texttt{void nextChar()}
|
||||||
|
|
||||||
|
Переход к следующему символу программы.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Основная часть алгоритма лексического анализа реализована в методе
|
||||||
|
\texttt{nextToken}. Для того, чтобы перейти к следующей лексеме, выполняется
|
||||||
|
следующая последовательность действий,
|
||||||
|
|
||||||
|
Прежде всего необходимо удалить пробелы и комментарии. Признаком начала
|
||||||
|
комментария является последовательность символов `\texttt{/*}'. При обнаружении
|
||||||
|
символа `\texttt{/}' необходимо проверить следующий за ним символ. Если он не
|
||||||
|
совпадает с `\texttt{*}', значит, был найден оператор деления. В этом случае
|
||||||
|
переменной \texttt{token\_} присваивается значение \texttt{T\_MULOP}, а атрибуту
|
||||||
|
\texttt{arithmeticValue\_} --- значение \texttt{A\_DIVIDE}. Если за символом
|
||||||
|
`\texttt{/}' непосредственно следует `\texttt{*}', лексический анализатор
|
||||||
|
пропускает все символы, пока не встретит закрывающую комментарий
|
||||||
|
последовательность `\texttt{*/}' или конец файла. После того, как был найден
|
||||||
|
признак конца комментария, еще раз вызывается функция \texttt{skipSpace}.
|
||||||
|
Операция удаления комментариев повторяется многократно, пока очередной
|
||||||
|
непробельный символ не окажется отличным от символа `\texttt{/}'. Если в
|
||||||
|
процессе удаления пробелов или комментариев был встречен конец файла, очередной
|
||||||
|
лексемой считается \texttt{T\_EOF}.
|
||||||
|
|
||||||
|
После удаления пробелов и комментариев происходит анализ очередного символа. Он
|
||||||
|
выполняется по следующим правилам.
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Если символ является цифрой, то очередная лексема --- целочисленная константа
|
||||||
|
(\texttt{T\_NUMBER}). Лексический анализатор считывает из входного потока эту
|
||||||
|
и все следующие за ней цифры, преобразуя полученную последовательность в целое
|
||||||
|
число. Это число становится значением атрибута \texttt{intValue\_}.
|
||||||
|
|
||||||
|
\item Если символ может быть началом идентификатора, из потока считываются все
|
||||||
|
последующие символы, которые могут быть частью идентификатора. Полученная
|
||||||
|
последовательность проверяется на совпадение с ключевым словом. В случае
|
||||||
|
совпадения очередной лексемой считается лексема, соответствующая этому ключевому
|
||||||
|
слову. Если цепочка символов не совпала ни с одним ключевым словом, очередная
|
||||||
|
лексема считается идентификатором (\texttt{T\_IDENTIFIER}), а сама цепочка
|
||||||
|
становится значением строкового атрибута \texttt{stringValue\_}.
|
||||||
|
|
||||||
|
\item Если символ равен `\texttt{:}', лексический анализатор считывает следующий
|
||||||
|
символ и проверяет, что он равен `\texttt{=}'. В этом случае возвращается
|
||||||
|
лексема \texttt{T\_ASSIGN}. Если следом за `\texttt{:}' идет любой другой
|
||||||
|
символ, лексема считается ошибочной (\texttt{T\_ILLEGAL}).
|
||||||
|
|
||||||
|
\item Если символ равен `\texttt{!}', производится аналогичная проверка на
|
||||||
|
равенство следующего символа `\texttt{=}'. В случае успеха текущей лексемой
|
||||||
|
становится лексема \texttt{T\_CMP}, а атрибут \texttt{cmpValue\_} принимает
|
||||||
|
значение \texttt{T\_NE}.
|
||||||
|
|
||||||
|
\item Если символ равен `\texttt{<}', `\texttt{>}' или `\texttt{=}', текущей
|
||||||
|
лексемой становится \texttt{T\_CMP}. Чтобы определить значение атрибута
|
||||||
|
\texttt{cmpValue\_}, лексический анализатор может прочитать еще один символ для
|
||||||
|
того, чтобы отличить оператор `\texttt{<}' от оператора `\texttt{>}', а оператор
|
||||||
|
`\texttt{>}' от оператора `\texttt{>=}'.
|
||||||
|
|
||||||
|
\item Если символ равен `\texttt{+}' или `\texttt{-}', переменная
|
||||||
|
\texttt{token\_} принимает значение \texttt{T\_ADDOP}, при этом соответствующим
|
||||||
|
образом устанавливается значение атрибута \texttt{arithmeticValue\_}. Аналогично
|
||||||
|
обрабатываются символ `\texttt{*}' (лексема \texttt{T\_MULOP}). Оператор деления
|
||||||
|
обрабатывать таким же образом не нужно, поскольку он обнаруживается в ходе
|
||||||
|
удаления комментариев.
|
||||||
|
|
||||||
|
\item Если символ совпадает с `\texttt{;}', `\texttt{(}', `\texttt{)}',
|
||||||
|
очередная лексема устанавливается в соответствующее символу значение.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection{Синтаксический анализатор}
|
||||||
|
|
||||||
|
Задачами синтаксического анализатора является проверка соответствия программы
|
||||||
|
грамматике языка Милан (рисунок~\ref{milan-grammar}) и формирование кода для
|
||||||
|
виртуальной машины Милана в соответствии со структурой программы. Синтаксический
|
||||||
|
анализ выполняется методом рекурсивного спуска. Каждому нетерминальному символу
|
||||||
|
грамматики сопоставлен метод, выполняющий проверку соответствия
|
||||||
|
последовательности лексем одному из тех правил грамматики, в левой части которых
|
||||||
|
стоит данный нетерминальный символ. Семантические действия (генерация кода)
|
||||||
|
встроены в код метода.
|
||||||
|
|
||||||
|
Исходный текст синтаксического анализатора находится в файлах \texttt{parser.h}
|
||||||
|
и \texttt{parser.cpp}. Алгоритм синтаксического анализа реализован в классе
|
||||||
|
\texttt{Parser}. Конструктор класса в качестве аргумента принимает имя файла, в
|
||||||
|
котором находится анализируемый текст, и создает экземпляры лексического
|
||||||
|
анализатора и генератора кода.
|
||||||
|
|
||||||
|
Синтаксический анализатор предоставляет один открытый метод \texttt{void parse()},
|
||||||
|
который используется для того, чтобы начать процесс анализа.
|
||||||
|
|
||||||
|
Состояние анализатора описывается следующими полями:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{Scanner* scanner\_}
|
||||||
|
|
||||||
|
Экземпляр лексического анализатора.
|
||||||
|
|
||||||
|
\item \texttt{CodeGen* codegen\_}
|
||||||
|
|
||||||
|
Экземпляр генератора кода.
|
||||||
|
|
||||||
|
\item \texttt{std::ostream\& output\_}
|
||||||
|
|
||||||
|
Выходной поток, в который должны быть выведены инструкции программы.
|
||||||
|
Базовая версия компилятора Милан использует в качестве выходного потока
|
||||||
|
стандартный вывод (\texttt{std::cout}).
|
||||||
|
|
||||||
|
\item \texttt{bool error\_}
|
||||||
|
|
||||||
|
Признак ошибки в тексте программы. Если \texttt{error\_} принимает
|
||||||
|
значение <<истина>>, генерируемый машинный код не выводится.
|
||||||
|
|
||||||
|
\item \texttt{map<string, int> variables\_}
|
||||||
|
|
||||||
|
Таблица имен, найденных в программе. Она сопоставляет каждой переменной ее
|
||||||
|
адрес в памяти виртуальной машины. Поскольку базовая версия языка Милан не
|
||||||
|
содержит вложенных блоков, процедур или функций, таблица имен представляет
|
||||||
|
собой простой ассоциативный массив.
|
||||||
|
|
||||||
|
\item \texttt{int lastVar\_}
|
||||||
|
|
||||||
|
Адрес последней найденной переменной.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Синтаксический анализатор включает ряд вспомогательных функций (закрытые методы
|
||||||
|
класса).
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item \texttt{bool see(Token t)}
|
||||||
|
|
||||||
|
Сравнение текущей лексемы с образцом. Текущая позиция в потоке лексем не
|
||||||
|
изменяется.
|
||||||
|
|
||||||
|
\item \texttt{bool match(Token t)}
|
||||||
|
|
||||||
|
Проверка совпадения текущей лексемы с образцом. Если лексема и образец
|
||||||
|
совпадают, лексема изымается из потока.
|
||||||
|
|
||||||
|
\item \texttt{void mustBe(Token t)}
|
||||||
|
|
||||||
|
Проверка совпадения текущей лексемы с образцом. Если лексема и образец
|
||||||
|
совпадают, лексема изымается из потока. В противном случае формируется
|
||||||
|
сообщение об ошибке, а программа считается некорректной.
|
||||||
|
|
||||||
|
\item \texttt{void next()}
|
||||||
|
|
||||||
|
Переход к следующей лексеме.
|
||||||
|
|
||||||
|
\item \texttt{void reportError(const string\& message)}
|
||||||
|
|
||||||
|
Формирование сообщения об ошибке. Каждое сообщение включает текст
|
||||||
|
\texttt{message} и номер строки, в которой обнаружена ошибка.
|
||||||
|
|
||||||
|
\item \texttt{void recover(Token t)}
|
||||||
|
|
||||||
|
Восстановление после ошибки. Используется примитивный алгоритм: если
|
||||||
|
очередная лексема не совпадает с ожидаемой, анализатор пропускает все
|
||||||
|
последующие лексемы, пока не встретит ожидаемую лексему или
|
||||||
|
конец файла. Хотя такой метод восстановления не отличается точностью, он,
|
||||||
|
тем не менее, позволяет продолжить анализ и, возможно, найти ошибки в
|
||||||
|
оставшейся части программы.
|
||||||
|
|
||||||
|
\item \texttt{int findOrAddVariable(const string\&)}
|
||||||
|
|
||||||
|
Поиск имени переменной в таблице имен. Если имя найдено, метод возвращает
|
||||||
|
адрес переменной, в противном случае имя добавляется в таблицу имен, и для
|
||||||
|
соответствующей переменной резервируется новый адрес.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Кроме служебных методов, класс \texttt{Parser} содержит закрытые методы
|
||||||
|
\texttt{void program()}, \texttt{void statementList()}, \texttt{void
|
||||||
|
statement()}, \texttt{void expression()}, \texttt{void term()}, \texttt{void
|
||||||
|
factor()}, \texttt{void relation()}, которые соответствуют нетерминальным
|
||||||
|
символам грамматики. Эти методы не возвращают значений и не принимают
|
||||||
|
аргументов, поскольку с нетерминальными символами не связаны явные атрибуты: все
|
||||||
|
семантические действия, которые производятся во время анализа программы,
|
||||||
|
модифицируют буфер общего для всех методов генератора кода.
|
||||||
|
|
||||||
|
\subsubsection{Распознавание операторов}
|
||||||
|
|
||||||
|
Продемонстрируем алгоритм работы синтаксического анализатора на примере анализа
|
||||||
|
операторов (метод \texttt{statement}).
|
||||||
|
|
||||||
|
В соответствии с грамматикой языка Милан, в качестве оператора может выступать
|
||||||
|
оператор присваивания, условный оператор \texttt{if}, оператор цикла
|
||||||
|
\texttt{while} или оператор печати \texttt{write}. Для выбора нужной
|
||||||
|
альтернативы достаточно прочитать первую лексему оператора.
|
||||||
|
|
||||||
|
Если очередная лексема равна \texttt{T\_IDENTIFIER}, синтаксический анализатор
|
||||||
|
имеет дело с оператором присваивания. Он считывает имя переменной, стоящей в
|
||||||
|
левой части присваивания, и определяет ее адрес. Затем анализатор проверяет, что
|
||||||
|
следующая лексема совпадает с \texttt{T\_ASSIGN}. После знака `\texttt{:=}' в
|
||||||
|
программе должно следовать арифметическое выражение, поэтому анализатор вызывает
|
||||||
|
метод \texttt{expression()}. Этот метод проверяет правильность арифметического
|
||||||
|
выражения и генерирует последовательность команд для его вычисления. В
|
||||||
|
результате выполнены этой последовательности на вершине стека будет находиться
|
||||||
|
значение выражения. Чтобы выполнить присваивание, достаточно записать значение с
|
||||||
|
вершины стека в память по адресу переменной в левой части оператора
|
||||||
|
присваивания. Для этого после вызова \texttt{expression()} нужно добавить в
|
||||||
|
буфер команд инструкцию \texttt{STORE}, аргументом которой будет запомненный
|
||||||
|
ранее адрес переменной.
|
||||||
|
|
||||||
|
Если очередная лексема равна \texttt{T\_IF}, анализатор должен начать разбор
|
||||||
|
условного оператора. Сначала он вызывает метод \texttt{relation()}, проверяя,
|
||||||
|
что после лексемы \texttt{T\_IF} следует правильное сравнение двух выражений.
|
||||||
|
Метод \texttt{relation()} генерирует код, вычисляющий и сравнивающий два
|
||||||
|
выражения. При выполнении этого кода на вершине стека останется значение $1$,
|
||||||
|
если условие выполнено, и $0$ в противном случае. Если условие не выполнено,
|
||||||
|
должен произойти переход к списку операторов блока \texttt{else} или, если этого
|
||||||
|
блока нет, по адресу следующей за условным оператором инструкции. Однако этот
|
||||||
|
адрес еще не известен синтаксическому анализатору. Чтобы решить эту проблему,
|
||||||
|
применяется так называемый <<метод обратных поправок>>~\cite{dragonbook11}.
|
||||||
|
Анализатор резервирует место для условного перехода \texttt{JUMP\_NO} и
|
||||||
|
запоминает адрес этой инструкции в переменной \texttt{jumpNoAddress}, после чего
|
||||||
|
переходит к дальнейшему анализу условного оператора.
|
||||||
|
|
||||||
|
Следом за условием в тексте программы должна находиться лексема
|
||||||
|
\texttt{T\_THEN}. Если она обнаружена, анализатор переходит к следующей лексеме
|
||||||
|
и вызывает метод \texttt{statementList()}, который анализирует список операторов
|
||||||
|
и генерирует для них исполняемый код. Дальнейшие действия зависят от того,
|
||||||
|
присутствует ли в условном операторе ветвь \texttt{else}. Если следующая лексема
|
||||||
|
равна \texttt{T\_ELSE}, синтаксический анализатор должен сгенерировать
|
||||||
|
инструкцию \texttt{JUMP} для выхода из условного оператора, после чего
|
||||||
|
приступить к анализу блока \texttt{else}. Если условный оператор не содержит
|
||||||
|
блока \texttt{else}, инструкция безусловного перехода в конце блока
|
||||||
|
\texttt{then} не нужна.
|
||||||
|
|
||||||
|
Генерация безусловного перехода также требует знания адреса, следующего за
|
||||||
|
последней инструкцией условного оператора, поэтому анализатор снова должен
|
||||||
|
зарезервировать ячейку памяти для команды перехода. Следующий за этой ячейкой
|
||||||
|
адрес содержит первую команду блока \texttt{else}. Это именно тот адрес, по
|
||||||
|
которому необходимо было выполнить переход в случае, если условие не было
|
||||||
|
выполнено. Поскольку теперь этот адрес известен, синтаксический анализатор
|
||||||
|
генерирует инструкцию безусловного перехода и помещает ее в буфер команд по
|
||||||
|
адресу, который записан в переменной \texttt{jumpNoAddress}. В случае отсутствия
|
||||||
|
блока \texttt{else} поправка происходит таким же образом, но в качестве адреса
|
||||||
|
перехода просто используется следующий за последней инструкцией блока
|
||||||
|
\texttt{then} адрес. После вызова функции \texttt{statementList}, которая
|
||||||
|
разбирает список операторов блока \texttt{else}, аналогично исправляется
|
||||||
|
зарезервированная инструкция безусловного перехода.
|
||||||
|
|
||||||
|
Структура кода, соответствующая условному оператору, приведена на
|
||||||
|
рисунке~\ref{ifthenelse-code}.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{verbatim}
|
||||||
|
Вычисление выражений
|
||||||
|
...
|
||||||
|
COMPARE operator
|
||||||
|
JUMP_NO elseLabel
|
||||||
|
Операторы блока THEN
|
||||||
|
...
|
||||||
|
JUMP endLabel
|
||||||
|
elseLabel: Операторы блока ELSE
|
||||||
|
...
|
||||||
|
endLabel:
|
||||||
|
\end{verbatim}
|
||||||
|
\caption{Структура исполняемого кода условного оператора}
|
||||||
|
\label{ifthenelse-code}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Если очередная лексема равна \texttt{T\_WHILE}, синтаксическому анализатору
|
||||||
|
предстоит разобрать оператор цикла. Анализатор должен запомнить текущий адрес
|
||||||
|
команды, поскольку после каждой итерации цикла по этому адресу нужно будет
|
||||||
|
возвращаться. Затем анализатор вызывает метод \texttt{relation()}, чтобы
|
||||||
|
сгенерировать код проверки условия. Если условие окажется ложным, нужно будет
|
||||||
|
выполнить переход на следующий за циклом оператор. Для этого синтаксический
|
||||||
|
анализатор резервирует ячейку памяти для команды \texttt{JUMP\_NO}. После этого
|
||||||
|
он проверяет наличие лексемы \texttt{T\_DO} и вызывает метод
|
||||||
|
\texttt{statementList()} для обработки тела цикла. Затем анализатор генерирует
|
||||||
|
инструкцию безусловного перехода назад, к началу проверки условия, и записывает
|
||||||
|
в зарезервированную ячейку инструкцию условного перехода по известному теперь
|
||||||
|
адресу конца цикла. Для завершения анализа инструкции достаточно убедиться, что
|
||||||
|
очередная лексема равна ожидаемому значению \texttt{T\_OD}. Структура
|
||||||
|
исполняемого кода для цикла приведена на рисунке~\ref{while-code}.
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\begin{verbatim}
|
||||||
|
whileLabel: Вычисление выражений
|
||||||
|
...
|
||||||
|
COMPARE operator
|
||||||
|
JUMP_NO endLabel
|
||||||
|
...
|
||||||
|
Операторы тела цикла
|
||||||
|
...
|
||||||
|
JUMP whileLabel
|
||||||
|
endLabel:
|
||||||
|
\end{verbatim}
|
||||||
|
\caption{Структура исполняемого кода цикла с предусловием}
|
||||||
|
\label{while-code}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Если очередная лексема равна \texttt{T\_WRITE}, необходимо проверить, что
|
||||||
|
следующая лексема равна \texttt{T\_LPAREN}, затем вызвать метод
|
||||||
|
\texttt{expression()} и проверить, что за выражением в потоке следует лексема
|
||||||
|
\texttt{T\_RPAREN}. Поскольку код, вычисляющий значение выражения, оставляет его
|
||||||
|
значение на вершине стека, для выполнения печати достаточно после вызова
|
||||||
|
\texttt{expression()} сгенерировать инструкцию \texttt{PRINT}.
|
||||||
|
|
||||||
|
\begin{thebibliography}{9}
|
||||||
|
\addcontentsline{toc}{section}{Список литературы}
|
||||||
|
|
||||||
|
\bibitem{dragonbook11}
|
||||||
|
А. Ахо, М. Лам, Р. Сети, Дж. Ульман,
|
||||||
|
\emph{Компиляторы: принципы, технологии и инструментарий}, 2-е изд.
|
||||||
|
М.: Вильямс, 2011.
|
||||||
|
|
||||||
|
\bibitem{karpov05}
|
||||||
|
Ю.Г. Карпов,
|
||||||
|
\emph{Теория и технология программирования. Основы построения трансляторов}.
|
||||||
|
СПб.: БХВ-Петербург, 2005.
|
||||||
|
\end{thebibliography}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
|
|
||||||
23
lab4/cmilan/src/Makefile
Normal file
23
lab4/cmilan/src/Makefile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CFLAGS = -Wall -W -Werror -O2
|
||||||
|
LDFLAGS =
|
||||||
|
|
||||||
|
HEADERS = scanner.h \
|
||||||
|
parser.h \
|
||||||
|
codegen.h
|
||||||
|
|
||||||
|
OBJS = main.o \
|
||||||
|
codegen.o \
|
||||||
|
scanner.o \
|
||||||
|
parser.o \
|
||||||
|
|
||||||
|
EXE = cmilan
|
||||||
|
|
||||||
|
$(EXE): $(OBJS) $(HEADERS)
|
||||||
|
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CXX) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-@rm -f $(EXE) $(OBJS)
|
||||||
|
|
||||||
20
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.sln
Normal file
20
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.sln
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual Studio 2010
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmilan_vs2011", "cmilan_vs2011.vcxproj", "{1D542465-2019-4442-864E-DC785FA067A8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{1D542465-2019-4442-864E-DC785FA067A8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{1D542465-2019-4442-864E-DC785FA067A8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{1D542465-2019-4442-864E-DC785FA067A8}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{1D542465-2019-4442-864E-DC785FA067A8}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
92
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj
Normal file
92
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{1D542465-2019-4442-864E-DC785FA067A8}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>cmilan_vs2011</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>cmilan</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<TargetName>cmilan</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\codegen.h" />
|
||||||
|
<ClInclude Include="..\parser.h" />
|
||||||
|
<ClInclude Include="..\scanner.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\codegen.cpp" />
|
||||||
|
<ClCompile Include="..\main.cpp" />
|
||||||
|
<ClCompile Include="..\parser.cpp" />
|
||||||
|
<ClCompile Include="..\scanner.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
42
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj.filters
Normal file
42
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj.filters
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\codegen.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\parser.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\scanner.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\codegen.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\parser.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\scanner.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
3
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj.user
Normal file
3
lab4/cmilan/src/cmilan_vs2011/cmilan_vs2011.vcxproj.user
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
</Project>
|
||||||
129
lab4/cmilan/src/codegen.cpp
Normal file
129
lab4/cmilan/src/codegen.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include "codegen.h"
|
||||||
|
|
||||||
|
void Command::print(int address, ostream& os)
|
||||||
|
{
|
||||||
|
os << address << ":\t";
|
||||||
|
switch(instruction_) {
|
||||||
|
case NOP:
|
||||||
|
os << "NOP";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STOP:
|
||||||
|
os << "STOP";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOAD:
|
||||||
|
os << "LOAD\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STORE:
|
||||||
|
os << "STORE\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BLOAD:
|
||||||
|
os << "BLOAD\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BSTORE:
|
||||||
|
os << "BSTORE\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUSH:
|
||||||
|
os << "PUSH\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP:
|
||||||
|
os << "POP";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DUP:
|
||||||
|
os << "DUP";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADD:
|
||||||
|
os << "ADD";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUB:
|
||||||
|
os << "SUB";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULT:
|
||||||
|
os << "MULT";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIV:
|
||||||
|
os << "DIV";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INVERT:
|
||||||
|
os << "INVERT";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMPARE:
|
||||||
|
os << "COMPARE\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP:
|
||||||
|
os << "JUMP\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP_YES:
|
||||||
|
os << "JUMP_YES\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP_NO:
|
||||||
|
os << "JUMP_NO\t" << arg_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INPUT:
|
||||||
|
os << "INPUT";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINT:
|
||||||
|
os << "PRINT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGen::emit(Instruction instruction)
|
||||||
|
{
|
||||||
|
commandBuffer_.push_back(Command(instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGen::emit(Instruction instruction, int arg)
|
||||||
|
{
|
||||||
|
commandBuffer_.push_back(Command(instruction, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGen::emitAt(int address, Instruction instruction)
|
||||||
|
{
|
||||||
|
commandBuffer_[address] = Command(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGen::emitAt(int address, Instruction instruction, int arg)
|
||||||
|
{
|
||||||
|
commandBuffer_[address] = Command(instruction, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CodeGen::getCurrentAddress()
|
||||||
|
{
|
||||||
|
return commandBuffer_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CodeGen::reserve()
|
||||||
|
{
|
||||||
|
emit(NOP);
|
||||||
|
return commandBuffer_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeGen::flush()
|
||||||
|
{
|
||||||
|
int count = commandBuffer_.size();
|
||||||
|
for(int address = 0; address < count; ++address) {
|
||||||
|
commandBuffer_[address].print(address, output_);
|
||||||
|
}
|
||||||
|
output_.flush();
|
||||||
|
}
|
||||||
100
lab4/cmilan/src/codegen.h
Normal file
100
lab4/cmilan/src/codegen.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#ifndef CMILAN_CODEGEN_H
|
||||||
|
#define CMILAN_CODEGEN_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Инструкции виртуальной машины Милана
|
||||||
|
|
||||||
|
enum Instruction
|
||||||
|
{
|
||||||
|
NOP, // отсутствие операции
|
||||||
|
STOP, // остановка машины, завершение работы программы
|
||||||
|
LOAD, // LOAD addr - загрузка слова данных в стек из памяти по адресу addr
|
||||||
|
STORE, // STORE addr - запись слова данных с вершины стека в память по адресу addr
|
||||||
|
BLOAD, // BLOAD addr - загрузка слова данных в стек из памяти по адресу addr + значение на вершине стека
|
||||||
|
BSTORE, // BSTORE addr - запись слова данных по адресу addr + значение на вершине стека
|
||||||
|
PUSH, // PUSH n - загрузка в стек константы n
|
||||||
|
POP, // удаление слова с вершины стека
|
||||||
|
DUP, // копирование слова на вершине стека
|
||||||
|
ADD, // сложение двух слов на вершине стека и запись результата вместо них
|
||||||
|
SUB, // вычитание двух слов на вершине стека и запись результата вместо них
|
||||||
|
MULT, // умножение двух слов на вершине стека и запись результата вместо них
|
||||||
|
DIV, // деление двух слов на вершине стека и запись результата вместо них
|
||||||
|
INVERT, // изменение знака слова на вершине стека
|
||||||
|
COMPARE, // COMPARE cmp - сравнение двух слов на вершине стека с помощью операции сравнения с кодом cmp
|
||||||
|
JUMP, // JUMP addr - безусловный переход по адресу addr
|
||||||
|
JUMP_YES, // JUMP_YES addr - переход по адресу addr, если на вершине стека значение 1
|
||||||
|
JUMP_NO, // JUMP_NO addr - переход по адресу addr, если на вершине стека значение 0
|
||||||
|
INPUT, // чтение целого числа со стандартного ввода и загрузка его в стек
|
||||||
|
PRINT // печать на стандартный вывод числа с вершины стека
|
||||||
|
};
|
||||||
|
|
||||||
|
// Класс Command представляет машинные инструкции.
|
||||||
|
|
||||||
|
class Command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Конструктор для инструкций без аргументов
|
||||||
|
Command(Instruction instruction)
|
||||||
|
: instruction_(instruction), arg_(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Конструктор для инструкций с одним аргументом
|
||||||
|
Command(Instruction instruction, int arg)
|
||||||
|
: instruction_(instruction), arg_(arg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Печать инструкции
|
||||||
|
// int address - адрес инструкции
|
||||||
|
// ostream& os - поток вывода, куда будет напечатана инструкция
|
||||||
|
void print(int address, ostream& os);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Instruction instruction_; // Код инструкции
|
||||||
|
int arg_; // Аргумент инструкции
|
||||||
|
};
|
||||||
|
|
||||||
|
// Кодогенератор.
|
||||||
|
// Назначение кодогенератора:
|
||||||
|
// - Формировать программу для виртуальной машины Милана
|
||||||
|
// - Отслеживать адрес последней инструкции
|
||||||
|
// - Буферизовать программу и печатать ее в указанный поток вывода
|
||||||
|
|
||||||
|
class CodeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CodeGen(ostream& output)
|
||||||
|
: output_(output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавление инструкции без аргументов в конец программы
|
||||||
|
void emit(Instruction instruction);
|
||||||
|
|
||||||
|
// Добавление инструкции с одним аргументом в конец программы
|
||||||
|
void emit(Instruction instruction, int arg);
|
||||||
|
|
||||||
|
// Запись инструкции без аргументов по указанному адресу
|
||||||
|
void emitAt(int address, Instruction instruction);
|
||||||
|
|
||||||
|
// Запись инструкции с одним аргументом по указанному адресу
|
||||||
|
void emitAt(int address, Instruction instruction, int arg);
|
||||||
|
|
||||||
|
// Получение адреса, непосредственно следующего за последней инструкцией в программе
|
||||||
|
int getCurrentAddress();
|
||||||
|
|
||||||
|
// Формирование "пустой" инструкции (NOP) и возврат ее адреса
|
||||||
|
int reserve();
|
||||||
|
|
||||||
|
// Запись последовательности инструкций в выходной поток
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ostream& output_; // Выходной поток
|
||||||
|
vector<Command> commandBuffer_; // Буфер инструкций
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
lab4/cmilan/src/codegen.o
Normal file
BIN
lab4/cmilan/src/codegen.o
Normal file
Binary file not shown.
32
lab4/cmilan/src/main.cpp
Normal file
32
lab4/cmilan/src/main.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void printHelp()
|
||||||
|
{
|
||||||
|
cout << "Usage: cmilan input_file" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if(argc < 2) {
|
||||||
|
printHelp();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifstream input;
|
||||||
|
input.open(argv[1]);
|
||||||
|
|
||||||
|
if(input) {
|
||||||
|
Parser p(argv[1], input);
|
||||||
|
p.parse();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cerr << "File '" << argv[1] << "' not found" << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
lab4/cmilan/src/main.o
Normal file
BIN
lab4/cmilan/src/main.o
Normal file
Binary file not shown.
270
lab4/cmilan/src/parser.cpp
Normal file
270
lab4/cmilan/src/parser.cpp
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
//Выполняем синтаксический разбор блока program. Если во время разбора не обнаруживаем
|
||||||
|
//никаких ошибок, то выводим последовательность команд стек-машины
|
||||||
|
void Parser::parse()
|
||||||
|
{
|
||||||
|
program();
|
||||||
|
if(!error_) {
|
||||||
|
codegen_->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::program()
|
||||||
|
{
|
||||||
|
mustBe(T_BEGIN);
|
||||||
|
statementList();
|
||||||
|
mustBe(T_END);
|
||||||
|
codegen_->emit(STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::statementList()
|
||||||
|
{
|
||||||
|
// Если список операторов пуст, очередной лексемой будет одна из возможных "закрывающих скобок": END, OD, ELSE, FI.
|
||||||
|
// В этом случае результатом разбора будет пустой блок (его список операторов равен null).
|
||||||
|
// Если очередная лексема не входит в этот список, то ее мы считаем началом оператора и вызываем метод statement.
|
||||||
|
// Признаком последнего оператора является отсутствие после оператора точки с запятой.
|
||||||
|
if(see(T_END) || see(T_OD) || see(T_ELSE) || see(T_FI)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool more = true;
|
||||||
|
while(more) {
|
||||||
|
statement();
|
||||||
|
more = match(T_SEMICOLON);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::statement()
|
||||||
|
{
|
||||||
|
// Если встречаем переменную, то запоминаем ее адрес или добавляем новую если не встретили.
|
||||||
|
// Следующей лексемой должно быть присваивание. Затем идет блок expression, который возвращает значение на вершину стека.
|
||||||
|
// Записываем это значение по адресу нашей переменной
|
||||||
|
if(see(T_IDENTIFIER)) {
|
||||||
|
int varAddress = findOrAddVariable(scanner_->getStringValue());
|
||||||
|
next();
|
||||||
|
mustBe(T_ASSIGN);
|
||||||
|
expression();
|
||||||
|
codegen_->emit(STORE, varAddress);
|
||||||
|
}
|
||||||
|
// Если встретили IF, то затем должно следовать условие. На вершине стека лежит 1 или 0 в зависимости от выполнения условия.
|
||||||
|
// Затем зарезервируем место для условного перехода JUMP_NO к блоку ELSE (переход в случае ложного условия). Адрес перехода
|
||||||
|
// станет известным только после того, как будет сгенерирован код для блока THEN.
|
||||||
|
else if(match(T_IF)) {
|
||||||
|
relation();
|
||||||
|
|
||||||
|
int jumpNoAddress = codegen_->reserve();
|
||||||
|
|
||||||
|
mustBe(T_THEN);
|
||||||
|
statementList();
|
||||||
|
if(match(T_ELSE)) {
|
||||||
|
//Если есть блок ELSE, то чтобы не выполнять его в случае выполнения THEN,
|
||||||
|
//зарезервируем место для команды JUMP в конец этого блока
|
||||||
|
int jumpAddress = codegen_->reserve();
|
||||||
|
//Заполним зарезервированное место после проверки условия инструкцией перехода в начало блока ELSE.
|
||||||
|
codegen_->emitAt(jumpNoAddress, JUMP_NO, codegen_->getCurrentAddress());
|
||||||
|
statementList();
|
||||||
|
//Заполним второй адрес инструкцией перехода в конец условного блока ELSE.
|
||||||
|
codegen_->emitAt(jumpAddress, JUMP, codegen_->getCurrentAddress());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Если блок ELSE отсутствует, то в зарезервированный адрес после проверки условия будет записана
|
||||||
|
//инструкция условного перехода в конец оператора IF...THEN
|
||||||
|
codegen_->emitAt(jumpNoAddress, JUMP_NO, codegen_->getCurrentAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
mustBe(T_FI);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(match(T_WHILE)) {
|
||||||
|
//запоминаем адрес начала проверки условия.
|
||||||
|
int conditionAddress = codegen_->getCurrentAddress();
|
||||||
|
relation();
|
||||||
|
//резервируем место под инструкцию условного перехода для выхода из цикла.
|
||||||
|
int jumpNoAddress = codegen_->reserve();
|
||||||
|
mustBe(T_DO);
|
||||||
|
statementList();
|
||||||
|
mustBe(T_OD);
|
||||||
|
//переходим по адресу проверки условия
|
||||||
|
codegen_->emit(JUMP, conditionAddress);
|
||||||
|
//заполняем зарезервированный адрес инструкцией условного перехода на следующий за циклом оператор.
|
||||||
|
codegen_->emitAt(jumpNoAddress, JUMP_NO, codegen_->getCurrentAddress());
|
||||||
|
}
|
||||||
|
else if(match(T_WRITE)) {
|
||||||
|
mustBe(T_LPAREN);
|
||||||
|
expression();
|
||||||
|
mustBe(T_RPAREN);
|
||||||
|
codegen_->emit(PRINT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reportError("statement expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::expression()
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
Арифметическое выражение описывается следующими правилами: <expression> -> <term> | <term> + <term> | <term> - <term>
|
||||||
|
При разборе сначала смотрим первый терм, затем анализируем очередной символ. Если это '+' или '-',
|
||||||
|
удаляем его из потока и разбираем очередное слагаемое (вычитаемое). Повторяем проверку и разбор очередного
|
||||||
|
терма, пока не встретим за термом символ, отличный от '+' и '-'
|
||||||
|
*/
|
||||||
|
|
||||||
|
term();
|
||||||
|
while(see(T_ADDOP)) {
|
||||||
|
Arithmetic op = scanner_->getArithmeticValue();
|
||||||
|
next();
|
||||||
|
term();
|
||||||
|
|
||||||
|
if(op == A_PLUS) {
|
||||||
|
codegen_->emit(ADD);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
codegen_->emit(SUB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::term()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Терм описывается следующими правилами: <expression> -> <factor> | <factor> + <factor> | <factor> - <factor>
|
||||||
|
При разборе сначала смотрим первый множитель, затем анализируем очередной символ. Если это '*' или '/',
|
||||||
|
удаляем его из потока и разбираем очередное слагаемое (вычитаемое). Повторяем проверку и разбор очередного
|
||||||
|
множителя, пока не встретим за ним символ, отличный от '*' и '/'
|
||||||
|
*/
|
||||||
|
factor();
|
||||||
|
while(see(T_MULOP)) {
|
||||||
|
Arithmetic op = scanner_->getArithmeticValue();
|
||||||
|
next();
|
||||||
|
factor();
|
||||||
|
|
||||||
|
if(op == A_MULTIPLY) {
|
||||||
|
codegen_->emit(MULT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
codegen_->emit(DIV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::factor()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Множитель описывается следующими правилами:
|
||||||
|
<factor> -> number | identifier | -<factor> | (<expression>) | READ
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
//Если встретили переменную, то выгружаем значение, лежащее по ее адресу, на вершину стека
|
||||||
|
}
|
||||||
|
else if(see(T_ADDOP) && scanner_->getArithmeticValue() == A_MINUS) {
|
||||||
|
next();
|
||||||
|
factor();
|
||||||
|
codegen_->emit(INVERT);
|
||||||
|
//Если встретили знак "-", и за ним <factor> то инвертируем значение, лежащее на вершине стека
|
||||||
|
}
|
||||||
|
else if(match(T_LPAREN)) {
|
||||||
|
expression();
|
||||||
|
mustBe(T_RPAREN);
|
||||||
|
//Если встретили открывающую скобку, тогда следом может идти любое арифметическое выражение и обязательно
|
||||||
|
//закрывающая скобка.
|
||||||
|
}
|
||||||
|
else if(match(T_READ)) {
|
||||||
|
codegen_->emit(INPUT);
|
||||||
|
//Если встретили зарезервированное слово READ, то записываем на вершину стека идет запись со стандартного ввода
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reportError("expression expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::relation()
|
||||||
|
{
|
||||||
|
//Условие сравнивает два выражения по какому-либо из знаков. Каждый знак имеет свой номер. В зависимости от
|
||||||
|
//результата сравнения на вершине стека окажется 0 или 1.
|
||||||
|
expression();
|
||||||
|
if(see(T_CMP)) {
|
||||||
|
Cmp cmp = scanner_->getCmpValue();
|
||||||
|
next();
|
||||||
|
expression();
|
||||||
|
switch(cmp) {
|
||||||
|
//для знака "=" - номер 0
|
||||||
|
case C_EQ:
|
||||||
|
codegen_->emit(COMPARE, 0);
|
||||||
|
break;
|
||||||
|
//для знака "!=" - номер 1
|
||||||
|
case C_NE:
|
||||||
|
codegen_->emit(COMPARE, 1);
|
||||||
|
break;
|
||||||
|
//для знака "<" - номер 2
|
||||||
|
case C_LT:
|
||||||
|
codegen_->emit(COMPARE, 2);
|
||||||
|
break;
|
||||||
|
//для знака ">" - номер 3
|
||||||
|
case C_GT:
|
||||||
|
codegen_->emit(COMPARE, 3);
|
||||||
|
break;
|
||||||
|
//для знака "<=" - номер 4
|
||||||
|
case C_LE:
|
||||||
|
codegen_->emit(COMPARE, 4);
|
||||||
|
break;
|
||||||
|
//для знака ">=" - номер 5
|
||||||
|
case C_GE:
|
||||||
|
codegen_->emit(COMPARE, 5);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reportError("comparison operator expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Parser::findOrAddVariable(const string& var)
|
||||||
|
{
|
||||||
|
VarTable::iterator it = variables_.find(var);
|
||||||
|
if(it == variables_.end()) {
|
||||||
|
variables_[var] = lastVar_;
|
||||||
|
return lastVar_++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::mustBe(Token t)
|
||||||
|
{
|
||||||
|
if(!match(t)) {
|
||||||
|
error_ = true;
|
||||||
|
|
||||||
|
// Подготовим сообщение об ошибке
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << tokenToString(scanner_->token()) << " found while " << tokenToString(t) << " expected.";
|
||||||
|
reportError(msg.str());
|
||||||
|
|
||||||
|
// Попытка восстановления после ошибки.
|
||||||
|
recover(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::recover(Token t)
|
||||||
|
{
|
||||||
|
while(!see(t) && !see(T_EOF)) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(see(t)) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
119
lab4/cmilan/src/parser.h
Normal file
119
lab4/cmilan/src/parser.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#ifndef CMILAN_PARSER_H
|
||||||
|
#define CMILAN_PARSER_H
|
||||||
|
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "codegen.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/* Синтаксический анализатор.
|
||||||
|
*
|
||||||
|
* Задачи:
|
||||||
|
* - проверка корректности программы,
|
||||||
|
* - генерация кода для виртуальной машины в процессе анализа,
|
||||||
|
* - простейшее восстановление после ошибок.
|
||||||
|
*
|
||||||
|
* Синтаксический анализатор языка Милан.
|
||||||
|
*
|
||||||
|
* Парсер с помощью переданного ему при инициализации лексического анализатора
|
||||||
|
* читает по одной лексеме и на основе грамматики Милана генерирует код для
|
||||||
|
* стековой виртуальной машины. Синтаксический анализ выполняется методом
|
||||||
|
* рекурсивного спуска.
|
||||||
|
*
|
||||||
|
* При обнаружении ошибки парсер печатает сообщение и продолжает анализ со
|
||||||
|
* следующего оператора, чтобы в процессе разбора найти как можно больше ошибок.
|
||||||
|
* Поскольку стратегия восстановления после ошибки очень проста, возможна печать
|
||||||
|
* сообщений о несуществующих ("наведенных") ошибках или пропуск некоторых
|
||||||
|
* ошибок без печати сообщений. Если в процессе разбора была найдена хотя бы
|
||||||
|
* одна ошибка, код для виртуальной машины не печатается.*/
|
||||||
|
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Конструктор
|
||||||
|
// const string& fileName - имя файла с программой для анализа
|
||||||
|
//
|
||||||
|
// Конструктор создает экземпляры лексического анализатора и генератора.
|
||||||
|
|
||||||
|
Parser(const string& fileName, istream& input)
|
||||||
|
: output_(cout), error_(false), recovered_(true), lastVar_(0)
|
||||||
|
{
|
||||||
|
scanner_ = new Scanner(fileName, input);
|
||||||
|
codegen_ = new CodeGen(output_);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Parser()
|
||||||
|
{
|
||||||
|
delete codegen_;
|
||||||
|
delete scanner_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse(); //проводим синтаксический разбор
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef map<string, int> VarTable;
|
||||||
|
//описание блоков.
|
||||||
|
void program(); //Разбор программы. BEGIN statementList END
|
||||||
|
void statementList(); // Разбор списка операторов.
|
||||||
|
void statement(); //разбор оператора.
|
||||||
|
void expression(); //разбор арифметического выражения.
|
||||||
|
void term(); //разбор слагаемого.
|
||||||
|
void factor(); //разбор множителя.
|
||||||
|
void relation(); //разбор условия.
|
||||||
|
|
||||||
|
// Сравнение текущей лексемы с образцом. Текущая позиция в потоке лексем не изменяется.
|
||||||
|
bool see(Token t)
|
||||||
|
{
|
||||||
|
return scanner_->token() == t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка совпадения текущей лексемы с образцом. Если лексема и образец совпадают,
|
||||||
|
// лексема изымается из потока.
|
||||||
|
|
||||||
|
bool match(Token t)
|
||||||
|
{
|
||||||
|
if(scanner_->token() == t) {
|
||||||
|
scanner_->nextToken();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переход к следующей лексеме.
|
||||||
|
|
||||||
|
void next()
|
||||||
|
{
|
||||||
|
scanner_->nextToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик ошибок.
|
||||||
|
void reportError(const string& message)
|
||||||
|
{
|
||||||
|
cerr << "Line " << scanner_->getLineNumber() << ": " << message << endl;
|
||||||
|
error_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mustBe(Token t); //проверяем, совпадает ли данная лексема с образцом. Если да, то лексема изымается из потока.
|
||||||
|
//Иначе создаем сообщение об ошибке и пробуем восстановиться
|
||||||
|
void recover(Token t); //восстановление после ошибки: идем по коду до тех пор,
|
||||||
|
//пока не встретим эту лексему или лексему конца файла.
|
||||||
|
int findOrAddVariable(const string&); //функция пробегает по variables_.
|
||||||
|
//Если находит нужную переменную - возвращает ее номер, иначе добавляет ее в массив, увеличивает lastVar и возвращает его.
|
||||||
|
|
||||||
|
Scanner* scanner_; //лексический анализатор для конструктора
|
||||||
|
CodeGen* codegen_; //указатель на виртуальную машину
|
||||||
|
ostream& output_; //выходной поток (в данном случае используем cout)
|
||||||
|
bool error_; //флаг ошибки. Используется чтобы определить, выводим ли список команд после разбора или нет
|
||||||
|
bool recovered_; //не используется
|
||||||
|
VarTable variables_; //массив переменных, найденных в программе
|
||||||
|
int lastVar_; //номер последней записанной переменной
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
lab4/cmilan/src/parser.o
Normal file
BIN
lab4/cmilan/src/parser.o
Normal file
Binary file not shown.
233
lab4/cmilan/src/scanner.cpp
Normal file
233
lab4/cmilan/src/scanner.cpp
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
#include "scanner.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
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",
|
||||||
|
"'('",
|
||||||
|
"')'",
|
||||||
|
"';'",
|
||||||
|
};
|
||||||
|
|
||||||
|
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<string, Token>::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 '+':
|
||||||
|
token_ = T_ADDOP;
|
||||||
|
arithmeticValue_ = A_PLUS;
|
||||||
|
nextChar();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
token_ = T_ADDOP;
|
||||||
|
arithmeticValue_ = A_MINUS;
|
||||||
|
nextChar();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
token_ = T_MULOP;
|
||||||
|
arithmeticValue_ = A_MULTIPLY;
|
||||||
|
nextChar();
|
||||||
|
break;
|
||||||
|
//Иначе лексема ошибки.
|
||||||
|
default:
|
||||||
|
token_ = T_ILLEGAL;
|
||||||
|
nextChar();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::skipSpace()
|
||||||
|
{
|
||||||
|
while(isspace(ch_)) {
|
||||||
|
if(ch_ == '\n') {
|
||||||
|
++lineNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::nextChar()
|
||||||
|
{
|
||||||
|
ch_ = input_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * tokenToString(Token t)
|
||||||
|
{
|
||||||
|
return tokenNames_[t];
|
||||||
|
}
|
||||||
|
|
||||||
164
lab4/cmilan/src/scanner.h
Normal file
164
lab4/cmilan/src/scanner.h
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#ifndef CMILAN_SCANNER_H
|
||||||
|
#define CMILAN_SCANNER_H
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
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 // ";"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция tokenToString возвращает описание лексемы.
|
||||||
|
// Используется при печати сообщения об ошибке.
|
||||||
|
const char * tokenToString(Token t);
|
||||||
|
|
||||||
|
// Виды операций сравнения
|
||||||
|
enum Cmp {
|
||||||
|
C_EQ, // Операция сравнения "="
|
||||||
|
C_NE, // Операция сравнения "!="
|
||||||
|
C_LT, // Операция сравнения "<"
|
||||||
|
C_LE, // Операция сравнения "<="
|
||||||
|
C_GT, // Операция сравнения ">"
|
||||||
|
C_GE // Операция сравнения ">="
|
||||||
|
};
|
||||||
|
|
||||||
|
// Виды арифметических операций
|
||||||
|
enum Arithmetic {
|
||||||
|
A_PLUS, //операция "+"
|
||||||
|
A_MINUS, //операция "-"
|
||||||
|
A_MULTIPLY, //операция "*"
|
||||||
|
A_DIVIDE //операция "/"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Лексический анализатор
|
||||||
|
|
||||||
|
class Scanner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Конструктор. В качестве аргумента принимает имя файла и поток,
|
||||||
|
// из которого будут читаться символы транслируемой программы.
|
||||||
|
|
||||||
|
explicit Scanner(const string& fileName, istream& input)
|
||||||
|
: fileName_(fileName), lineNumber_(1), input_(input)
|
||||||
|
{
|
||||||
|
keywords_["begin"] = T_BEGIN;
|
||||||
|
keywords_["end"] = T_END;
|
||||||
|
keywords_["if"] = T_IF;
|
||||||
|
keywords_["then"] = T_THEN;
|
||||||
|
keywords_["else"] = T_ELSE;
|
||||||
|
keywords_["fi"] = T_FI;
|
||||||
|
keywords_["while"] = T_WHILE;
|
||||||
|
keywords_["do"] = T_DO;
|
||||||
|
keywords_["od"] = T_OD;
|
||||||
|
keywords_["write"] = T_WRITE;
|
||||||
|
keywords_["read"] = T_READ;
|
||||||
|
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Деструктор
|
||||||
|
virtual ~Scanner()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//getters всех private переменных
|
||||||
|
const string& getFileName() const //не используется
|
||||||
|
{
|
||||||
|
return fileName_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLineNumber() const
|
||||||
|
{
|
||||||
|
return lineNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token token() const
|
||||||
|
{
|
||||||
|
return token_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getIntValue() const
|
||||||
|
{
|
||||||
|
return intValue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
string getStringValue() const
|
||||||
|
{
|
||||||
|
return stringValue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmp getCmpValue() const
|
||||||
|
{
|
||||||
|
return cmpValue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arithmetic getArithmeticValue() const
|
||||||
|
{
|
||||||
|
return arithmeticValue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Переход к следующей лексеме.
|
||||||
|
// Текущая лексема записывается в token_ и изымается из потока.
|
||||||
|
void nextToken();
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Пропуск всех пробельные символы.
|
||||||
|
// Если встречается символ перевода строки, номер текущей строки
|
||||||
|
// (lineNumber) увеличивается на единицу.
|
||||||
|
void skipSpace();
|
||||||
|
|
||||||
|
|
||||||
|
void nextChar(); //переходит к следующему символу
|
||||||
|
//проверка переменной на первый символ (должен быть буквой латинского алфавита)
|
||||||
|
bool isIdentifierStart(char c)
|
||||||
|
{
|
||||||
|
return ((c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= 'A' && c <= 'Z'));
|
||||||
|
}
|
||||||
|
//проверка на остальные символы переменной (буква или цифра)
|
||||||
|
bool isIdentifierBody(char c)
|
||||||
|
{
|
||||||
|
return isIdentifierStart(c) || isdigit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const string fileName_; //входной файл
|
||||||
|
int lineNumber_; //номер текущей строки кода
|
||||||
|
|
||||||
|
Token token_; //текущая лексема
|
||||||
|
int intValue_; //значение текущего целого
|
||||||
|
string stringValue_; //имя переменной
|
||||||
|
Cmp cmpValue_; //значение оператора сравнения (>, <, =, !=, >=, <=)
|
||||||
|
Arithmetic arithmeticValue_; //значение знака (+,-,*,/)
|
||||||
|
|
||||||
|
map<string, Token> keywords_; //ассоциативный массив с лексемами и
|
||||||
|
//соответствующими им зарезервированными словами в качестве индексов
|
||||||
|
|
||||||
|
istream& input_; //входной поток для чтения из файла.
|
||||||
|
char ch_; //текущий символ
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
lab4/cmilan/src/scanner.o
Normal file
BIN
lab4/cmilan/src/scanner.o
Normal file
Binary file not shown.
7
lab4/cmilan/test/add.mil
Normal file
7
lab4/cmilan/test/add.mil
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
BEGIN
|
||||||
|
i := 1;
|
||||||
|
j := 2;
|
||||||
|
k := i + j;
|
||||||
|
WRITE(k)
|
||||||
|
END
|
||||||
|
|
||||||
14
lab4/cmilan/test/comment.mil
Normal file
14
lab4/cmilan/test/comment.mil
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/* это комментарий */
|
||||||
|
/* это продолжение комментария */
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* эта программа печатает 42 *
|
||||||
|
****************************/
|
||||||
|
|
||||||
|
begin /* комментарий в конце строки */
|
||||||
|
/* комментарий в начале строки */ write(42)
|
||||||
|
/* многострочный
|
||||||
|
комментарий */
|
||||||
|
end
|
||||||
|
|
||||||
|
/* комментарий в конце файла */
|
||||||
10
lab4/cmilan/test/factorial.mil
Normal file
10
lab4/cmilan/test/factorial.mil
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
BEGIN
|
||||||
|
n := READ;
|
||||||
|
factorial := 1;
|
||||||
|
i := 1;
|
||||||
|
WHILE i <= n DO
|
||||||
|
factorial := factorial * i;
|
||||||
|
i := i + 1
|
||||||
|
OD;
|
||||||
|
WRITE(factorial)
|
||||||
|
END
|
||||||
17
lab4/cmilan/test/fib.mil
Normal file
17
lab4/cmilan/test/fib.mil
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> N-<2D><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
a := 1;
|
||||||
|
b := 1;
|
||||||
|
n := READ;
|
||||||
|
|
||||||
|
WHILE n > 1 DO
|
||||||
|
t := a;
|
||||||
|
a := b;
|
||||||
|
b := b + t;
|
||||||
|
n := n - 1
|
||||||
|
OD;
|
||||||
|
|
||||||
|
WRITE(a)
|
||||||
|
END
|
||||||
|
|
||||||
17
lab4/cmilan/test/gcd.mil
Normal file
17
lab4/cmilan/test/gcd.mil
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/* Greatest common divisor */
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
a := READ;
|
||||||
|
b := READ;
|
||||||
|
|
||||||
|
WHILE a != b DO
|
||||||
|
IF a < b THEN
|
||||||
|
b := b - a
|
||||||
|
ELSE
|
||||||
|
a := a - b
|
||||||
|
FI
|
||||||
|
OD;
|
||||||
|
|
||||||
|
WRITE(a)
|
||||||
|
END
|
||||||
|
|
||||||
8
lab4/cmilan/test/if.mil
Normal file
8
lab4/cmilan/test/if.mil
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
BEGIN
|
||||||
|
i := 1;
|
||||||
|
j := 2;
|
||||||
|
|
||||||
|
IF i < j THEN WRITE(i) FI;
|
||||||
|
IF i < j THEN WRITE(i) ELSE WRITE(j) FI
|
||||||
|
END
|
||||||
|
|
||||||
5
lab4/cmilan/test/invalid.mil
Normal file
5
lab4/cmilan/test/invalid.mil
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
BEGIN
|
||||||
|
IF 1 2 THEN WRITE(n) ELSE WRITE(2) FI;
|
||||||
|
X := Y + 1;
|
||||||
|
WRITE (X +)
|
||||||
|
END
|
||||||
14
lab4/cmilan/test/invert.mil
Normal file
14
lab4/cmilan/test/invert.mil
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
BEGIN
|
||||||
|
x := READ;
|
||||||
|
x := -x;
|
||||||
|
|
||||||
|
WRITE(-x);
|
||||||
|
|
||||||
|
IF -x > 0 THEN x := 1 FI;
|
||||||
|
|
||||||
|
x := x + -1;
|
||||||
|
x := x - -x;
|
||||||
|
|
||||||
|
x := x -1
|
||||||
|
END
|
||||||
|
|
||||||
17
lab4/cmilan/test/loop.mil
Normal file
17
lab4/cmilan/test/loop.mil
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
BEGIN
|
||||||
|
/* Read a number */
|
||||||
|
|
||||||
|
i := READ;
|
||||||
|
|
||||||
|
/* Count from 0 to this number */
|
||||||
|
|
||||||
|
IF i > 0 THEN step := 1 ELSE step := -1 FI;
|
||||||
|
k := 0;
|
||||||
|
WHILE k != i DO
|
||||||
|
WRITE(k);
|
||||||
|
k := k + step
|
||||||
|
OD;
|
||||||
|
|
||||||
|
WRITE(i)
|
||||||
|
END
|
||||||
|
|
||||||
14
lab4/cmilan/test/power.mil
Normal file
14
lab4/cmilan/test/power.mil
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
BEGIN
|
||||||
|
N := READ;
|
||||||
|
P := READ;
|
||||||
|
|
||||||
|
S := 1;
|
||||||
|
|
||||||
|
WHILE P > 0 DO
|
||||||
|
S := S * N;
|
||||||
|
P := P - 1
|
||||||
|
OD;
|
||||||
|
|
||||||
|
WRITE(S)
|
||||||
|
END
|
||||||
|
|
||||||
8
lab4/cmilan/test/read2.mil
Normal file
8
lab4/cmilan/test/read2.mil
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
BEGIN
|
||||||
|
IF READ < READ
|
||||||
|
THEN
|
||||||
|
WRITE(1)
|
||||||
|
ELSE
|
||||||
|
WRITE(2)
|
||||||
|
FI
|
||||||
|
END
|
||||||
9
lab4/cmilan/test/sum.mil
Normal file
9
lab4/cmilan/test/sum.mil
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
BEGIN
|
||||||
|
i := 8;
|
||||||
|
j := 2;
|
||||||
|
|
||||||
|
WHILE i != j DO
|
||||||
|
IF i < j THEN j := j - i ELSE i := i - j FI
|
||||||
|
OD;
|
||||||
|
WRITE(i)
|
||||||
|
END
|
||||||
BIN
lab4/vm/bin/milanvm.exe
Normal file
BIN
lab4/vm/bin/milanvm.exe
Normal file
Binary file not shown.
10
lab4/vm/doc/changelog.txt
Normal file
10
lab4/vm/doc/changelog.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:
|
||||||
|
==================
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1.2:
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ymilan <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> NOP (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>).
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1.1:
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ymilan 1.1.
|
||||||
224
lab4/vm/doc/vm.txt
Normal file
224
lab4/vm/doc/vm.txt
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
== <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ==
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
NOP
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
STOP
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
LOAD <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>.
|
||||||
|
|
||||||
|
STORE <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>.
|
||||||
|
<20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
|
||||||
|
BLOAD <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:
|
||||||
|
<<3C><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>> = <<3C><><EFBFBD><EFBFBD><EFBFBD>> + <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> BLOAD <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
BSTORE <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:
|
||||||
|
<<3C><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>> = <<3C><><EFBFBD><EFBFBD><EFBFBD>> + <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> BSTORE <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>: [10, 20, ...]. <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> BSTORE 5
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 15 <20><><EFBFBD><EFBFBD><EFBFBD> 20.
|
||||||
|
|
||||||
|
PUSH <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>> <20> <20><><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
POP
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
DUP
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
ADD
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
MULT
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
SUB
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <a>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <b>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <b> - <a>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
PUSH 10
|
||||||
|
PUSH 8
|
||||||
|
SUB
|
||||||
|
|
||||||
|
<20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> 2.
|
||||||
|
|
||||||
|
DIV
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <a>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <b>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <b> / <a>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <a> = 0, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
INVERT
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
COMPARE <<3C><><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <a>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <b>,
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <b> <20> <a>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD>>:
|
||||||
|
|
||||||
|
<<3C><><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
0 <b> = <a>
|
||||||
|
1 <b> != <a>
|
||||||
|
2 <b> < <a>
|
||||||
|
3 <b> > <a>
|
||||||
|
4 <b> <= <a>
|
||||||
|
5 <b> >= <a>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> 0 <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
PUSH 5
|
||||||
|
PUSH 7
|
||||||
|
COMPARE 2
|
||||||
|
|
||||||
|
<20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1 (<28><><EFBFBD> <20><><EFBFBD> 5 < 7).
|
||||||
|
|
||||||
|
JUMP <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>, <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>. <20><><EFBFBD><EFBFBD>
|
||||||
|
<<3C><><EFBFBD><EFBFBD><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
|
||||||
|
JUMP_YES <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>, <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>; <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
JUMP_NO <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>>, <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0; <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD>
|
||||||
|
<<3C><><EFBFBD><EFBFBD><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
INPUT
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20> <20><><EFBFBD><EFBFBD>. <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
PRINT
|
||||||
|
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<20><><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ';' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> <20> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ':'. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> 0.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: STOP. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
0: INPUT
|
||||||
|
1: STORE 42 ; n := READ
|
||||||
|
2: LOAD 14
|
||||||
|
3: PUSH 4
|
||||||
|
4: LOAD 42
|
||||||
|
5: COMPARE 2
|
||||||
|
6: JUMP_NO 9
|
||||||
|
7: PUSH 10
|
||||||
|
8: STORE 42
|
||||||
|
9: LOAD 42
|
||||||
|
10: PRINT
|
||||||
|
11: STOP
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET:
|
||||||
|
|
||||||
|
SET <<3C><><EFBFBD><EFBFBD><EFBFBD>> <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD>> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET <<3C><><EFBFBD><EFBFBD><EFBFBD>> <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
PUSH <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
STORE <<3C><><EFBFBD><EFBFBD><EFBFBD>>
|
||||||
|
|
||||||
|
<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>.
|
||||||
|
|
||||||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SET:
|
||||||
|
|
||||||
|
------------------------------------
|
||||||
|
SET 0 15
|
||||||
|
SET 1 40
|
||||||
|
|
||||||
|
0: LOAD 0
|
||||||
|
1: LOAD 1
|
||||||
|
2: ADD
|
||||||
|
3: PRINT
|
||||||
|
4: STOP
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> 55.
|
||||||
|
|
||||||
15
lab4/vm/vm/Makefile
Normal file
15
lab4/vm/vm/Makefile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
mvm: vm.c lex.yy.c vmparse.tab.h main.c
|
||||||
|
gcc -o mvm main.c vm.c lex.yy.c vmparse.tab.c
|
||||||
|
|
||||||
|
lex.yy.c: vmlex.l
|
||||||
|
flex vmlex.l
|
||||||
|
|
||||||
|
vmparse.tab.h: vmparse.y
|
||||||
|
bison -d vmparse.y
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm lex.yy.c vmparse.tab.h vmparse.tab.c
|
||||||
|
|
||||||
|
distclean:
|
||||||
|
rm mvm lex.yy.c vmparse.tab.h vmparse.tab.c
|
||||||
|
|
||||||
1690
lab4/vm/vm/lex.yy.c
Normal file
1690
lab4/vm/vm/lex.yy.c
Normal file
File diff suppressed because it is too large
Load Diff
46
lab4/vm/vm/main.c
Normal file
46
lab4/vm/vm/main.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#include "vmparse.tab.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
extern FILE *yyin;
|
||||||
|
int need_close = 0;
|
||||||
|
|
||||||
|
int yyparse();
|
||||||
|
|
||||||
|
void milan_error(char const * msg)
|
||||||
|
{
|
||||||
|
if(need_close)
|
||||||
|
fclose(yyin);
|
||||||
|
|
||||||
|
fprintf(stderr, msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc < 2) {
|
||||||
|
yyin = stdin;
|
||||||
|
printf("Reading input from stdin\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yyin = fopen(argv[1], "rt");
|
||||||
|
if(!yyin) {
|
||||||
|
printf("Unable to read %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
need_close = 1;
|
||||||
|
printf("Reading input from %s\n", argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 == yyparse()) {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(need_close) {
|
||||||
|
fclose(yyin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
6
lab4/vm/vm/test/bop1.ms
Normal file
6
lab4/vm/vm/test/bop1.ms
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
4: STOP
|
||||||
|
1: PUSH 20
|
||||||
|
2: ADD
|
||||||
|
3: PRINT
|
||||||
|
0: PUSH 10
|
||||||
|
2: MULT
|
||||||
8
lab4/vm/vm/test/bop2.ms
Normal file
8
lab4/vm/vm/test/bop2.ms
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
0: PUSH 10
|
||||||
|
1: PUSH -1
|
||||||
|
2: BSTORE 2
|
||||||
|
3: PUSH 0
|
||||||
|
4: BLOAD 1
|
||||||
|
5: PRINT
|
||||||
|
6: STOP
|
||||||
|
|
||||||
37
lab4/vm/vm/test/fib.ms
Normal file
37
lab4/vm/vm/test/fib.ms
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> N-<2D><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
SET 0 0 ; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0
|
||||||
|
SET 1 1 ; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1
|
||||||
|
|
||||||
|
SET 1000 0 ; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> n
|
||||||
|
SET 1001 1 ; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> a
|
||||||
|
SET 1002 1 ; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> b
|
||||||
|
|
||||||
|
; <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
0: INPUT
|
||||||
|
1: STORE 1000 ; n := READ
|
||||||
|
|
||||||
|
2: LOAD 1000
|
||||||
|
3: LOAD 1
|
||||||
|
4: COMPARE 3 ; IF n > 1
|
||||||
|
5: JUMP_NO 17
|
||||||
|
|
||||||
|
6: LOAD 1002 ; STACK <- b
|
||||||
|
7: LOAD 1001 ; STACK <- a
|
||||||
|
8: LOAD 1002
|
||||||
|
9: STORE 1001 ; a := b
|
||||||
|
10: ADD
|
||||||
|
11: STORE 1002 ; b := <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD><5F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_a + b
|
||||||
|
|
||||||
|
12: LOAD 1000
|
||||||
|
13: LOAD 1
|
||||||
|
14: SUB
|
||||||
|
15: STORE 1000 ; n := n - 1
|
||||||
|
16: JUMP 2
|
||||||
|
|
||||||
|
17: LOAD 1001 ; WRITE(a)
|
||||||
|
18: PRINT
|
||||||
|
|
||||||
|
19: STOP
|
||||||
|
|
||||||
21
lab4/vm/vm/test/fib2.ms
Normal file
21
lab4/vm/vm/test/fib2.ms
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
SET 0 1
|
||||||
|
SET 1 1
|
||||||
|
|
||||||
|
0: INPUT
|
||||||
|
1: DUP
|
||||||
|
2: PUSH 1
|
||||||
|
3: COMPARE 3
|
||||||
|
4: JUMP_NO 14
|
||||||
|
5: LOAD 1
|
||||||
|
6: LOAD 0
|
||||||
|
7: LOAD 1
|
||||||
|
8: STORE 0
|
||||||
|
9: ADD
|
||||||
|
10: STORE 1
|
||||||
|
11: PUSH 1
|
||||||
|
12: SUB
|
||||||
|
13: JUMP 1
|
||||||
|
14: LOAD 0
|
||||||
|
15: PRINT
|
||||||
|
16: STOP
|
||||||
|
|
||||||
371
lab4/vm/vm/vm.c
Normal file
371
lab4/vm/vm/vm.c
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
void milan_error();
|
||||||
|
|
||||||
|
command vm_program[MAX_PROGRAM_SIZE];
|
||||||
|
|
||||||
|
int vm_memory[MAX_MEMORY_SIZE];
|
||||||
|
int vm_stack[MAX_STACK_SIZE];
|
||||||
|
|
||||||
|
unsigned int vm_stack_pointer = 0;
|
||||||
|
unsigned int vm_command_pointer = 0;
|
||||||
|
|
||||||
|
opcode_info opcodes_table[] = {
|
||||||
|
{"NOP", 0},
|
||||||
|
{"STOP", 0},
|
||||||
|
{"LOAD", 1},
|
||||||
|
{"STORE", 1},
|
||||||
|
{"BLOAD", 1},
|
||||||
|
{"BSTORE", 1},
|
||||||
|
{"PUSH", 1},
|
||||||
|
{"POP", 0},
|
||||||
|
{"DUP", 0},
|
||||||
|
{"INVERT", 0},
|
||||||
|
{"ADD", 0},
|
||||||
|
{"SUB", 0},
|
||||||
|
{"MULT", 0},
|
||||||
|
{"DIV", 0},
|
||||||
|
{"COMPARE", 1},
|
||||||
|
{"JUMP", 1},
|
||||||
|
{"JUMP_YES", 1},
|
||||||
|
{"JUMP_NO", 1},
|
||||||
|
{"INPUT", 0},
|
||||||
|
{"PRINT", 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int opcodes_table_size = sizeof(opcodes_table) / sizeof(opcode_info);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BAD_DATA_ADDRESS,
|
||||||
|
BAD_CODE_ADDRESS,
|
||||||
|
BAD_RELATION,
|
||||||
|
STACK_OVERFLOW,
|
||||||
|
STACK_EMPTY,
|
||||||
|
DIVISION_BY_ZERO,
|
||||||
|
BAD_INPUT,
|
||||||
|
UNKNOWN_COMMAND
|
||||||
|
} runtime_error;
|
||||||
|
|
||||||
|
void vm_init()
|
||||||
|
{
|
||||||
|
vm_stack_pointer = 0;
|
||||||
|
vm_command_pointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_error(runtime_error error)
|
||||||
|
{
|
||||||
|
opcode_info* info;
|
||||||
|
|
||||||
|
switch(error) {
|
||||||
|
case BAD_DATA_ADDRESS:
|
||||||
|
fprintf(stderr, "Error: illegal data address\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAD_CODE_ADDRESS:
|
||||||
|
fprintf(stderr, "Error: illegal address in JUMP* instruction\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAD_RELATION:
|
||||||
|
fprintf(stderr, "Error: illegal comparison operator\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STACK_OVERFLOW:
|
||||||
|
fprintf(stderr, "Error: stack overflow\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STACK_EMPTY:
|
||||||
|
fprintf(stderr, "Error: stack is empty (no arguments are available)\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIVISION_BY_ZERO:
|
||||||
|
fprintf(stderr, "Error: division by zero\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAD_INPUT:
|
||||||
|
fprintf(stderr, "Error: illegal input\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UNKNOWN_COMMAND:
|
||||||
|
fprintf(stderr, "Error: unknown command, unable to execute\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: runtime error %d\n", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Code:\n\n");
|
||||||
|
|
||||||
|
info = operation_info(vm_program[vm_command_pointer].operation);
|
||||||
|
if(NULL == info) {
|
||||||
|
fprintf(stderr, "%d\t(%d)\t\t%d\n", vm_command_pointer,
|
||||||
|
vm_program[vm_command_pointer].operation,
|
||||||
|
vm_program[vm_command_pointer].arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(info->need_arg) {
|
||||||
|
fprintf(stderr, "\t%d\t%s\t\t%d\n", vm_command_pointer, info->name,
|
||||||
|
vm_program[vm_command_pointer].arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "\t%d\t%s\n", vm_command_pointer, info->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
milan_error("VM error");
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_load(unsigned int address)
|
||||||
|
{
|
||||||
|
if(address < MAX_MEMORY_SIZE) {
|
||||||
|
return vm_memory[address];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_DATA_ADDRESS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_store(unsigned int address, int word)
|
||||||
|
{
|
||||||
|
if(address < MAX_MEMORY_SIZE) {
|
||||||
|
vm_memory[address] = word;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_DATA_ADDRESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_read()
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
fprintf(stderr, "> "); fflush(stdout);
|
||||||
|
if(scanf("%d", &n)) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_INPUT);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_write(int n)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%d\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_pop()
|
||||||
|
{
|
||||||
|
if(vm_stack_pointer > 0) {
|
||||||
|
return vm_stack[--vm_stack_pointer];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(STACK_EMPTY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_push(int word)
|
||||||
|
{
|
||||||
|
if(vm_stack_pointer < MAX_STACK_SIZE) {
|
||||||
|
vm_stack[vm_stack_pointer++] = word;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(STACK_OVERFLOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_run_command()
|
||||||
|
{
|
||||||
|
unsigned int index = vm_command_pointer;
|
||||||
|
|
||||||
|
operation op = vm_program[index].operation;
|
||||||
|
unsigned int arg = vm_program[index].arg;
|
||||||
|
int data;
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
case NOP:
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STOP:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOAD:
|
||||||
|
vm_push(vm_load(arg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STORE:
|
||||||
|
vm_store(arg, vm_pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BLOAD:
|
||||||
|
vm_push(vm_load(arg + vm_pop()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BSTORE:
|
||||||
|
data = vm_pop();
|
||||||
|
vm_store(arg + data, vm_pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PUSH:
|
||||||
|
vm_push(arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POP:
|
||||||
|
vm_pop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DUP:
|
||||||
|
data = vm_pop();
|
||||||
|
vm_push(data);
|
||||||
|
vm_push(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INVERT:
|
||||||
|
vm_push(-vm_pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADD:
|
||||||
|
data = vm_pop();
|
||||||
|
vm_push(vm_pop() + data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUB:
|
||||||
|
data = vm_pop();
|
||||||
|
vm_push(vm_pop() - data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MULT:
|
||||||
|
data = vm_pop();
|
||||||
|
vm_push(vm_pop() * data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIV:
|
||||||
|
data = vm_pop();
|
||||||
|
if(0 == data) {
|
||||||
|
vm_error(DIVISION_BY_ZERO);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_push(vm_pop() / data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COMPARE:
|
||||||
|
data = vm_pop();
|
||||||
|
switch(arg) {
|
||||||
|
case EQ:
|
||||||
|
vm_push((vm_pop() == data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NE:
|
||||||
|
vm_push((vm_pop() != data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LT:
|
||||||
|
vm_push((vm_pop() < data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GT:
|
||||||
|
vm_push((vm_pop() > data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LE:
|
||||||
|
vm_push((vm_pop() <= data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GE:
|
||||||
|
vm_push((vm_pop() >= data) ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vm_error(BAD_RELATION);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP:
|
||||||
|
if(arg < MAX_PROGRAM_SIZE) {
|
||||||
|
vm_command_pointer = arg;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_CODE_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP_YES:
|
||||||
|
if(arg < MAX_PROGRAM_SIZE) {
|
||||||
|
data = vm_pop();
|
||||||
|
if(data) {
|
||||||
|
vm_command_pointer = arg;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_CODE_ADDRESS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JUMP_NO:
|
||||||
|
if(arg < MAX_PROGRAM_SIZE) {
|
||||||
|
data = vm_pop();
|
||||||
|
if(!data) {
|
||||||
|
vm_command_pointer = arg;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vm_error(BAD_CODE_ADDRESS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INPUT:
|
||||||
|
vm_push(vm_read());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINT:
|
||||||
|
vm_write(vm_pop());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vm_error(UNKNOWN_COMMAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
++vm_command_pointer;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
vm_command_pointer = 0;
|
||||||
|
while(vm_command_pointer < MAX_PROGRAM_SIZE) {
|
||||||
|
if(!vm_run_command())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode_info* operation_info(operation op)
|
||||||
|
{
|
||||||
|
return (op < opcodes_table_size) ? &opcodes_table[op] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_command(unsigned int address, operation op, int arg)
|
||||||
|
{
|
||||||
|
if(address < MAX_PROGRAM_SIZE) {
|
||||||
|
vm_program[address].operation = op;
|
||||||
|
vm_program[address].arg = arg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
milan_error("Illegal address in put_command()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_mem(unsigned int address, int value)
|
||||||
|
{
|
||||||
|
vm_memory[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
88
lab4/vm/vm/vm.h
Normal file
88
lab4/vm/vm/vm.h
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#ifndef _MILAN_VM_H
|
||||||
|
#define _MILAN_VM_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
#define MAX_PROGRAM_SIZE 65536
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
#define MAX_MEMORY_SIZE 65536
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
#define MAX_STACK_SIZE 8192
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
typedef enum {
|
||||||
|
NOP = 0, /* <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
STOP, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
LOAD, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
STORE, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
BLOAD, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
BSTORE, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
PUSH, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD> */
|
||||||
|
POP, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
DUP, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
INVERT, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
ADD, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
SUB, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
MULT, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
DIV, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
COMPARE, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
JUMP, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
JUMP_YES, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> 0 */
|
||||||
|
JUMP_NO, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> 0 */
|
||||||
|
INPUT, /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
PRINT /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
} operation;
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
typedef enum {
|
||||||
|
EQ, /* = */
|
||||||
|
NE, /* !- */
|
||||||
|
LT, /* < */
|
||||||
|
GT, /* > */
|
||||||
|
LE, /* <= */
|
||||||
|
GE /* >= */
|
||||||
|
} compare_type;
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
typedef struct {
|
||||||
|
operation operation; /* <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
int arg; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
} command;
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
typedef struct opcode_info {
|
||||||
|
char *name; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
int need_arg; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
} opcode_info;
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD> op.
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
opcode_info* operation_info(operation op);
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> address. */
|
||||||
|
|
||||||
|
void put_command(unsigned int address, operation op, int arg);
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
*
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0 <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> STOP <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> value <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> address. */
|
||||||
|
|
||||||
|
void set_mem(unsigned int address, int value);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
51
lab4/vm/vm/vmlex.l
Normal file
51
lab4/vm/vm/vmlex.l
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
%{
|
||||||
|
#include "vmparse.tab.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
#define YY_NO_UNISTD_H
|
||||||
|
#endif
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option noyywrap
|
||||||
|
|
||||||
|
WHITESPACE [ \t]+
|
||||||
|
EOL \n
|
||||||
|
INT -?[0-9]+
|
||||||
|
COMMENT ;[^\n]*\n
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
{EOL}
|
||||||
|
{COMMENT}
|
||||||
|
{WHITESPACE}
|
||||||
|
{INT} { yylval = atoi(yytext); return T_INT; }
|
||||||
|
|
||||||
|
: { return T_COLON; }
|
||||||
|
|
||||||
|
SET { return T_SET; }
|
||||||
|
STOP { return T_STOP; }
|
||||||
|
LOAD { return T_LOAD; }
|
||||||
|
STORE { return T_STORE; }
|
||||||
|
BLOAD { return T_BLOAD; }
|
||||||
|
BSTORE { return T_BSTORE; }
|
||||||
|
PUSH { return T_PUSH; }
|
||||||
|
POP { return T_POP; }
|
||||||
|
DUP { return T_DUP; }
|
||||||
|
INVERT { return T_INVERT; }
|
||||||
|
ADD { return T_ADD; }
|
||||||
|
SUB { return T_SUB; }
|
||||||
|
MULT { return T_MULT; }
|
||||||
|
DIV { return T_DIV; }
|
||||||
|
COMPARE { return T_COMPARE; }
|
||||||
|
JUMP { return T_JUMP; }
|
||||||
|
JUMP_YES { return T_JUMP_YES; }
|
||||||
|
JUMP_NO { return T_JUMP_NO; }
|
||||||
|
INPUT { return T_INPUT; }
|
||||||
|
PRINT { return T_PRINT; }
|
||||||
|
NOP { return T_NOP; }
|
||||||
|
|
||||||
|
<<EOF>> { yyterminate(); }
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
1736
lab4/vm/vm/vmparse.tab.c
Normal file
1736
lab4/vm/vm/vmparse.tab.c
Normal file
File diff suppressed because it is too large
Load Diff
79
lab4/vm/vm/vmparse.tab.h
Normal file
79
lab4/vm/vm/vmparse.tab.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
/* A Bison parser, made by GNU Bison 2.4.1. */
|
||||||
|
|
||||||
|
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||||
|
|
||||||
|
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* As a special exception, you may create a larger work that contains
|
||||||
|
part or all of the Bison parser skeleton and distribute that work
|
||||||
|
under terms of your choice, so long as that work isn't itself a
|
||||||
|
parser generator using the skeleton or a modified version thereof
|
||||||
|
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||||
|
the parser skeleton itself, you may (at your option) remove this
|
||||||
|
special exception, which will cause the skeleton and the resulting
|
||||||
|
Bison output files to be licensed under the GNU General Public
|
||||||
|
License without this special exception.
|
||||||
|
|
||||||
|
This special exception was added by the Free Software Foundation in
|
||||||
|
version 2.2 of Bison. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Tokens. */
|
||||||
|
#ifndef YYTOKENTYPE
|
||||||
|
# define YYTOKENTYPE
|
||||||
|
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||||
|
know about them. */
|
||||||
|
enum yytokentype {
|
||||||
|
T_INT = 258,
|
||||||
|
T_SET = 259,
|
||||||
|
T_NOP = 260,
|
||||||
|
T_STOP = 261,
|
||||||
|
T_LOAD = 262,
|
||||||
|
T_STORE = 263,
|
||||||
|
T_BLOAD = 264,
|
||||||
|
T_BSTORE = 265,
|
||||||
|
T_PUSH = 266,
|
||||||
|
T_POP = 267,
|
||||||
|
T_DUP = 268,
|
||||||
|
T_INVERT = 269,
|
||||||
|
T_ADD = 270,
|
||||||
|
T_SUB = 271,
|
||||||
|
T_MULT = 272,
|
||||||
|
T_DIV = 273,
|
||||||
|
T_COMPARE = 274,
|
||||||
|
T_JUMP = 275,
|
||||||
|
T_JUMP_YES = 276,
|
||||||
|
T_JUMP_NO = 277,
|
||||||
|
T_INPUT = 278,
|
||||||
|
T_PRINT = 279,
|
||||||
|
T_COLON = 280
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||||
|
typedef int YYSTYPE;
|
||||||
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
|
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||||
|
# define YYSTYPE_IS_DECLARED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern YYSTYPE yylval;
|
||||||
|
|
||||||
|
|
||||||
70
lab4/vm/vm/vmparse.y
Normal file
70
lab4/vm/vm/vmparse.y
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
%{
|
||||||
|
#include "vm.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define YYSTYPE int
|
||||||
|
|
||||||
|
int yylex();
|
||||||
|
void yyerror(char const *);
|
||||||
|
%}
|
||||||
|
|
||||||
|
%token T_INT
|
||||||
|
%token T_SET
|
||||||
|
%token T_NOP
|
||||||
|
%token T_STOP
|
||||||
|
%token T_LOAD
|
||||||
|
%token T_STORE
|
||||||
|
%token T_BLOAD
|
||||||
|
%token T_BSTORE
|
||||||
|
%token T_PUSH
|
||||||
|
%token T_POP
|
||||||
|
%token T_DUP
|
||||||
|
%token T_INVERT
|
||||||
|
%token T_ADD
|
||||||
|
%token T_SUB
|
||||||
|
%token T_MULT
|
||||||
|
%token T_DIV
|
||||||
|
%token T_COMPARE
|
||||||
|
%token T_JUMP
|
||||||
|
%token T_JUMP_YES
|
||||||
|
%token T_JUMP_NO
|
||||||
|
%token T_INPUT
|
||||||
|
%token T_PRINT
|
||||||
|
%token T_COLON
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
program : line program
|
||||||
|
| line
|
||||||
|
;
|
||||||
|
|
||||||
|
line : T_INT T_COLON T_NOP { put_command($1, NOP, 0); }
|
||||||
|
| T_INT T_COLON T_STOP { put_command($1, STOP, 0); }
|
||||||
|
| T_INT T_COLON T_LOAD T_INT { put_command($1, LOAD, $4); }
|
||||||
|
| T_INT T_COLON T_STORE T_INT { put_command($1, STORE, $4); }
|
||||||
|
| T_INT T_COLON T_BLOAD T_INT { put_command($1, BLOAD, $4); }
|
||||||
|
| T_INT T_COLON T_BSTORE T_INT { put_command($1, BSTORE, $4); }
|
||||||
|
| T_INT T_COLON T_PUSH T_INT { put_command($1, PUSH, $4); }
|
||||||
|
| T_INT T_COLON T_POP { put_command($1, POP, 0); }
|
||||||
|
| T_INT T_COLON T_DUP { put_command($1, DUP, 0); }
|
||||||
|
| T_INT T_COLON T_INVERT { put_command($1, INVERT, 0); }
|
||||||
|
| T_INT T_COLON T_ADD { put_command($1, ADD, 0); }
|
||||||
|
| T_INT T_COLON T_SUB { put_command($1, SUB, 0); }
|
||||||
|
| T_INT T_COLON T_MULT { put_command($1, MULT, 0); }
|
||||||
|
| T_INT T_COLON T_DIV { put_command($1, DIV, 0); }
|
||||||
|
| T_INT T_COLON T_COMPARE T_INT { put_command($1, COMPARE, $4); }
|
||||||
|
| T_INT T_COLON T_JUMP T_INT { put_command($1, JUMP, $4); }
|
||||||
|
| T_INT T_COLON T_JUMP_YES T_INT { put_command($1, JUMP_YES, $4); }
|
||||||
|
| T_INT T_COLON T_JUMP_NO T_INT { put_command($1, JUMP_NO, $4); }
|
||||||
|
| T_INT T_COLON T_INPUT { put_command($1, INPUT, 0); }
|
||||||
|
| T_INT T_COLON T_PRINT { put_command($1, PRINT, 0); }
|
||||||
|
| T_SET T_INT T_INT { set_mem($2, $3); }
|
||||||
|
;
|
||||||
|
%%
|
||||||
|
|
||||||
|
void yyerror(char const *str)
|
||||||
|
{
|
||||||
|
printf("Error: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user