России Бориса Николаевича Ельцина Кафедра "Информационные технологии и автоматизация проектирования" курсовая
Вид материала | Курсовая |
СодержаниеOperation = 1 |
- Роль Бориса Николаевича Ельцина в демократических преобразованиях в России, 175.25kb.
- Бориса Николаевича Ельцина. Мы с вами начинаем работу XVIII научно-практической конференции, 646.25kb.
- Направление 230400 «Информационные системы и технологии», 20.25kb.
- Президента Российской Федерации Б. Н. Ельцина» Кафедра иностранных языков в области, 307.91kb.
- Уральский Государственный Технический университет упи факультет дистанционного образования, 453.26kb.
- Название Предмет Направление, 921.62kb.
- Апреля IV международная научно-практическая конференция «Информационные технологии, 281.05kb.
- Рабочая программа по дисциплине "алгоритмизация и программирование" для специальности, 136.78kb.
- Уважаемые коллеги!, 57.4kb.
- Некоммерческое Партнерство «Автоматизация деятельности музеев и информационные технологии», 35.47kb.
Министерство образования и науки
Федеральное агентство по образованию РФ
ГОУ ВПО «Уральский государственный технический университет – УПИ
Имени первого президента России Бориса Николаевича Ельцина»
Кафедра “Информационные технологии и автоматизация проектирования”
Курсовая работа
По предмету “Теория языков и методы трансляции”
Руководитель: Копорушкин П.А.
Группа: М-45072
Студент: Рудаковский К.И.
Екатеринбург
2008
Задание:
Реализовать МП транслятор, для своего языка. Язык должен включать определение переменных типа целое число или с плавающей запятой. Инициализацию этих переменных, возможность считать выражения состоящие из констант, переменных, бинарных операций, таких как сложение, вычитание, умножение, деление, возведение в степень, а так же унарный + и -.
Создание программы для курсовой работы было разбито на несколько этапов.
- На первом этапе нам надо было написать программу, которая бы с помощью конечного автомата проверяла правильность введенной цепочки. Автомат задавался матрицей смежности, которая загружалась в программу, при этом происходил анализ по поиску повторяющихся и недопустимых состояний.
- На втором этапе надо было составить автомат для анализа выражения, состоящего из чисел и знаков + , - , * , /, . Реализовать Математический блок, который бы считал выражение без приоритета операций.
- Реализовать программу на основе конечного автомата, которая бы разбивала исходный текст на лексемы.
- Реализовать МП-распознаватель, который исходя из заданной грамматики проверял бы последовательность лексем.
- Реализовать МП-транслятор, который в процессе распознавания, выполняло бы определенные действия.
На первом этапе был реализован конечный автомат.
Конечный автомат — в теории алгоритмов математическая абстракция, позволяющая описывать пути изменения состояния объекта в зависимости от его текущего состояния и входных данных, при условии что общее возможное количество состояний конечно.
С помощью него был реализован синтаксический анализатор. Мы загружали из исходного файла матрица смежности, которой задавался наш граф. Столбцы соответствовали множеству символов, из которых могла состоять исходная проверяемая последовательность. Строки соответствовали состояниям автомата. На пересечении столбца и строки находиться номер новой строки (т.е. нового состояния) или специальный символ который означает недопустимый переход, и следовательно текущая последовательность считается не корректной.
При загрузке автомата из исходного файла программа должна была проанализировать его. путем перебора всех состояний и проверкой их на эквивалентность, те нахождение таких состояний в который мы попадаем по одним и тем же правилам и выход из этих состояний осуществляется по одинаковым правилам. Так же необходимо было удалить не достижимые состояния. Недостижимые состояния искались путем поиска по графу в глубину. Т.е. мы брали первое состояние, заносили его список пройденных, и далее переходили по всем возможным переходам до тех пор, пока мы не сможем перейти дальше, а это возможно только в том случае если то состояние куда нам предлагается перейти, помечено как пройденное.
Так же необходимо было предоставить возможность выгрузки оптимизированного конечного автомата в файл.
На втором этапе был реализован конечный автомат для анализа выражений. А так же арифметический блок, который считал бы проверенную последовательность без приоритета операций, те слева на право.
Матрица смежности для такого конечного автомата выглядит как:
| с | , | + | - | * | / | |
0 | 1 | -1 | -1 | -1 | -1 | -1 | -1 |
1 | 1 | 2 | 0 | 0 | 0 | 0 | 0 |
2 | 3 | -1 | -1 | -1 | -1 | -1 | -1 |
3 | 3 | -1 | 0 | 0 | 0 | 0 | 0 |
Где с – означает множество чисел {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. Запятая отделяет целую часть от дробной. 0 состояние означает разрешает ввод только числа, далее мы переходим в 1 состояние, в котором допускается ввод следующей части числа, в этом случае м будем оставаться в этом состоянии, до тех пор пока не встретиться символ операции, в этом случае мы закончим считывании числа, и перейдем в состояние 0. Если в 1 состоянии мы встречаем , то переходим в состояние 2, в котором мы должны ввести число, тогда перейдем в состояние 3, где будем считывать дробную часть до тех пор пока не встретим символ операции.
Вторая часть данного этапа состояла из реализации арифметического блока без приоритетов операций. При разбиении последовательности мы уверены в ее правильности, тк автомат пропустил ее.
Разбиение последовательности происходило рекурсивно, мы искали самый правый стоящий символ, и разбивали последовательность, на оператор, который ставился в вершине, отсеченного числа, которое ставилось в правую ветку, и оставшейся части, которая ставилась в левую ветку. Операции повторялись до тех пока последовательность находящею в левой ветке не удавалось разбить.
Те для выражения a + b * c составлялось бинарное дерево вида:
c
b
a
Берется операция стоящая в вершины, и выполняется к значениям стоящий в ветках.
Таким образом поднимаясь с самой нижней вершины и выполняя операции мы получим вычисленное выражение с право на лево не учитывая приоритет операций.
На третьем этапе нам необходимо было разбивать исходный текст на лексемы.
При чтении текста мы отталкивались от двух событий автомата. Автомат перешел в новое состояние, а это значит что мы заканчиваем читать текущую лексему и добавляем ее в список лексем. Проверяем символ который привел к смене состояния, и если это символ операции, разделитель то формируем соответствующую лексему. Если мы считали символ и состояние автомата не изменилось мы добавляем текущий символ к текущей лексеме. Лексемы на которые мы разбивает текущий текст :
- целое число
- дробное число
- операция сложения
- операция вычитания
- операция деления
- операция умножения
- операция присвоение ( = )
- операция возведения в степень
- тип с плавающей запятой
- тип целых чисел
- запятая
- точка с запятой
При этом наш конечный автомат проверяет исходный текст на наличие недопустимых символов алфавита. Формируется поток лексем, последовательность которых никак не проверяется.
На четвертом этапе нам необходимо было реализовать автомат с магазинной памятью.
Задачей данного мп автомата была проверка исходной последовательности лексем, которую мы получаем на третьем этапе нашей работы. И в соответствии с заданной грамматикой проверять на корректность последовательность лексем.
Автомат с магазинной памятью задается:
- конечным множеством входных символов
- конечным множествам магазинных символов
- конечным множеством состояний
- управляющим устройством, которое в соответствии предыдущим трем пунктам, ставит новое состояние или переходит в состояние ошибки.
- Начальным содержимым магазина.
Грамматика для нашего автомата имеет вид:
Правило: Множество выбора:
P -> D k
P -> I4 v
D ->k I1 k
I1 ->I I2 v
I2 ->, I1 ,
I2 -> έ ; =
I4 -> I3 v
I ->v I3 v
I3 -> = E =
I3 -> έ ,;
E ->T X +-vc(
X ->+ T X +
X -> - T X -
X -> έ ,;)
T -> F Y +-vc(
Y -> * F Y *
Y -> / F Y /
Y -> S
Y -> έ +-),;
S -> S F
S -> έ
F -> + F +
F -> - F -
F -> v v
F -> c c
F ->( E ) (
Заглавными символами обозначаются нетерминальные символы, маленькими терминальные. Грамматика однозначна, те для каждого нетерминального символа, существует только один переход, определяемый множеством выбора.
Грамматика вместе со множеством выбора задается в программе.
На пятом этапе нам необходимо было реализовать мп транслятор.
Во время проверки исходной последовательности лексем, в магазин помещаются управляющие символы, встречая которые мп автомат выполняет.
Список управляющий символов:
- Declare - объявить
- Initialize - инициализировать
- + - сложить
- ++ - унарный +
- - вычесть
- -- унарный минус
- * - умножить
- / - поделить
- - возвести в степень
В программе храниться стек констант, стек переменных, и словарь состоящий из пар имя переменной : значение.
Когда управляющее устройство извлекает управляющий символ, оно его выполняет.
Например когда мы извлекаем из магазина + , то из стека констант выталкиваются два значения, складываются и помещаются обратно: Constants.Push(Constants.Pop() + Constants.Pop()). Операции * выполняются аналогично.
Для операций -, и /, сначала извлекается верхний символ стека, заноситься во временную переменную, далее выталкивается следующая константа, из которого вычитается , делится или возводиться в степень временная константа: tmpConstant = Constants.Pop(); Constants.Push(Constants.Pop() / tmpConstant);
При извлечении из магазина команды объявить, и при условии что такого идентификатора еще не существует, добавляем в список переменных.
При извлечении команды присвоить, ищем такой идентификатор в словаре с объявленными переменными, и в случае нахождения присваиваем ему новое значение.
При реализации это задачи пришлось реализовать свой класс число. Которое бы динамически приводило себя к нужному типу, в зависимости от типа другого операнда.
Те если к integer мы прибавим float, то тип возвращаемого значения будет float. Если объявленная переменная имеет тип integer, то при присвоении в нее переменной/числа типа float, оно будет динамически приведено к integer;
События на которые реагирует программа:
Разбор текста на лексемы и запуска мп распознававателя по лексемам.
private void button1_Click(object sender, EventArgs e)
{
itsDFS.Reset();
listView1.Items.Clear();
listView2.Items.Clear();
try
{
for (int i = 0; i < richTextBox1.Text.Length; ++i)
{
itsDFS.setNextSymbol(richTextBox1.Text[i]);
}
}
catch (IncorrectSymbolExeption) { MessageBox.Show("Lexems Parser fail"); }
try
{
MPTranslator.Reset(itsDFS.TEMP);
MPTranslator.Go();
}
catch (ArgumentOutOfRangeException ex) { MessageBox.Show("Something goes wrong"); }
catch (Exception ex) { MessageBox.Show(ex.Message); }
for (int i = 0; i < itsDFS.TEMP.Count; ++i)
listView1.Items.Add(itsDFS.TEMP[i].ToString());
for (int i = 0; i < MPTranslator.Variable.Count; ++i)
{
if (MPTranslator.InitializeTable.ContainsKey(MPTranslator.Variable[i]))
{
listView2.Items.Add(MPTranslator.Variable[i] + ": " + MPTranslator.InitializeTable[MPTranslator.Variable[i]].ToString());
}
else listView2.Items.Add(MPTranslator.Variable[i] + ": null");
}
}
Выход:
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
if (richTextBox1.Text.Length != 0)
richTextBox1.Text = "";
button1.Enabled = false;
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Text files (*.txt)|*.txt";
open.ShowDialog();
if (open.FileName == "")
{
MessageBox.Show("File not selected");
}
else
{
try
{
itsDFS = new pseudoKA(open.FileName);
MPTranslator = new MP();
}
catch (IOException)
{
MessageBox.Show("Incorrect input file");
return;
}
button1.Enabled = true;
}
}
Сохранение ка, который использовался для разбора лексем
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if (itsDFS == null)
{
MessageBox.Show("FM is not loaded !");
return;
}
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Text files (*.txt)|*.txt";
save.ShowDialog();
if (save.FileName == "")
{
MessageBox.Show("File for save not selected !");
return;
}
if (!itsDFS.Save(save.FileName)) MessageBox.Show("File not saved");
}
Класс автомат с магазинной памятью:
class MP
{
private Stack
private Stack
private List
private List
private Dictionary
private string CurrentVariable;
private MyType CurrentValue;
private string CurrentType;
private List
private int CurrentLexeme;
public MP()
{
CurrentLexeme = 0;
CurrentValue = new MyType(0f);
Constants = new Stack
Variables = new List
VariablesType = new List
InitializeVariables = new Dictionary
Magazine = new Stack
Magazine.Push("P");
}
public void Reset(List
{
this.ListOfLexems = ListOfLexems;
CurrentLexeme = 0;
Magazine.Clear();
Magazine.Push("END");
Magazine.Push("P");
VariablesType.Clear();
Constants.Clear();
Variables.Clear();
InitializeVariables.Clear();
}
public void Go()
{
MyType tmpConstant;
while(true)
{
if ((Magazine.Count == 0) && (CurrentLexeme == ListOfLexems.Count)) break;
switch (Magazine.Pop())
{
case "END":
if ((ListOfLexems[CurrentLexeme].Symbol == ';')&
(CurrentLexeme != ListOfLexems.Count - 1))
{
Magazine.Push("END");
Magazine.Push("P");
CurrentLexeme++;
break;
}
if ((ListOfLexems[CurrentLexeme].Symbol == ';') &
(CurrentLexeme == ListOfLexems.Count - 1))
{
CurrentLexeme++;
break;
}
throw new Exception();
break;
//****************
case "P":
if (ListOfLexems[CurrentLexeme].Symbol == 'k')
{
CurrentType = ListOfLexems[CurrentLexeme].ToString();
Magazine.Push("D");
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == 'v')
{
Magazine.Push("I4");
CurrentVariable = ListOfLexems[CurrentLexeme].ToString();
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() +" :type or variable expected");
break;
//****************
case "I4":
if (ListOfLexems[CurrentLexeme].Symbol == 'v')
{
Magazine.Push("I3");
CurrentLexeme++;
break;
}
throw new Exception();
break;
//****************
case "D":
if (ListOfLexems[CurrentLexeme].Symbol == 'k')
{
Magazine.Push("I1");
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :type expected");
break;
//***************
case "I1":
if (ListOfLexems[CurrentLexeme].Symbol == 'v')
{
Magazine.Push("I2");
Magazine.Push("I");
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :type expected");
break;
//***************
case "I2":
if (ListOfLexems[CurrentLexeme].Symbol == ',')
{
Magazine.Push("I1");
CurrentLexeme++;
break;
}
if ((ListOfLexems[CurrentLexeme].Symbol == ';') |
(ListOfLexems[CurrentLexeme].Symbol == '='))
{
break;
}
throw new Exception();
break;
//***************
case "I":
if (ListOfLexems[CurrentLexeme].Symbol == 'v')
{
Magazine.Push("I3");
Magazine.Push("Declare");
CurrentVariable = ListOfLexems[CurrentLexeme].ToString();
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == 'c')
{
Magazine.Push("E");
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :constant or variable expected");
break;
//***************
case "I3":
if (ListOfLexems[CurrentLexeme].Symbol == '=')
{
Magazine.Push("Initialize");
Magazine.Push("E");
CurrentLexeme++;
break;
}
if ((ListOfLexems[CurrentLexeme].Symbol == ';') |
(ListOfLexems[CurrentLexeme].Symbol == ','))
{
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " : = {| ; | ,} expected");
break;
//***************
case "E":
if ((ListOfLexems[CurrentLexeme].Symbol == '+')|
(ListOfLexems[CurrentLexeme].Symbol == '-')|
(ListOfLexems[CurrentLexeme].Symbol == 'c')|
(ListOfLexems[CurrentLexeme].Symbol == 'v')|
(ListOfLexems[CurrentLexeme].Symbol == '(')|
(ListOfLexems[CurrentLexeme].Symbol == ''))
{
Magazine.Push("X");
Magazine.Push("T");
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{+|-|c|v|(|} expected");
break;
//***************
case "X":
if ((ListOfLexems[CurrentLexeme].Symbol == ';')|
(ListOfLexems[CurrentLexeme].Symbol == ',')|
(ListOfLexems[CurrentLexeme].Symbol == ')')|
(ListOfLexems[CurrentLexeme].Symbol == ''))
{
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '+')
{
Magazine.Push("X");
Magazine.Push("+");
Magazine.Push("T");
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '-')
{
Magazine.Push("X");
Magazine.Push("-");
Magazine.Push("T");
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{+|-|;|,|)|} expected");
break;
//***************
case "T":
if ((ListOfLexems[CurrentLexeme].Symbol == 'c')|
(ListOfLexems[CurrentLexeme].Symbol == '+')|
(ListOfLexems[CurrentLexeme].Symbol == '-')|
(ListOfLexems[CurrentLexeme].Symbol == 'v')|
(ListOfLexems[CurrentLexeme].Symbol == '(')|
(ListOfLexems[CurrentLexeme].Symbol == ''))
{
Magazine.Push("Y");
Magazine.Push("F");
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{+|-|c|v|(|} expected");
break;
//***************
case "Y":
if ((ListOfLexems[CurrentLexeme].Symbol == ';')|
(ListOfLexems[CurrentLexeme].Symbol == ',')|
(ListOfLexems[CurrentLexeme].Symbol == '+')|
(ListOfLexems[CurrentLexeme].Symbol == '-'))
{
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == ')')
{
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '')
{
Magazine.Push("S");
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '*')
{
Magazine.Push("Y");
Magazine.Push("*");
Magazine.Push("F");
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '/')
{
Magazine.Push("Y");
Magazine.Push("/");
Magazine.Push("F");
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{+|-|/|*|)||;|,} expected");
break;
//***************
case "S":
if (ListOfLexems[CurrentLexeme].Symbol == '')
{
Magazine.Push("S");
Magazine.Push("");
Magazine.Push("F");
CurrentLexeme++;
break;
}
if ((ListOfLexems[CurrentLexeme].Symbol == ';')|
(ListOfLexems[CurrentLexeme].Symbol == ',')|
(ListOfLexems[CurrentLexeme].Symbol == '+')|
(ListOfLexems[CurrentLexeme].Symbol == '-')|
(ListOfLexems[CurrentLexeme].Symbol == ')'))
{
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{+|-|;|,|)|} expected");
break;
//***************
case "F":
if (ListOfLexems[CurrentLexeme].Symbol == 'c')
{
CurrentValue = ListOfLexems[CurrentLexeme].Number;
Constants.Push(CurrentValue);
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == 'v')
{
if (!Variables.Contains(ListOfLexems[CurrentLexeme].ToString())) throw new Exception(ListOfLexems[CurrentLexeme].ToString() + " is not declared");
Constants.Push(new MyType(InitializeVariables[ListOfLexems[CurrentLexeme].ToString()]));
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '+')
{
Magazine.Push("++");
Magazine.Push("F");
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '-')
{
Magazine.Push("--");
Magazine.Push("F");
CurrentLexeme++;
break;
}
if (ListOfLexems[CurrentLexeme].Symbol == '(')
{
Magazine.Push(")");
Magazine.Push("E");
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{ + | - | c | v | ( } expected");
break;
//***************
case ")":
if (ListOfLexems[CurrentLexeme].Symbol == ')')
{
CurrentLexeme++;
break;
}
throw new Exception("Incorrect " + ListOfLexems[CurrentLexeme].ToString() + " :{ ) } expected");
break;
// Rule symbols
//***************
case "Declare":
if (Variables.Contains(CurrentVariable)) throw new Exception("Variable: " + CurrentVariable + " is also declared");
Variables.Add(CurrentVariable);
VariablesType.Add(CurrentType);
break;
//***************
case "Initialize":
tmpConstant = Constants.Pop();
if (!Variables.Contains(CurrentVariable)) throw new Exception("Variable: " + CurrentVariable.ToString() + " is not declared");
if (VariablesType[Variables.IndexOf(CurrentVariable)] == "float") tmpConstant.ToFloat();
else tmpConstant.ToInteger();
if (InitializeVariables.ContainsKey(CurrentVariable))
{
InitializeVariables[CurrentVariable] = tmpConstant;
break;
}
InitializeVariables.Add(CurrentVariable, tmpConstant);
break;
//***************
case "+":
Constants.Push(Constants.Pop() + Constants.Pop());
break;
//***************
case "-":
tmpConstant = Constants.Pop();
Constants.Push(Constants.Pop() - tmpConstant);
break;
//***************
case "++":
break;
//***************
case "--":
tmpConstant = Constants.Pop();
tmpConstant.Inverse();
Constants.Push(tmpConstant);
break;
//***************
case "*":
Constants.Push(Constants.Pop() * Constants.Pop());
break;
//***************
case "/":
tmpConstant = Constants.Pop();
Constants.Push(Constants.Pop() / tmpConstant);
break;
case "":
tmpConstant = Constants.Pop();
Constants.Push(Constants.Pop() tmpConstant);
break;
//***************
default: throw new Exception();
}
}
}
public List
{
get { return Variables; }
}
public Dictionary
{
get { return InitializeVariables; }
}
}
Класс который проходит по тексту и формирует лексемы:
class pseudoKA
{
private int itsCurrentState;
private List
private List
private Lexeme itsLexeme;
private int itsOldState;
public pseudoKA(string path)
{
itsState = new List
itsLexeme = new Lexeme();
ReadAndOptimize tmp = new ReadAndOptimize(path, itsState, itsLexeme);
itsSymbols = new List
itsCurrentState = 0;
itsOldState = 0;
}
public void Reset()
{
itsCurrentState = 0;
itsOldState = 0;
itsLexeme.ClearLex();
itsLexeme.Reset();
}
public bool Save(string path)
{
try
{
SaveKA save = new SaveKA(path, itsState, itsSymbols);
return true;
}
catch (IOException)
{
return false;
}
}
public void setNextSymbol(char symbol)
{
itsCurrentState = itsState[itsCurrentState].setNextSymbol(symbol);
if (itsCurrentState != itsOldState) itsLexeme.OnStateChange(symbol);
else itsLexeme.setNextSymbol(symbol);
if ((symbol == ';') && (itsState[itsOldState].FiniteState == false)) throw new IncorrectSymbolExeption();
itsOldState = itsCurrentState;
}
public List
{
get { return itsLexeme.LexemsList; }
}
}
Чтение и оптимизация автомата для разбора на лексемы:
class ReadAndOptimize
{
private List
private List