О классах - blockschemstudio

advertisement
Балтийский государственный технический университет
«Военмех» им. Д.Ф.Устинова
Кафедра И3
«Системы обработки информации и управления»
Лабораторная работа по программированию
“Калькулятор на основе обратной польской записи”
Выполнил:
Козятинский А.Ю.
Группа И383
Санкт-Петербург
2010
1
Оглавление
Выдержки из теории ................................................................................................................................... 3
Обратная польская нотация ................................................................................................................... 3
Конечный автомат ................................................................................................................................... 3
Таблица с использованием хэш – функций........................................................................................... 4
Разрешение коллизий ......................................................................................................................... 5
Сведения о программе ............................................................................................................................... 6
О пути данных сквозь строки кода......................................................................................................... 6
О конечном автомате .............................................................................................................................. 6
Таблица переходов: ............................................................................................................................ 7
О хэш-таблицах ........................................................................................................................................ 8
О классах .................................................................................................................................................. 8
Класс Tables .......................................................................................................................................... 8
Класс Avtomat ...................................................................................................................................... 9
Класс RPN.............................................................................................................................................. 9
Класс HashTableOprs ..........................................................................................................................10
Класс HashTableEllPri ........................................................................................................................10
Класс Ellement ....................................................................................................................................10
Класс Ellement_Priority ......................................................................................................................11
Классы Open и Close ..........................................................................................................................11
Класc Operation ..................................................................................................................................11
Классы Delenie,Factorial,Minus,Plus,Step,Umnogenie ......................................................................11
Класс User_Operation ........................................................................................................................12
Класс Operand ....................................................................................................................................12
Класс Var .............................................................................................................................................12
Класс Const .........................................................................................................................................12
Листинг .......................................................................................................................................................13
Заголовочные файлы ............................................................................................................................13
“AllRPN.h” ...........................................................................................................................................13
“Avtomat.h” ........................................................................................................................................13
“Close.h”..............................................................................................................................................17
“Const.h” .............................................................................................................................................17
“Delenie.h” ..........................................................................................................................................18
2
“Ellement.h” ........................................................................................................................................18
“Ellement_Priority.h” ..........................................................................................................................19
“Excpt_ParAmount.h” .........................................................................................................................20
“Factorial.h” ........................................................................................................................................21
“HashTable.h” .....................................................................................................................................22
“Minus.h” ............................................................................................................................................27
“Open.h” .............................................................................................................................................27
“Operand.h” ........................................................................................................................................27
“Operation.h” ......................................................................................................................................28
“Plus.h” ................................................................................................................................................29
“RPN.h”................................................................................................................................................29
“Step.h” ...............................................................................................................................................32
“Tables.h” ............................................................................................................................................33
“Umnogenie.h”....................................................................................................................................35
“User_Operation.h” ............................................................................................................................35
“Var.h” .................................................................................................................................................36
Файлы с исходным кодом(cpp) ............................................................................................................36
“Avtomat.cpp”.....................................................................................................................................36
“Close.cpp” ..........................................................................................................................................36
“Const.cpp” .........................................................................................................................................36
“Delenie.cpp” ......................................................................................................................................36
“Ellement.cpp” ....................................................................................................................................36
“Ellement_Priority.cpp” ......................................................................................................................37
“Excpt_ParAmount.cpp” .....................................................................................................................37
“Factorial.cpp”.....................................................................................................................................37
“HashTable.cpp”..................................................................................................................................37
“main.cpp” ..........................................................................................................................................37
“Minus.cpp” ........................................................................................................................................38
“Open.cpp” ..........................................................................................................................................38
“Operand.cpp” ....................................................................................................................................38
“Operation.cpp” ..................................................................................................................................38
“Plus.cpp” ............................................................................................................................................39
“RPN.cpp” ............................................................................................................................................39
“Step.cpp” ...........................................................................................................................................39
“Tables.cpp” ........................................................................................................................................39
3
“Umnogenie.cpp” ................................................................................................................................39
“User_Operation.cpp”.........................................................................................................................39
“Var.cpp” .............................................................................................................................................39
Выдержки из теории
Обратная польская нотация
Форма записи математических выражений, в которой операнды расположены перед знаками
операций называется обратной польской записью.
Обратная польская запись обладает рядом замечательных свойств, которые превращают ее в
идеальный промежуточный язык при трансляции. Во-первых, вычисление выражения,
записанного в обратной польской записи, может проводиться путем однократного просмотра,
что является весьма удобным при генерации объектного кода программ.
Во-вторых, получение обратной польской записи из исходного выражения
осуществляться весьма просто на основе алгоритма, предложенного Дейкстрой.
может
Для реализации алгоритма Дейкстры вводится понятие – приоритет операции, который совпадает
с реальными приоритетами операций. Сам алгоритм выглядит так:
1. Если стек пуст, то операция из входной строки переписывается в стек;
2. Операция выталкивает из стека все операции с большим или равным приоритетом в
выходную строку;
3. Если очередной символ из исходной строки есть открывающая скобка,
то он
проталкивается в стек;
4. Закрывающая скобка выталкивает все операции из стека до ближайшей открывающей
скобки, сами скобки в выходную строку не переписываются, а уничтожают друг друга.
Вычисление выражения, записанного обратной
использованием стека по следующему алгоритму:
польской
записью,
производиться
с
1. Обработка входного символа
a. Если на вход подан операнд, он помещается на вершину стека.
b. Если на вход подан знак операции, то соответствующая операция выполняется над
требуемым количеством значений, извлечённых из стека, взятых в порядке
добавления. Результат выполненной операции кладётся на вершину стека.
2. Если входной набор символов обработан не полностью, перейти к шагу 1.
3. После полной обработки входного набора символов результат вычисления выражения лежит
на вершине стека.
Конечный автомат
Конечный автомат — в теории алгоритмов математическая абстракция, позволяющая описывать
пути изменения состояния объекта в зависимости от его текущего состояния и входных данных,
4
при условии, что общее возможное количество состояний конечно. Конечный автомат является
частным случаем абстрактного автомата.
Детерминированным конечным автоматом (ДКА) называется такой автомат, в котором для
каждой последовательности входных символов существует лишь одно состояние, в которое
автомат может перейти из текущего.
Как правило, задается пятеркой:
1.
2.
3.
4.
5.
Конечным множеством состояний автомата;
Начальным состоянием автомата;
Множеством заключительных состояний;
Допустимым входным алфавитом;
Функцией перехода автомата;
Автомат начинает работу в начальном состоянии, считывая по одному символу входной строки.
Считанный символ переводит автомат в новое состояние из Q в соответствии с функцией
переходов. Если по завершении считывания входного слова (цепочки символов) автомат
оказывается в одном из допускающих состояний, то слово «принимается» автоматом. В этом
случае говорят, что оно принадлежит языку данного автомата. В противном случае слово
«отвергается».
Способы реализации:
1. Диаграмма состояний (или иногда граф переходов) — графическое представление
множества состояний и функции переходов. Представляет собой нагруженный
однонаправленный граф, вершины которого — состояния КА, дуги — переходы из одного
состояния в другое, а нагрузка — символы, при которых осуществляется данный переход.
Если переход из состояния q1 в q2 может быть осуществлен при появлении одного из
нескольких символов, то над дугой должны быть надписаны все они.
2. Таблица переходов — табличное представление функции переходов. Обычно в такой
таблице каждой строке соответствует одно состояние, а столбцу — один допустимый
входной символ. В ячейке на пересечении строки и столбца записывается действие, которое
должен выполнить автомат, в ситуации, когда он находился в данном состоянии и на входе
получил данный символ.
Таблица с использованием хэш – функций
Хеш-табли́ ца — это структура данных, реализующая интерфейс ассоциативного массива, а
именно, она позволяет хранить пары (ключ, значение) и выполнять три операции: операцию
добавления новой пары, операцию поиска и операцию удаления пары по ключу.
Существует два основных варианта хеш-таблиц: с цепочками и открытой адресацией. Хештаблица содержит некоторый массив H, элементы которого есть пары (хеш-таблица с открытой
адресацией) или списки пар (хеш-таблица с цепочками).
Выполнение операции в хеш-таблице начинается с вычисления хеш-функции от ключа.
Получающееся хеш-значение i = hash(key) играет роль индекса в массиве H. Затем выполняемая
операция (добавление, удаление или поиск) перенаправляется объекту, который хранится в
соответствующей ячейке массива H[i].
5
Ситуация, когда для различных ключей получается одно и то же хеш-значение, называется
коллизией..
В некоторых специальных случаях удаётся избежать коллизий вообще. Например, если все ключи
элементов известны заранее (или очень редко меняются), то для них можно найти некоторую
cовершенную хеш-функцию, которая распределит их по ячейкам хеш-таблицы без коллизий. Хештаблицы, использующие подобные хеш-функции, не нуждаются в механизме разрешения
коллизий, и называются хеш-таблицами с прямой адресацией.
Число хранимых элементов, делённое на размер массива H (число возможных значений хешфункции), называется коэффициентом заполнения хеш-таблицы (load factor) и является важным
параметром, от которого зависит среднее время выполнения операций.
Важное свойство хеш-таблиц состоит в том, что при некоторых разумных допущениях, все три
операции (поиск, вставка, удаление элементов) в среднем выполняются за время O(1). Но при
этом не гарантируется, что время выполнения отдельной операции мало. Это связано с тем, что
при достижении некоторого значения коэффициента заполнения необходимо осуществлять
перестройку индекса хеш-таблицы: увеличить значение размера массива H и заново добавить в
пустую хеш-таблицу все пары.
Разрешение коллизий
Метод цепочек
Каждая ячейка массива H является указателем на связный список (цепочку) пар ключ-значение,
соответствующих одному и тому же хеш-значению ключа. Коллизии просто приводят к тому, что
появляются цепочки длиной более одного элемента.
Операции поиска или удаления элемента требуют просмотра всех элементов соответствующей
ему цепочки, чтобы найти в ней элемент с заданным ключом. Для добавления элемента нужно
добавить элемент в конец или начало соответствующего списка, и, в случае если коэффициент
заполнения станет слишком велик, увеличить размер массива H и перестроить таблицу.
При предположении, что каждый элемент может попасть в любую позицию таблицы H с равной
вероятностью и независимо от того, куда попал любой другой элемент, среднее время работы
операции поиска элемента составляет Θ(1 + α), где α — коэффициент заполнения таблицы.
Открытая адресация
В массиве H хранятся сами пары ключ-значение. Алгоритм вставки элемента проверяет ячейки
массива H в некотором порядке до тех пор, пока не будет найдена первая свободная ячейка, в
которую и будет записан новый элемент. Этот порядок вычисляется на лету, что позволяет
сэкономить на памяти для указателей, требующихся в хеш-таблицах с цепочками.
Последовательность, в которой просматриваются ячейки хеш-таблицы, называется
последовательностью проб. В общем случае, она зависит только от ключа элемента, то есть это
последовательность h0(x), h1(x), …, hn — 1(x), где x — ключ элемента, а hi(x) — произвольные
функции, сопоставляющие каждому ключу ячейку в хеш-таблице. Первый элемент в
последовательности, как правило, равен значению некоторой хеш-функции от ключа, а остальные
считаются от него одним из приведённых ниже способов. Для успешной работы алгоритмов
6
поиска, последовательность проб должна быть такой, чтобы все ячейки хеш-таблицы оказались
просмотренными ровно по одному разу.
Алгоритм поиска просматривает ячейки хеш-таблицы в том же самом порядке, что и при вставке,
до тех пор, пока не найдется либо элемент с искомым ключом, либо свободная ячейка (что
означает отсутствие элемента в хеш-таблице).
Удаление элементов в такой схеме несколько затруднено. Обычно поступают так: заводят
булевый флаг для каждой ячейки, помечающий, удален ли элемент в ней или нет. Тогда удаление
элемента состоит в установке этого флага для соответствующей ячейки хеш-таблицы, но при этом
необходимо модифицировать процедуру поиска существующего элемента так, чтобы она считала
удалённые ячейки занятыми, а процедуру добавления — чтобы она их считала свободными и
сбрасывала значение флага при добавлении.
Сведения о программе
О пути данных сквозь строки кода
С помощью стандартной консоли ввода/вывода пользователю предлагается ввести строку
выражения для вычисления.
Строка данных тут же поступает в детерминированный конечный автомат, который удаляет из неё
знаки форматирования, проверяет синтаксис, добавляет переменные в таблицу, если это
требуется, а так же возвращает на выходе своей работы массив из строк – имен переменных и
операций.
На основе массива строк уже непосредственно конструируется объект класса обратной польской
записи, который сохраняет в себе массив, а так же на его основе строится такой же массив строк,
но записанный уже в последовательности, соответствующей обратной польской записи. На
данном этапе проверяется баланс скобок.
Далее объект класса RPN переходит к вычислению полученного выражения, взаимодействуя с
таблицей переменных, а так же запрашивая значения неинициализированных переменных у
пользователя, получает ответ. На данном этапе фильтруются остальные синтаксические ошибки.
О конечном автомате
Конечный автомат различает пять групп различных символов на входе:
1.
2.
3.
4.
Буквы и символ подчеркивания
Цифры
. и , - символы, разделяющие дробную константу
+-*/()[]{}!^%#@$<> - символы, которые могут выступать в качестве скобок, либо операций разделители
5. Различные символы форматирования
Реализован в программе в статическом класса Avtomat по средством таблицы переходов.
Генерирует исключение SyntaxError при попадании в 11 состояние.
Синтаксически правильным считается идентификатор, начинающийся с буквы, либо символа
подчеркивания и состоящий из буков, символов подчеркивания и цифр.
7
Синтаксически правильным считается разделитель, состоящий из любого символа из +*/()[]{}!^%#@$<>, разделитель всегда состоит из одного символа. Как следствие, привычные
формы записи инкремента и декремента: ++ и - - в данном автомате невозможны.
Синтаксически правильной константой считается строка, состоящая из цифр, которая в одном
месте может быть разделена запятой, либо точкой.
Таблица переходов:
Входной 1
символ Буквы и _
Состояние
0
Начальное
состояние
1
Накапливание
идентификатора
2
Идентификатор
3
Накапливание
целой константы
4
Целая константа
5
Накапливание
дробной
константы
6
Дробная
константа
7
Накапливание
разделителя,
не используется
8
Разделитель
9
Накапливание
знаков
форматирования
2
Цифры
3
.и,
4
Разделители
5
Символы
формат-ия
1
3
5
7
9
1
1
11
2
2
1
3
5
7
9
11
3
5
4
4
1
3
5
7
9
11
5
11
6
6
1
3
5
7
9
8
8
8
8
8
1
3
5
7
9
10
10
10
10
9
8
10
Строка
форматирования
11
Синтаксическая
ошибка
1
3
5
7
9
1
3
5
7
9
О хэш-таблицах
Хэш-таблицы в программе используются для хранения операций и операндов.
Коллизии разрешаются по средствам цепочек, в качестве хэш-функции используется алгоритм
вычисления контрольной суммы CRC-32-IEEE 802.3, основанный на полиноме:
x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
Для ускорения вычислений хэш-функции используется алгоритм, основанный на табличном
расчете.
О классах
В программе активно используются классы. Практически все классы программы являются
шаблонными и зависят от типа используемых операндов и типа составных элементов строки.
Класс Tables
Класс содержит лишь статические данные и методы и является абстрактным. Служит таблицами
для классов Avtomat и RPN.
Данный класс содержит две статические таблицы:


HashTableEllPri – содержит операции и скобки
HashTableOprs – содержит переменные и константы
Ряд статических, защищенных методов (чтобы обеспечить доступ к ним, лишь из классов Avtomat
и RPN):







AddOperand – добавляет значение в таблицу переменных и констант, так же по указателю
IsInOperation – проверят наличие операции в таблице по имени, возвращает 1, если
данная операция есть в таблице
GetPriority – возвращает значение приоритета операции по имени
IsInit – возвращает 1,еслиоперанд с данным именем, уже инициализирован, иначе 0
GetValue – запрашивает значение операнда по его имени
SetTo – просит установить значение данного операнда пользователем и возвращает
заданной значение
GetPointer – возвращает указатель на операцию по имени для использования в стеке
операций при формировании обратной польской записи
А так же один статически, публичный метод:

AddOperator - добавляет значение в таблицу операций и скобок по указателю на элемент
9
Класс Avtomat
Класс содержит лишь статические данные и методы и является абстрактным. Служит, как
преобразователь входной строки в формат понятный классу RPN. Является потомком класса Table.
Содержит статический массив:

Nav[12][5] – хранит в себе таблицу переходов
Ряд статических приватных методов:






IsKey – возвращает 1, если символ – буква, либо знак подчеркивания
IsNum – возвращает 1,если символ – цифра
IsSep – возвращает 1,если символ – знак разделителя
IsDot – возвращает 1,если символ – точка, либо запятая
IsFormat – возвращает 1,если символ – знак форматирования
IsSmh – возвращает 1, если входной символ – буква, 2 – цифра,3 – точка, либо запятая, 4 –
знак разделителя, 5 – знак форматирования, иначе генерирует исключение о
синтаксической ошибке
И один статический публичный метод:

Convert – принимает на входе строку символов и возвращает на выходе массив, понятный
классу RPN, так же дополняет таблицу операндов
Класс RPN
Является классом, реализующим обратную польскую запись. Хранит в себе входную строку и
строку в обратной польской записи, а так же позволяет вычислять выражение, с использованием
пользовательского ввода, или на основе входного массива операндов. Наследуется от класса
Table.
Конструируется на основе массива строк, который формируется классом Avtomat.
Два приватных поля данных:


In – входной массив
Expr – выражение в форме обратной польской записи
Две публичные функции:


Execute – вычисляет выражение на основе таблицы переменных и констант, запрашивая
при необходимости у пользователя, значения неинициализированных переменных,
возвращает результат вычисления
Execute – вычисляет выражение на основе входного массива операндов, так же
возвращает результат вычисления
В процессе конструирования объекта, возможно генерирования исключения о неверном балансе
скобок. А в процессе вычисления возможны исключения, связанные с неверными операндами в
операциях.
10
Класс HashTableOprs
Является классом, реализующим хэш-таблицу переменных и констант. Поддерживает операции
добавления и поиска по таблице, так же может возвращать значение элемента, проверять степень
его инициализации и запрашивать у пользователя значение переменной.
Содержит два приватных поля данных:
 Data – двумерный массив, хранящий указатели на операнды
 CRC32_Table[256] – массив, необходимый для ускорения вычисления хэш-функции
Так же, содержит приватную функцию:

GetHash – получает входную строку и возвращает значение хэш-функции ля неё
Содержит ряд публичных методов:





Add – добавляет операнд по указателю на него
IsIn – получает на входе имя операнда и возвращает 1, если находит операнд в таблице
IsInit – получает на входе имя операнда и возвращает 1, если данный операнд существует в
таблице и инициализирован
SetTo – получает на входе имя операнда и запрашивает у пользователя значение данного
операнда, которое в последствие, возвращает
GetValue – запрашивает значение операнда по его имени, возвращает его, либо
генерирует исключение NotFound,если операнд отсутствует в таблице
Класс HashTableEllPri
Является классом, реализующим хэш-таблицу операций. Поддерживает операции добавления и
поиска по таблице, так же может возвращать приоритет операции и указатель на операцию.
Содержит два приватных поля данных:
 Data – двумерный массив, хранящий указатели на операнды
 CRC32_Table[256] – массив, необходимый для ускорения вычисления хэш-функции
Так же, содержит приватную функцию:

GetHash – получает входную строку и возвращает значение хэш-функции ля неё
Содержит ряд публичных методов:




Add – добавляет операцию по указателю на неё
IsIn – получает на входе указатель на операцию и возвращает 1, если находит операнд в
таблице
GetPriority – возвращает приоритет операции по её имени
GetPointer – возвращает указатель на операцию по её имени
Класс Ellement
Является базовым классом для всех элементов входного массива в RPN. Содержит поле имя
элемента и поддерживает функции сравнения двух элементов и возвращение имени.
Конструируется по имени.
11
Приватное поле данных:

Name – содержит имя элемента
Публичные методы:



RetName – метод возвращает имя элемента
Перегруженный оператор == - может сравнивать элемент с строкой и другим элементов
Перегруженный оператор<< - позволяет выводить элемент в стандартный поток
ввода/вывода
Класс Ellement_Priority
Является производным абстрактным классом от класса Ellement, дополняя его понятием
приоритета операции.
Приватные поля:


Priority – приоритет операции
Max_priority – статическое поле, хранящее максимальный возможный приоритет при
превышении, которого будет сгенерировано исключение о неверном приоритете
операции
Публичные методы:
 RetPriority – возвращает значение приоритета операции
 SetMaxPriority - статический метод, устанавливающий максимальное значение приоритета
Классы Open и Close
Являются производными классами от класса Ellement_Priority, реализуя скобки.
Конструируются по имени скобки.
Класc Operation
Является производным от класса Ellement_Priority и дополняет его понятием арности операции.
Приватные поля:


n_nary – значение арности данной операции
max_n_nary – статическое поле, содержит максимальное значение арности операции, при
превышении, которого будет сгенерировано исключение о неверной арности операции
Публичные методы:


RetN_nary – возвращает значение арности операции
SetMax_n_nary – статический метод, устанавливает значение максимальной арности
Классы Delenie,Factorial,Minus,Plus,Step,Umnogenie
Являются производными классами от Operation. Реализуют стандартный набор операций.
Конструируются по имени.
Содержат публичный метод:
12

Execute – принимает массив операндов и вычисляет на его основе - значение операции,
может генерировать исключение о неверном кол-ве операндов и исключения, связанные с
неверными операндами ( деление на ноль и прочие)
Класс User_Operation
Является производным классом от Operation. Реализует возможность пользователем создавать
новые операции на основе уже имеющихся.
Конструируется по польской записи, соответствующей выражению операции, приоритету
операции, арности операции и имени новой операции.
Приватное поле:

Expr – объект класса RPN
Публичный метод:

Execute – принимает массив операндов и вычисляет его на основе – значение операции,
которое возвращает.
Класс Operand
Является производным, абстрактным классом от Ellement. Реализует операнды. Добавляет
понятие инициализации элементу.
Содержит поле:

Init – характеризующее инициализирован ли операнд
А так же ряд публичных методов:


RetInit – возвращает 1, если элемент инициализирован, иначе 0
Init – инициализирует элемент
Класс Var
Является производным классом от класса Operand. Реализует переменные.
Конструируется по имени переменной.
Содержит поле:

Now – текущее значение переменной
Публичные методы:



SetTo – присваивает переменной значение, передаваемое в качестве параметра
RetNow – возвращает текущее значение переменной
SetToByUser – запрашивает значение переменной у пользователя и возвращает его
Класс Const
Является производным классом от класса Operand. Реализует поддержку констант.
Конструируется по имени константы и её значению.
13
Содержит поле:

Now – значение константы
Публичные методы:


RetNow – возвращает текущее значение переменной
SetToByUser – возвращает значение константы
Листинг
Заголовочные файлы
“AllRPN.h”
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
"Minus.h"
"Plus.h"
"Umnogenie.h"
"Delenie.h"
"Step.h"
"Factorial.h"
"Open.h"
"Close.h"
"Var.h"
"Const.h"
"HashTable.h"
"User_Operation.h"
"RPN.h"
"Tables.h"
"Avtomat.h"
#ifdef _UNICODE
#define _tcout wcout
#define _tcin wcin
#define _tifstream wifstream
#define _tofstream wofstream
#else
#define _tcout cout
#define _tcin cin
#define _tifstream ifstream
#define _tofstream ofstream
#endif
“Avtomat.h”
//!!
#pragma once
#include <vector>
#include "Tables.h"
#include <tchar.h>
#include "Var.h"
#include "Const.h"
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверной входной строке на входе автомата.
Может выводить информацию в стандартный поток I/O
14
-------------------------------------------------------------------------*/
using namespace std;
template<class ElPartType>
class SyntaxError{
std::basic_string<ElPartType> Data;
public:
SyntaxError(const std::basic_string<ElPartType>&);
friend std::ostream& operator<< <>(std::ostream&,const SyntaxError&);
};
template<class ElPartType>
SyntaxError<ElPartType>::SyntaxError(const std::basic_string<ElPartType>& _Data){
Data = _Data;
}
template<class ElPartType>
std::ostream& operator<<(std::ostream& Out,const SyntaxError<ElPartType>& _T){
Out << "Error: Input string has syntax error in ";
for (unsigned int i =0 ;i<_T.Data.size();i++)
Out << (char)_T.Data[i];
Out << std::endl;
return Out;
}
/*----------------------------------------------------------------------Класс простейшего конечно автомата, который будет разбирать входную строку на
элементы, дополняя таблицу операндов.
Класс является абстрактным и содержит лишь статические функции и поля данных.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Avtomat:public Tables<OperandType,ElPartType>
{
static bool IsKey(ElPartType);
символ подчеркивания
1
static bool IsNum(ElPartType);
//буква, либо
//цифра
2
static bool IsDot(ElPartType);
//точка, либо
запятая
3
static bool IsSep(ElPartType);
//составляющие
части операторов +-!*/#^| 4
static bool IsFormat(ElPartType);
//знаки
форматирования \t \r \n пробел
5
static unsigned int IsSmh(ElPartType);
//возвращает номер
static unsigned int Nav[12][5];
//массив
отвечающий за навигацию по графу
public:
static std::vector<std::basic_string<ElPartType>> Convert(const
std::basic_string<ElPartType>&);
virtual ~Avtomat(void)=0;
};
//массив переходов для графа автомата
template<class OperandType,class ElPartType>
unsigned int Avtomat<OperandType,ElPartType>::Nav[12][5]={
{1,
3,
5,
7,
9},
{1,
1,
11,
2,
2},
{1,
3,
5,
7,
9},
{11,3, 5,
4,
4},
{1,
3,
5,
7,
9},
{11,5, 11,
6,
6},
{1,
3,
5,
7,
9},
15
{8,
8,
{1,
3,
{10,10,
{1,
3,
{1,
3,
8,
5,
10,
5,
5,
8,
7,
10,
7,
7,
8},
9},
9},
9},
9}
};
template<class OperandType,class ElPartType>
std::vector<std::basic_string<ElPartType>> Avtomat<OperandType,ElPartType>::Convert
(const std::basic_string<ElPartType>& _In1)
{
int CurPos = 0;
std::basic_string<ElPartType> _In = _In1;
_In.push_back(' ');
std::vector<std::basic_string<ElPartType>> Out;
std::basic_string<ElPartType> tmp;
for (unsigned int i = 0; i< _In.size();i++){
//начинаем просматривать входной массив и получаем тип текущего символа
unsigned int type = IsSmh(_In[i]);
//совершаем переход по графу
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
switch(CurPos){
//проверяем не достигли ли мы конечного состояния
case 2:
//конечное
состояние - идентификатор
if (!Tables<OperandType,ElPartType>::IsInOperation(tmp)){
Var<OperandType,ElPartType> *tmpVar = new
Var<OperandType,ElPartType>(tmp);
Tables<OperandType,ElPartType>::AddOperand(tmpVar);
}
Out.push_back(tmp);
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
tmp.clear();
break;
case 4:
//конечное
состояние - целая константа
{
Const<OperandType,ElPartType> *tmpConst = new
Const<OperandType,ElPartType>(tmp,(OperandType)_ttoi(tmp.c_str()));
Tables<OperandType,ElPartType>::AddOperand(tmpConst);
}
Out.push_back(tmp);
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
tmp.clear();
break;
case 6:
//конечное
состояние - дробная константа
{
Const<OperandType,ElPartType> *tmpConst = new
Const<OperandType,ElPartType>(tmp,(OperandType)_tstof(tmp.c_str()));
Tables<OperandType,ElPartType>::AddOperand(tmpConst);
}
Out.push_back(tmp);
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
tmp.clear();
break;
case 8:
//конечное состояние - разделитель,сверяемся есть ли такая операция
if (!Tables<OperandType,ElPartType>::IsInOperation(tmp)){
//в случае если разделитель не найден в таблице операторов,
генерируем исключаение
throw SyntaxError<ElPartType>(tmp);
}
//заносим в выходной массив и совершаем переход по текущему символу
16
Out.push_back(tmp);
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
tmp.clear();
break;
case 10:
//конечное состояние - знак форматирования, просто удаляем
tmp.clear();
CurPos = Avtomat<OperandType,ElPartType>::Nav[CurPos][type-1];
break;
case 11:
//конечное состояние - синтаксическая ошибка, генерируем исключение
throw SyntaxError<ElPartType>(tmp);
tmp.clear();
break;
}
tmp.push_back(_In[i]);
}
return Out;
}
template<class OperandType,class ElPartType>
unsigned int Avtomat<OperandType,ElPartType>::IsSmh(ElPartType ch){
//сверяем входной эл-т со всеми возможными, если не находим его , тогда генерируем
исключение
if (IsKey(ch))
return 1;
if (IsNum(ch))
return 2;
if (IsDot(ch))
return 3;
if (IsSep(ch))
return 4;
if (IsFormat(ch))
return 5;
std::basic_string<ElPartType> tmp;
tmp.push_back(ch);
throw SyntaxError<ElPartType>(tmp);
}
template<class Operand,class ElPartType>
bool Avtomat<Operand,ElPartType>::IsKey(ElPartType ch){
std::basic_string<ElPartType> tmp =
_T("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_");
if (tmp.find_first_of(ch)!=std::string::npos)
return 1;
else
return 0;
}
template<class Operand,class ElPartType>
bool Avtomat<Operand,ElPartType>::IsNum(ElPartType ch){
std::basic_string<ElPartType> tmp = _T("1234567890");
if (tmp.find_first_of(ch)!=std::string::npos)
return 1;
else
return 0;
}
template<class Operand,class ElPartType>
bool Avtomat<Operand,ElPartType>::IsDot(ElPartType ch){
std::basic_string<ElPartType> tmp = _T(".,");
if (tmp.find_first_of(ch)!=std::string::npos)
return 1;
else
17
return 0;
}
template<class Operand,class ElPartType>
bool Avtomat<Operand,ElPartType>::IsSep(ElPartType ch){
std::basic_string<ElPartType> tmp = _T("+-*/()[]{}!^%#@$<>");
if (tmp.find_first_of(ch)!=std::string::npos)
return 1;
else
return 0;
}
template<class Operand,class ElPartType>
bool Avtomat<Operand,ElPartType>::IsFormat(ElPartType ch){
std::basic_string<ElPartType> tmp = _T(" \n\r\t");
if (tmp.find_first_of(ch)!=std::string::npos)
return 1;
else
return 0;
}
template<class OperandType,class ElPartType>
Avtomat<OperandType,ElPartType>::~Avtomat(void){}
“Close.h”
//!!
#pragma once
#include "Ellement_Priority.h"
/*----------------------------------------------------------------------Класс закрывающий скобки, конструируется по имени.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Close:public Ellement_Priority<OperandType,ElPartType>
{
public:
Close(const std::basic_string<ElPartType>&);
};
template<class OperandType,class ElPartType>
Close<OperandType,ElPartType>::Close(const std::basic_string<ElPartType>& _Name)
:Ellement_Priority<OperandType,ElPartType>(_Name,1){};
“Const.h”
//!!
#pragma once
#include "Operand.h"
/*----------------------------------------------------------------------Класс константы.
Конструируется по имени и значению. Не может быть изменена. Считается
инициализированной.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Const:public Operand<OperandType,ElPartType>
{
OperandType Now;
public:
Const(const std::basic_string<ElPartType>&,OperandType);
OperandType RetNow()const{return Now;}
OperandType SetToByUser(){return Now;}
18
~Const(void){};
};
template<class OperandType,class ElPartType>
Const<OperandType,ElPartType>::Const(const std::basic_string<ElPartType>&
_Name,OperandType _Now):
Operand<OperandType,ElPartType>(_Name,1){
Now = _Now;
}
“Delenie.h”
//!!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
/*----------------------------------------------------------------------Исключение.
Сигнализирует о попытке деления на ноль.
Способен выводить сообщение об ошибке в стандартный поток вывода
-------------------------------------------------------------------------*/
class EDivisionByZero{
public:
EDivisionByZero(){};
void ConsoleErrorPrint();
friend std::ostream& operator<< (std::ostream&,const EDivisionByZero&);
};
/*----------------------------------------------------------------------Класс - операция деления. Конструируется по имени. Выполняется по массиву
операндов
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Delenie:public Operation<OperandType,ElPartType>
{
public:
Delenie(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Delenie<OperandType,ElPartType>::Delenie(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,3,2){};
template<class OperandType,class ElPartType>
OperandType Delenie<OperandType,ElPartType>::Execute(const std::vector<OperandType>& In)
const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
if (In[0])
return In[1]/In[0];
else
throw EDivisionByZero();
}
“Ellement.h”
//!!
#pragma once
#include <vector>
#include <iostream>
/*----------------------------------------------------------------------Базовый класс для всех элементов строки, содержит лишь название элемента.
19
Конструируется по имени эл-та.
Может возвращать имя эл-та, быть сравнен со строкой и другим элементом и
выведен в поток.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Ellement
{
private:
std::basic_string<ElPartType> Name;
public:
Ellement(const std::basic_string<ElPartType>&);
std::basic_string<ElPartType> RetName() const;
bool operator==(const std::basic_string<ElPartType>&)const;
bool operator==(const Ellement&)const;
friend std::ostream& std::operator<< <>(std::ostream&,const Ellement&);
};
template<class OperandType,class ElPartType>
std::ostream& operator<<(std::ostream &out,const Ellement<OperandType,ElPartType> &T){
for (unsigned int i=0;i<T.Name.size();i++)
out << T.Name[i];
out << std::endl;
return out;
}
template<class OperandType,class ElPartType>
Ellement<OperandType,ElPartType>::Ellement(const std::basic_string<ElPartType>& _Name){
if (_Name.size())
Name = _Name;
}
template<class OperandType,class ElPartType>
std::basic_string<ElPartType> Ellement<OperandType,ElPartType>::RetName() const{
return Name;
}
template<class OperandType,class ElPartType>
bool Ellement<OperandType,ElPartType>::operator==(const std::basic_string<ElPartType>
&_In)const{
if (Name.compare(_In))
return 0;
else
return 1;
}
template<class OperandType,class ElPartType>
bool Ellement<OperandType,ElPartType>::operator==(const Ellement<OperandType,ElPartType>
&_In)const{
if (Name.compare(_In.Name))
return 0;
else
return 1;
}
“Ellement_Priority.h”
//!
#pragma once
#include "Ellement.h"
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверном значении приоритета операции.
Функция ConsoleErrorPrint() выводит в консоль сообщение о неверном приоритете
20
с его значением.
-------------------------------------------------------------------------*/
class Ipriority{
private:
int n;
public:
Ipriority(int _n){n=_n;}
void ConsoleErrorPrint();
friend std::ostream& operator<<(std::ostream&,const Ipriority&);
};
/*----------------------------------------------------------------------Промежуточный,абстрактный класс.
Добавляет к базовому классу - Ellement понятие приоритета операции.
В статическом элементе хранит максимальный приоритет, который может быть изменен.
Конструируется по имени эл-та и его приоритету.
Добавляет функцию, возвращающую значение приоритета операции.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Ellement_Priority:public Ellement<OperandType,ElPartType>
{
unsigned int Priority;
static unsigned int max_priority;
public:
Ellement_Priority(const std::basic_string<ElPartType>&,unsigned int);
unsigned int RetPriority() const{return Priority;}
virtual ~Ellement_Priority(void)=0;
static void SetMaxPriority(int n){max_priority = n;}
};
template<class OperandType,class ElPartType>
unsigned int Ellement_Priority<OperandType,ElPartType>::max_priority=100;
template<class OperandType,class ElPartType>
Ellement_Priority<OperandType,ElPartType>::Ellement_Priority(const
std::basic_string<ElPartType>& _Name,
unsigned int _Priority):Ellement(_Name)
{
Priority = _Priority;
}
template<class OperandType,class ElPartType>
Ellement_Priority<OperandType,ElPartType>::~Ellement_Priority(){};
“Excpt_ParAmount.h”
//!
#pragma once
#include <iostream>
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверном кол-ве операндов переданных в выражение.
При ошибке, может выводить реальное и необходимое кол-во операндов.
Возникать не должно :)))
-------------------------------------------------------------------------*/
class Excpt_ParAmount
{
private:
int Need;
int Here;
21
public:
Excpt_ParAmount(int _Need,int _Here){Need = _Need;Here = _Here;}
void ConsoleErrorPrint();
friend std::ostream& operator<<(std::ostream&,const Excpt_ParAmount&);
~Excpt_ParAmount(void){};
};
“Factorial.h”
//!!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверном операнде в факториале
-------------------------------------------------------------------------*/
using namespace std;
template<class OperandType>
class IFact{
OperandType a;
public:
IFact(OperandType _a){a=_a;}
void ConsoleErrorPrint();
friend std::ostream& operator<< <>(std::ostream&,const IFact&);
};
template<class OperandType>
std::ostream& operator<<(std::ostream& Out,const IFact<OperandType>& T){
std::cout << "Error: fact = " << T.a << " is incorrect. Must be positive" <<
std::endl;
return Out;
}
template<class OperandType>
void IFact<OperandType>::ConsoleErrorPrint(){
std::cout << "Error: fact = " << a << " is incorrect. Must be positive" <<
std::endl;
}
/*----------------------------------------------------------------------Класс. Операция факториал.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Factorial:public Operation<OperandType,ElPartType>
{
public:
Factorial(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Factorial<OperandType,ElPartType>::Factorial(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,4,1){};
template<class OperandType,class ElPartType>
OperandType Factorial<OperandType,ElPartType>::Execute(const std::vector<OperandType>&
In) const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
if (In[0]<0)
throw IFact<OperandType>(In[0]);
22
else{
OperandType Res=In[0];
OperandType Umn=In[0]-1;
for (int i=1;i<In[0];i++){
Res*=Umn;
Umn--;
}
return Res;
}
}
“HashTable.h”
#pragma once
#include "Operand.h"
#include "Ellement_Priority.h"
#include "Ellement.h"
class NotFound{
public:
NotFound(){};
friend std::ostream& operator<< (std::ostream&,const NotFound&);
};
template<class OperandType,class ElPartType>
class HashTableOprs
{
private:
std::vector<std::vector<Operand<OperandType,ElPartType>*>> Data;
unsigned int GetHash(const std::basic_string<ElPartType>&) const;
static unsigned int CRC32_table[256];
public:
HashTableOprs(void);
void Add(Operand<OperandType,ElPartType>*);
bool IsIn(const std::basic_string<ElPartType>&);
bool IsInit(const std::basic_string<ElPartType>&)const;
OperandType SetTo(const std::basic_string<ElPartType>&);
OperandType GetValue(const std::basic_string<ElPartType>&)const;
};
template<class OperandType,class ElPartType>
unsigned int HashTableOprs<OperandType,ElPartType>::CRC32_table[256]={
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
23
0x62DD1DDF,
0x4DB26158,
0x4ADFA541,
0x4369E96A,
0x44042D73,
0x5005713C,
0x5768B525,
0x5EDEF90E,
0x59B33D17,
0xEDB88320,
0xEAD54739,
0xE3630B12,
0xE40ECF0B,
0xF00F9344,
0xF762575D,
0xFED41B76,
0xF9B9DF6F,
0xD6D6A3E8,
0xD1BB67F1,
0xD80D2BDA,
0xDF60EFC3,
0xCB61B38C,
0xCC0C7795,
0xC5BA3BBE,
0xC2D7FFA7,
0x9B64C2B0,
0x9C0906A9,
0x95BF4A82,
0x92D28E9B,
0x86D3D2D4,
0x81BE16CD,
0x88085AE6,
0x8F659EFF,
0xA00AE278,
0xA7672661,
0xAED16A4A,
0xA9BCAE53,
0xBDBDF21C,
0xBAD03605,
0xB3667A2E,
0xB40BBE37,
0x15DA2D49,
0x3AB551CE,
0x3DD895D7,
0x346ED9FC,
0x33031DE5,
0x270241AA,
0x206F85B3,
0x29D9C998,
0x2EB40D81,
0x9ABFB3B6,
0x9DD277AF,
0x94643B84,
0x9309FF9D,
0x8708A3D2,
0x806567CB,
0x89D32BE0,
0x8EBEEFF9,
0xA1D1937E,
0xA6BC5767,
0xAF0A1B4C,
0xA867DF55,
0xBC66831A,
0xBB0B4703,
0xB2BD0B28,
0xB5D0CF31,
0xEC63F226,
0xEB0E363F,
0xE2B87A14,
0xE5D5BE0D,
0xF1D4E242,
0xF6B9265B,
0xFF0F6A70,
0xF862AE69,
0xD70DD2EE,
0xD06016F7,
0xD9D65ADC,
0xDEBB9EC5,
0xCABAC28A,
0xCDD70693,
0xC4614AB8,
0xC30C8EA1,
0x8CD37CF3,
0xA3BC0074,
0xA4D1C46D,
0xAD678846,
0xAA0A4C5F,
0xBE0B1010,
0xB966D409,
0xB0D09822,
0xB7BD5C3B,
0x03B6E20C,
0x04DB2615,
0x0D6D6A3E,
0x0A00AE27,
0x1E01F268,
0x196C3671,
0x10DA7A5A,
0x17B7BE43,
0x38D8C2C4,
0x3FB506DD,
0x36034AF6,
0x316E8EEF,
0x256FD2A0,
0x220216B9,
0x2BB45A92,
0x2CD99E8B,
0x756AA39C,
0x72076785,
0x7BB12BAE,
0x7CDCEFB7,
0x68DDB3F8,
0x6FB077E1,
0x66063BCA,
0x616BFFD3,
0x4E048354,
0x4969474D,
0x40DF0B66,
0x47B2CF7F,
0x53B39330,
0x54DE5729,
0x5D681B02,
0x5A05DF1B,
0xFBD44C65,
0xD4BB30E2,
0xD3D6F4FB,
0xDA60B8D0,
0xDD0D7CC9,
0xC90C2086,
0xCE61E49F,
0xC7D7A8B4,
0xC0BA6CAD,
0x74B1D29A,
0x73DC1683,
0x7A6A5AA8,
0x7D079EB1,
0x6906C2FE,
0x6E6B06E7,
0x67DD4ACC,
0x60B08ED5,
0x4FDFF252,
0x48B2364B,
0x41047A60,
0x4669BE79,
0x5268E236,
0x5505262F,
0x5CB36A04,
0x5BDEAE1D,
0x026D930A,
0x05005713,
0x0CB61B38,
0x0BDBDF21,
0x1FDA836E,
0x18B74777,
0x11010B5C,
0x166CCF45,
0x3903B3C2,
0x3E6E77DB,
0x37D83BF0,
0x30B5FFE9,
0x24B4A3A6,
0x23D967BF,
0x2A6F2B94,
0x2D02EF8D
};
template<class OperandType,class ElPartType>
unsigned int HashTableOprs<OperandType,ElPartType>::GetHash(const
std::basic_string<ElPartType>& _In) const{
unsigned int crc = 0xFFFFFFFF;
for (unsigned int i = 0 ;i<_In.size();i++)
crc = (crc >> 8) ^ CRC32_table[(crc ^ _In[i]) & 0xFF];
return (crc ^ 0xFFFFFFFF)%1009;
}
template<class OperandType,class ElPartType>
HashTableOprs<OperandType,ElPartType>::HashTableOprs(){
Data.resize(1009);
for (unsigned int i=0;i<1009;i++)
Data[i].reserve(15);
};
template<class OperandType,class ElPartType>
void HashTableOprs<OperandType,ElPartType>::Add(Operand<OperandType,ElPartType> *T){
unsigned int hash = GetHash(T->RetName());
Data[hash].push_back(T);
24
}
template<class OperandType,class ElPartType>
OperandType HashTableOprs<OperandType,ElPartType>::GetValue(const
std::basic_string<ElPartType>& _In)const{
unsigned int hash = GetHash(_In);
if (Data.at(hash).size()==1)
return Data[hash][0]->RetNow();
else
if (Data.at(hash).size()==0){
throw NotFound();
}else
for (unsigned int i = 0;Data[hash][i]&&i<Data[hash].size();i++){
if ((*Data[hash][i])==_In)
return Data[hash][i]->RetNow();
}
throw NotFound();
return (OperandType)0;
}
template<class OperandType,class ElPartType>
bool HashTableOprs<OperandType,ElPartType>::IsIn(const std::basic_string<ElPartType>& T){
unsigned int hash = GetHash(T);
for (unsigned int i=0;i<Data[hash].size();i++)
if (*Data[hash][i]==T)
return 1;
return 0;
}
template<class OperandType,class ElPartType>
bool HashTableOprs<OperandType,ElPartType>::IsInit(const std::basic_string<ElPartType>&
T)const{
unsigned int hash = GetHash(T);
for (unsigned int i=0;i<Data[hash].size();i++)
if (*Data[hash][i]==T)
return (Data[hash][i]->RetInit());
return 0;
}
template<class OperandType,class ElPartType>
OperandType HashTableOprs<OperandType,ElPartType>::SetTo(const
std::basic_string<ElPartType>& T){
unsigned int hash = GetHash(T);
for (unsigned int i=0;i<Data[hash].size();i++)
if (*Data[hash][i]==T)
return Data[hash][i]->SetToByUser();
return (OperandType)0;
}
/*----------------------------------------------------------------------Класс хэш таблицы элементов с приоритетом
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class HashTableEllPri
{
private:
std::vector<std::vector<Ellement_Priority<OperandType,ElPartType>*>> Data;
unsigned int GetHash(const std::basic_string<ElPartType>&) const;
static unsigned int CRC32_table[256];
public:
HashTableEllPri(void);
void Add(Ellement_Priority<OperandType,ElPartType>*);
unsigned int GetPriority(const std::basic_string<ElPartType>&);
25
Ellement_Priority<OperandType,ElPartType>* GetPointer(const
std::basic_string<ElPartType>&);
bool IsIn(const Ellement<OperandType,ElPartType>&);
};
template<class OperandType,class ElPartType>
unsigned int HashTableEllPri<OperandType,ElPartType>::CRC32_table[256]={
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
26
0xA7672661,
0xAED16A4A,
0xA9BCAE53,
0xBDBDF21C,
0xBAD03605,
0xB3667A2E,
0xB40BBE37,
0xD06016F7,
0xD9D65ADC,
0xDEBB9EC5,
0xCABAC28A,
0xCDD70693,
0xC4614AB8,
0xC30C8EA1,
0x4969474D,
0x40DF0B66,
0x47B2CF7F,
0x53B39330,
0x54DE5729,
0x5D681B02,
0x5A05DF1B,
0x3E6E77DB,
0x37D83BF0,
0x30B5FFE9,
0x24B4A3A6,
0x23D967BF,
0x2A6F2B94,
0x2D02EF8D
};
template<class OperandType,class ElPartType>
unsigned int HashTableEllPri<OperandType,ElPartType>::GetHash(const
std::basic_string<ElPartType>& _In) const{
unsigned int crc = 0xFFFFFFFF;
for (unsigned int i = 0 ;i<_In.size();i++)
crc = (crc >> 8) ^ CRC32_table[(crc ^ _In[i]) & 0xFF];
return (crc ^ 0xFFFFFFFF)%1009;
}
template<class OperandType,class ElPartType>
HashTableEllPri<OperandType,ElPartType>::HashTableEllPri(){
Data.resize(1009);
for (unsigned int i=0;i<1009;i++)
Data[i].reserve(15);
};
template<class OperandType,class ElPartType>
void
HashTableEllPri<OperandType,ElPartType>::Add(Ellement_Priority<OperandType,ElPartType>*
T){
unsigned int hash = GetHash(T->RetName());
Data[hash].push_back(T);
}
template<class OperandType,class ElPartType>
unsigned int HashTableEllPri<OperandType,ElPartType>::GetPriority(const
std::basic_string<ElPartType>& _In){
unsigned int hash = GetHash(_In);
if (Data.at(hash).size()==1)
return Data[hash][0]->RetPriority();
else
if (Data.at(hash).size()==0){
throw NotFound();
}else
for (unsigned int i = 0;Data[hash][i]&&i<Data[hash].size();i++){
if (*Data[hash][i]==_In)
return Data[hash][i]->RetPriority();
}
throw NotFound();
return 0;
}
template<class OperandType,class ElPartType>
bool HashTableEllPri<OperandType,ElPartType>::IsIn(const
Ellement<OperandType,ElPartType>& T){
unsigned int hash = GetHash(T.RetName());
for (unsigned int i=0;i<Data[hash].size();i++)
if (*Data[hash][i]==T)
return 1;
return 0;
}
template<class OperandType,class ElPartType>
27
Ellement_Priority<OperandType,ElPartType>*
HashTableEllPri<OperandType,ElPartType>::GetPointer(const std::basic_string<ElPartType>&
_In){
unsigned int hash = GetHash(_In);
if (Data.at(hash).size()==1)
return Data[hash][0];
else
for (unsigned int i = 0;Data[hash][i]&&i<Data[hash].size();i++)
if (*Data[hash][i]==_In)
return Data[hash][i];
throw NotFound();
return 0;
}
“Minus.h”
//!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
template<class OperandType,class ElPartType>
class Minus:public Operation<OperandType,ElPartType>
{
public:
Minus(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Minus<OperandType,ElPartType>::Minus(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,2,2){};
template<class OperandType,class ElPartType>
OperandType Minus<OperandType,ElPartType>::Execute(const std::vector<OperandType>& In)
const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
return In[1]-In[0];
}
“Open.h”
//!
#pragma once
#include "Ellement_Priority.h"
/*----------------------------------------------------------------------Класс открывающей скобки, конструируется по имени.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Open:public Ellement_Priority<OperandType,ElPartType>
{
public:
Open(const std::basic_string<ElPartType>&);
};
template<class OperandType,class ElPartType>
Open<OperandType,ElPartType>::Open(const std::basic_string<ElPartType>& _Name)
:Ellement_Priority<OperandType,ElPartType>(_Name,0){};
“Operand.h”
#pragma once
28
#include "Ellement.h"
template<class OperandType,class ElPartType>
class Operand:public Ellement<OperandType,ElPartType>
{
bool init;
public:
Operand(const std::basic_string<ElPartType>&,bool);
virtual OperandType RetNow()const =0;
virtual OperandType SetToByUser(){return 0;};
bool RetInit()const{return init;}
void Init(){init = 1;}
};
template<class OperandType,class ElPartType>
Operand<OperandType,ElPartType>::Operand(const std::basic_string<ElPartType>& _Name,bool
_init)
:Ellement(_Name)
{
init = _init;
}
“Operation.h”
//!
#pragma once
#include "Ellement_Priority.h"
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверном значении кол-ва операндов для операции
-------------------------------------------------------------------------*/
class In_nary{
private:
int n;
public:
In_nary(int _n){n=_n;}
void ConsoleErrorPrint();
friend std::ostream& operator<<(std::ostream&,const In_nary&);
};
/*----------------------------------------------------------------------Класс, вводящий понятие кол-ва операндов для операций
Хранит в статическом члене максимальное значение кол-ва операндов
Вводит чисто виртуальную функцию - Execute - которая вычисляет данную
операцию.
Объект данного класса конструируется по трем параметрам: имени, приоритету и
кол-ву операндов.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Operation:public Ellement_Priority<OperandType,ElPartType>
{
private:
unsigned int n_nary;
static unsigned int max_n_nary;
public:
Operation(const std::basic_string<ElPartType>&,unsigned int,unsigned int);
virtual OperandType Execute(const std::vector<OperandType>&) const =0;
unsigned int RetN_nary() const {return n_nary;}
static void SetMax_n_nary(int n){max_n_nary = n;}
};
template<class OperandType,class ElPartType>
29
unsigned int Operation<OperandType,ElPartType>::max_n_nary = 100;
template<class OperandType,class ElPartType>
Operation<OperandType,ElPartType>::Operation(const std::basic_string<ElPartType>& _Name,
unsigned int _Priority,unsigned int _n_nary)
:Ellement_Priority<OperandType,ElPartType>(_Name,_Priority)
{
if (_n_nary<=max_n_nary)
n_nary = _n_nary;
else
throw In_nary(_n_nary);
};
“Plus.h”
//!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
template<class OperandType,class ElPartType>
class Plus:public Operation<OperandType,ElPartType>
{
public:
Plus(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Plus<OperandType,ElPartType>::Plus(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,2,2){};
template<class OperandType,class ElPartType>
OperandType Plus<OperandType,ElPartType>::Execute(const std::vector<OperandType>& In)
const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
return In[0]+In[1];
}
“RPN.h”
//!
#pragma once
#include "Skobki.h"
#include "Operation.h"
#include "Operand.h"
#include "Var.h"
#include "Const.h"
#include "HashTable.h"
#include "Ellement_Priority.h"
#include "Tables.h"
#include "Avtomat.h"
#include <tchar.h>
/*----------------------------------------------------------------------Исключение.
Сигнализирует о неверной скобке
-------------------------------------------------------------------------*/
class IBreak{
public:
IBreak(){};
void ConsoleErrorPrint();
30
friend std::ostream& operator<<(std::ostream&,const IBreak&);
};
/*----------------------------------------------------------------------Класс польской записи
На вход получает массив строк - элементов.
Преобразует выражение в обратную польскую запись и может вычислить
результат, используя либо данные из таблицы переменных, либо последовательный
массив операндов
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class RPN:public Tables<OperandType,ElPartType>
{
private:
std::vector<std::basic_string<ElPartType>> In;
std::vector<std::basic_string<ElPartType>> Expr;
public:
RPN(const std::vector<std::basic_string<ElPartType>>&);
OperandType Execute()const;
OperandType Execute(const std::vector<OperandType>&)const;
};
template<class OperandType,class ElPartType>
RPN<OperandType,ElPartType>::RPN(const std::vector<std::basic_string<ElPartType>> &_In){
In = _In;
std::vector<Ellement_Priority<OperandType,ElPartType>*> Stack;
for (unsigned int i=0;i<In.size();i++){
//начинаем просматривать входную строку слева-направо
if (Tables<OperandType,ElPartType>::IsInOperation(In[i])){
//если входной эл-т операция, запрашиваем из таблицы её приоритет
unsigned int tmppri =
Tables<OperandType,ElPartType>::GetPriority(In[i]);
if (tmppri==0)
//если входной элемент - открывающая скобка, то просто
складываем её в стек
Stack.push_back(Tables<OperandType,ElPartType>::GetPointer(In[i]));
else
if (tmppri==1){
//если входной элемент - закрывающая скобка,то
while (Stack.size()&&(*Stack.back()).RetPriority()!=0){
//пока в стеке есть элементы и элемент на
вершине стека не открывающая собка
Expr.push_back(Stack.back()->RetName());
Stack.pop_back();
//достаем элементы и складываем их в выходную
строку
}
if (Stack.size())
//если в стеке что-то осталось, то это
открывающая скобка, достаем её
Stack.pop_back();
else
//если стек пуст, то в нашем выражение
закрывающих скобок, больше, чем октрывающих
throw IBreak();
}else
//если входной элемент - операция, не скобка
if (Stack.size()==0)
//если стек пуст, то просто проталкиваем
операцию
Stack.push_back(Tables<OperandType,ElPartType>::GetPointer(In[i]));
31
else{
//если в стеке, что-то есть, то достаем все
операции с приоритетом >= текущего эл-та
while(Stack.size()&&Stack.back()>RetPriority()>=tmppri){
// пока в стеке есть элементы и приоритет
верхнего больше либо равен текущему
// перемещаем операции из стека в выходную
строку
Expr.push_back(Stack.back()->RetName());
Stack.pop_back();
}
//помещаем в стек входную операцию
Stack.push_back(Tables<OperandType,ElPartType>::GetPointer(In[i]));
}
}else
//если элемент - операнд, то просто помещаем его в выходную строку
Expr.push_back(In[i]);
}
while (Stack.size()){
//пока в стеке остаются эл-ты, достаем их и помещаем в выходную строку
Expr.push_back(Stack.back()->RetName());
Stack.pop_back();
}
}
template<class OperandType,class ElPartType>
OperandType RPN<OperandType,ElPartType>::Execute()const{
//вычисление выражение с использованием пользователя :)
std::vector<OperandType> Stack;
Stack.reserve(100);
std::cout << "Expression in normal:" << std::endl;
for (unsigned int i=0;i<In.size();i++){
for (unsigned int j=0;j<In[i].size();j++)
std::cout << (char)In[i][j];
std::cout << " ";
}
std::cout << std::endl;
std::cout << "Expression in RPN:" << std::endl;
for (unsigned int i=0;i<Expr.size();i++){
for (unsigned int j=0;j<Expr[i].size();j++)
std::cout << (char)Expr[i][j];
std::cout << " ";
}
std::cout << std::endl;
for (unsigned int i = 0;i<Expr.size();i++)
//начинаем просматривать выражение в обратной польской записи
if (Tables<OperandType,ElPartType>::IsInOperation(Expr[i])){
//если входной эл-т - операция, запрашиваем из таблицы указатель на
соотвествующую операцию
//создаем массив операндов и вычисляем выражение, записывая результат
в стек
std::vector<OperandType> Oprs;
Operation<OperandType,ElPartType> *CurOperation =
static_cast<Operation<OperandType,ElPartType>*>(Tables<OperandType,ElPartType>::GetPointe
r(Expr[i]));
for (unsigned int k=0;k<CurOperation->RetN_nary();k++){
Oprs.push_back(Stack.back());
Stack.pop_back();
}
Stack.push_back(CurOperation->Execute(Oprs));
Oprs.clear();
}else
32
//если входной эл-т - операнд
if (Tables<OperandType,ElPartType>::IsInit(Expr[i]))
//запрашиваем у таблицы инициализирована ли данная переменная,
получаем значение и
//заносим его в стек
Stack.push_back(Tables<OperandType,ElPartType>::GetValue(Expr[i]));
else
//иначе запрашиваем значение данной переменной у пользователя
Stack.push_back(Tables<OperandType,ElPartType>::SetTo(Expr[i]));
//получаем ответ из вершины стека и выводим его
if (Stack.size()==1){
OperandType Ans = Stack.back();
std::cout << "Answer = " << Ans <<std::endl;
return Ans;
}else{
throw SyntaxError<ElPartType>(_T("string."));
return (OperandType)0;
}
}
template<class OperandType,class ElPartType>
OperandType RPN<OperandType,ElPartType>::Execute(const std::vector<OperandType>&
_Operands)const{
//вычисление выражения на основе входного массива операндов
std::vector<OperandType> Stack;
Stack.reserve(100);
std::vector<OperandType> Use = _Operands;
for (unsigned int i = 0;i<Expr.size();i++)
if (Tables<OperandType,ElPartType>::IsInOperation(Expr[i])){
std::vector<OperandType> Oprs;
Operation<OperandType,ElPartType> *tmp2 =
static_cast<Operation<OperandType,ElPartType>*>(Tables<OperandType,ElPartType>::GetPointe
r(Expr[i]));
for (unsigned int k=0;k<tmp2->RetN_nary();k++){
Oprs.push_back(Stack.back());
Stack.pop_back();
}
Stack.push_back(tmp2->Execute(Oprs));
}else{
//отличается от ручного вычисления лишь данной частью, в которой
необходимые операнды
//просто получаются из входного массива
Stack.push_back(Use.back());
Use.pop_back();
}
OperandType Ans = Stack.back();
return Ans;
}
“Step.h”
//!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
using namespace std;
template<class OperandType>
class IStep{
private:
OperandType a;
public:
33
IStep(OperandType _a){a = _a;}
void ConsoleErrorPrint();
friend ostream& operator<< <>(ostream&,const IStep&);
};
template<class OperandType>
void IStep<OperandType>::ConsoleErrorPrint(){
std::cout << "Error: step = " << a <<" is not correct" <<std::endl;
}
template<class OperandType>
ostream& operator<<(ostream& Out,const IStep<OperandType> &T){
Out << "Error: step = " << T.a <<" is not correct" <<std::endl;
return Out;
}
template<class OperandType,class ElPartType>
class Step:public Operation<OperandType,ElPartType>
{
public:
Step(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Step<OperandType,ElPartType>::Step(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,4,2){};
template<class OperandType,class ElPartType>
OperandType Step<OperandType,ElPartType>::Execute(const std::vector<OperandType>& In)
const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
if (In[1]<0)
throw IStep<OperandType>(In[1]);
else
if (In[1]==0)
return 1;
else{
OperandType Res=In[0];
for (int i=1;i<In[1];i++)
Res*=In[0];
return Res;
}
}
“Tables.h”
#pragma once
#include "HashTable.h"
/*----------------------------------------------------------------------Данный класс будет содержать, лишь статические элементы - таблицы с операторами
и операндами.
Таблица операторов будет формироваться, перед выполнением выражения, а операндов
в процессе разбора выражения конечным автоматом.
-------------------------------------------------------------------------*/
template<class OperandType,class ElPartType>
class Tables
{
static HashTableEllPri<OperandType,ElPartType> OperationTable;
34
static HashTableOprs<OperandType,ElPartType> OperandsTable;
public:
static void AddOperator(Ellement_Priority<OperandType,ElPartType>*);
protected:
static void AddOperand(Operand<OperandType,ElPartType>*);
static bool IsInOperation(const std::basic_string<ElPartType>&);
static unsigned int GetPriority(const std::basic_string<ElPartType>&);
static bool IsInit(const std::basic_string<ElPartType>&);
static OperandType GetValue(const std::basic_string<ElPartType>&);
static OperandType SetTo(const std::basic_string<ElPartType>&);
static Ellement_Priority<OperandType,ElPartType> *GetPointer(const
std::basic_string<ElPartType>&);
virtual ~Tables(void)=0;
};
template<class OperandType,class ElPartType>
HashTableEllPri<OperandType,ElPartType> Tables<OperandType,ElPartType>::OperationTable;
template<class OperandType,class ElPartType>
HashTableOprs<OperandType,ElPartType> Tables<OperandType,ElPartType>::OperandsTable;
template<class OperandType,class ElPartType>
void
Tables<OperandType,ElPartType>::AddOperator(Ellement_Priority<OperandType,ElPartType>*
T){
OperationTable.Add(T);
}
template<class OperandType,class ElPartType>
void Tables<OperandType,ElPartType>::AddOperand(Operand<OperandType,ElPartType>* T){
OperandsTable.Add(T);
}
template<class OperandType,class ElPartType>
Tables<OperandType,ElPartType>::~Tables(){}
template<class OperandType,class ElPartType>
bool Tables<OperandType,ElPartType>::IsInOperation(const std::basic_string<ElPartType>&
T){
return OperationTable.IsIn(T);
}
template<class OperandType,class ElPartType>
unsigned int Tables<OperandType,ElPartType>::GetPriority(const
std::basic_string<ElPartType>& T){
return OperationTable.GetPriority(T);
}
template<class OperandType,class ElPartType>
Ellement_Priority<OperandType,ElPartType>
*Tables<OperandType,ElPartType>::GetPointer(const std::basic_string<ElPartType>& T){
return OperationTable.GetPointer(T);
}
template<class OperandType,class ElPartType>
bool Tables<OperandType,ElPartType>::IsInit(const std::basic_string<ElPartType>& T){
return OperandsTable.IsInit(T);
}
template<class OperandType,class ElPartType>
OperandType Tables<OperandType,ElPartType>::GetValue(const std::basic_string<ElPartType>&
T){
return OperandsTable.GetValue(T);
35
}
template<class OperandType,class ElPartType>
OperandType Tables<OperandType,ElPartType>::SetTo(const std::basic_string<ElPartType>&
T){
return OperandsTable.SetTo(T);
}
“Umnogenie.h”
//!
#pragma once
#include "Operation.h"
#include "Excpt_ParAmount.h"
template<class OperandType,class ElPartType>
class Umnogenie:public Operation<OperandType,ElPartType>
{
public:
Umnogenie(const std::basic_string<ElPartType>&);
OperandType Execute(const std::vector<OperandType>&) const;
};
template<class OperandType,class ElPartType>
Umnogenie<OperandType,ElPartType>::Umnogenie(const std::basic_string<ElPartType>& _Name):
Operation<OperandType,ElPartType>(_Name,3,2){};
template<class OperandType,class ElPartType>
OperandType Umnogenie<OperandType,ElPartType>::Execute(const std::vector<OperandType>&
In) const{
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
return In[0]*In[1];
}
“User_Operation.h”
#pragma once
#include "Operation.h"
#include "RPN.h"
template<class OperandType,class ElPartType>
class User_Operation:public Operation<OperandType,ElPartType>
{
private:
RPN<OperandType,ElPartType> Expr;
public:
User_Operation(const std::basic_string<ElPartType>&,unsigned int,unsigned
int,const RPN<OperandType,ElPartType>&);
OperandType Execute(const std::vector<OperandType>&)const;
};
template<class OperandType,class ElPartType>
User_Operation<OperandType,ElPartType>::User_Operation(const
std::basic_string<ElPartType>& _Name,unsigned int _n_nary,unsigned int _priority,
const RPN<OperandType,ElPartType>&_RPN):
Operation<OperandType,ElPartType>(_Name,_priority,_n_nary),Expr(_RPN){};
template<class OperandType,class ElPartType>
OperandType User_Operation<OperandType,ElPartType>::Execute(const
std::vector<OperandType>& In)const{
std::vector<OperandType> tmp = In;
if (In.size()!=RetN_nary())
throw Excpt_ParAmount(RetN_nary(),In.size());
else
36
return Expr.Execute(tmp);
}
“Var.h”
#pragma once
#include "Operand.h"
template<class OperandType,class ElPartType>
class Var:public Operand<OperandType,ElPartType>
{
private:
OperandType Now;
public:
Var(const std::basic_string<ElPartType>&);
void SetTo(OperandType _Now){Now=_Now;Init();}
OperandType SetToByUser();
OperandType RetNow()const{return Now;};
~Var(void);
};
template<class OperandType,class ElPartType>
Var<OperandType,ElPartType>::Var(const std::basic_string<ElPartType>&
_Name):Operand(_Name,0){};
template<class OperandType,class ElPartType>
Var<OperandType,ElPartType>::~Var(){};
template<class OperandType,class ElPartType>
OperandType Var<OperandType,ElPartType>::SetToByUser(){
std::basic_string<ElPartType> tmp = RetName();
for (unsigned int i=0;i<tmp.size();i++)
std::cout << (char)tmp[i];
std::cout << "=";
std::cin >> Now;
Init();
return Now;
}
Файлы с исходным кодом(cpp)
“Avtomat.cpp”
#include "Avtomat.h"
“Close.cpp”
#include "Close.h"
“Const.cpp”
#include "Const.h"
“Delenie.cpp”
#include "Delenie.h"
void EDivisionByZero::ConsoleErrorPrint(){
std::cout << "Error : division by zero" <<std::endl;
}
std::ostream& operator<< (std::ostream &Out,const EDivisionByZero &_T){
Out << "Error: division by zero! " <<std::endl;
return Out;
}
“Ellement.cpp”
#include "Ellement.h"
37
“Ellement_Priority.cpp”
void Ipriority::ConsoleErrorPrint(){
std::cout << "Error: priority = " << n << " is not correct" <<std::endl;
}
std::ostream& operator<<(std::ostream& Out,const Ipriority& T){
Out << "Error: priority = " << T.n << " is not correct" <<std::endl;
return Out;
}
“Excpt_ParAmount.cpp”
#include "Excpt_ParAmount.h"
void Excpt_ParAmount::ConsoleErrorPrint(){
std::cout << "Error: incorrect parametrs amount here: " << Here << " Need: " <<
Need << std::endl;
}
std::ostream& operator<<(std::ostream& Out,const Excpt_ParAmount& T){
Out << "Error: incorrect parametrs amount here: " << T.Here << " Need: " << T.Need
<< std::endl;
return Out;
}
“Factorial.cpp”
#include "Factorial.h"
“HashTable.cpp”
#include "HashTable.h"
std::ostream& operator<< (std::ostream& Out,const NotFound&){
Out << "Error: node not found in table" <<std::endl;
return Out;
}
“main.cpp”
#include <stdio.h>
#include "AllRPN.h"
int main(){
Plus<int,TCHAR> zn1(_T("+"));
Tables<int,TCHAR>::AddOperator(&zn1);
Minus<int,TCHAR> zn2(_T("-"));
Tables<int,TCHAR>::AddOperator(&zn2);
Umnogenie<int,TCHAR> zn3(_T("*"));
Tables<int,TCHAR>::AddOperator(&zn3);
Delenie<int,TCHAR> zn9(_T("/"));
Tables<int,TCHAR>::AddOperator(&zn9);
Open<int,TCHAR> zn4(_T("("));
Tables<int,TCHAR>::AddOperator(&zn4);
Close<int,TCHAR> zn5(_T(")"));
Tables<int,TCHAR>::AddOperator(&zn5);
Factorial<int,TCHAR> zn7(_T("!"));
Tables<int,TCHAR>::AddOperator(&zn7);
Step<int,TCHAR> zn8(_T("^"));
Tables<int,TCHAR>::AddOperator(&zn8);
setlocale(LC_ALL, "rus_rus.1251");
try{
38
RPN<int,TCHAR> test8(Avtomat<int,TCHAR>::Convert(_T("a!*b")));
User_Operation<int,TCHAR> zn6(_T("#"),2,7,test8);
Tables<int,TCHAR>::AddOperator(&zn6);
do{
std::_tcout << _T("Добро пожаловать.") << std::endl;
std::_tcout << "Please input expression:\n";
TCHAR buf[200];
std::_tcin.getline(buf,200);
RPN<int,TCHAR> expression(Avtomat<int,TCHAR>::Convert(buf));
expression.Execute();
std::_tcout << "Retry? ";
TCHAR tmp;
std::_tcin >>tmp;
if (tmp=='n')
return 0;
else{
//чтобы затереть символ новой строки, который в ином случае
все портит
std::_tcin.clear();
std::_tcin.sync();
}
}while(1);
}catch(EDivisionByZero a){
std::cout << a;
}catch(IStep<int> a){
std::cout << a;
}catch(Excpt_ParAmount a){
std::cout << a;
}catch(IBreak a){
std::cout << a;
}catch(SyntaxError<TCHAR> a){
std::cout << a;
}catch(Ipriority a){
std::cout << a;
}catch(IFact<int> a){
std::cout << a;
}catch(NotFound a){
std::cout << a;
}catch(In_nary a){
std::cout << a;
}
int i;
std::_tcin >> i;
return 0;
}
“Minus.cpp”
#include "Minus.h"
“Open.cpp”
#include "Open.h"
“Operand.cpp”
#include "Operand.h"
“Operation.cpp”
#include "Operation.h"
void In_nary::ConsoleErrorPrint(){
std::cout << "Error: n_nary = " << n << " is not correct" <<std::endl;
}
std::ostream& operator<< (std::ostream& Out,const In_nary& T){
39
Out << "Error: n_nary = " << T.n << " is not correct" <<std::endl;
return Out;
}
“Plus.cpp”
#include "Plus.h"
“RPN.cpp”
#include "RPN.h"
void IBreak::ConsoleErrorPrint(){
std::cout << "Error: incorrect break" <<std::endl;
}
std::ostream& operator<<(std::ostream& Out,const IBreak& T){
Out << "Error: incorrect break" <<std::endl;
return Out;
}
“Step.cpp”
#include "Step.h"
“Tables.cpp”
#include "Tables.h"
“Umnogenie.cpp”
#include "Umnogenie.h"
“User_Operation.cpp”
#include "User_Operation.h"
“Var.cpp”
#include "Var.h"
Download