pavlenko

advertisement
Федеральное агентство по образованию
Государственное общеобразовательное учреждение ТГТУ
Отчет по лабораторной работе №1
Тема: “ РАЗРАБОТКА ЛЕКСИЧЕСКОГО АНАЛИЗАТОРА ”
Выполнила:
Студентка 4 курса
Специальности ПОВТ-0906
Павленко Людмила
Принял:
Калабин А.Л.
Тверь, 2012
Отчет по лабораторной работе №1
Тема: «РАЗРАБОТКА ЛЕКСИЧЕСКОГО АНАЛИЗАТОРА»
Целью данной работы является написание блока сканирования,
который считывает исходную программу и представляет ее в форме файла
лексем.
Чтение файла в строку. Для выбора исходного файла в структуре
файловой системы используется элемент управления OpenFileDialog. Метод
ShowDialog() отобразит диалог выбора файла на экран, а о том, какую кнопку
в диалоге нажал пользователь можно узнать, сравнив значение,
возвращенное методом с константами статического класса DialogResult. При
значении, равном DialogResult.OK путь к выбранному файлу в файловой
системе можно получить через свойство FileName экземпляра
OpenFileDialog. Это значение нужно передать в метод ReadAllText класса
File. Метод вернет нам содержимое исходного файла.
Запись строки в файл. Необходимо использовать метод WriteAllText
класса File. В качестве параметров ему передаются имя файла и исходная
строка. Широко распространенной практикой является проверка на
существование файла перед записью с помощью метода Exists класса File.
Посимвольное чтение из файла. Класс StreamReader предоставляет
методы чтения следующего символа, строки или блока в файле. Однако на
каждом шаге необходимо сохранять данные о текущей строке, текущем
символе и позиции символа в строке. Довольно логичным будет реализовать
статический класс-обертку над StreamReader, который обеспечил бы нам не
только чтение из файла,но и хранение этих данных.
Вариант 10 (БНФ)
<Программа> ::= <Объявление переменных> <Описание вычислений>
<Оператор печати>
<Описание вычислений> ::= Begin <Список присваиваний> End
<Объявление переменных> ::= Integer <Список переменных>
<Список переменных> ::= <Идент>; | <Идент> , <Список переменных>
<Список присваиваний>::= <Присваивание> |
<Присваивание> <Список присваиваний>
<Присваивание> ::= <Идент> := <Выражение> ;
<Выражение> ::= <Ун.оп.> <Подвыражение> | <Подвыражение>
<Подвыражение> :: = ( <Выражение> ) | <Операнд> |
< Подвыражение > <Бин.оп.> <Подвыражение>
<Ун.оп.> ::= "-"
<Бин.оп.> ::= "-" | "+" | "*" | "/"
<Операнд> ::= <Идент> | <Const>
<Идент> ::= <Буква> <Идент> | <Буква>
<Const> ::= <Цифра> <Const> | <Цифра>
<Оператор печати>::=Print <Идент>
На одной строке может быть только объявление переменных или один
оператор присваивания
Нетерминалы:
N=
{
S=<Программа>
D=<Объявление переменных>
F=<Описание вычислений>
P=<Оператор печати>
V=<Список переменных>
I=<Идентификатор>
G=<Список присваиваний>
A=<Присваивание>
E=<Выражение>
H=<Подвыражение>
O=<Операнд>
C=<Const>
N=<Цифра>
}
Терминалы:
Ключевые слова языка:
T={begin, end, integer, print}
Разделители:
R={:=, .();}
Алфавит:
A={a|…|z}
Бинарные операции:
B={+|-|/|*}
Унарная опреация:
U={-}
Цифры:
C={0|…|9}
Правила:
S=DF
F=begin G end
G=A|AG
A=I:=E
I=LI|L
E=UH|H
H=(E)|O|HBH
O=I|C
C=NC|N
D=integer V
V=I;|I,V
P=print I
Листинг программы:
/// <summary>
/// Класс анализатор
/// Содержит символы разделения значений и конца строки
/// </summary>
public class Analiser
{
/// <summary>
/// Символ разделения параметров
/// </summary>
protected const String SEPARATOR = ",";
/// <summary>
/// Символ конца строки
/// </summary>
protected const String END_LINE = ";";
/// <summary>
/// Пробел
/// </summary>
protected const String BLANK = " ";
/// <summary>
/// Установление значение
/// </summary>
protected const String EQUATION = ":=";
/// <summary>
/// Таблица ключевых слов
/// </summary>
protected String[] TABLE_KEY_WORDS = { "const", "integer", "begin",
"end", "print" };
/// <summary>
/// Бинарная операция "Плюс"
/// </summary>
protected const String PLUS = "+";
/// <summary>
/// Бинарная операция "Минус"
/// </summary>
protected const String MINUS = "-";
/// <summary>
/// Бинарная операция "Умножение"
/// </summary>
protected const String MULTI = "*";
/// <summary>
/// Бинарная операция "Деление"
/// </summary>
protected const String DIVISION = "/";
}
public class LexemeAnaliser:Analiser,ILexemeAnalyser
{
private LexemeList lexemeList;
/// <summary>
/// Объект "представление"
/// </summary>
private TranslatorView view;
public LexemeAnaliser(TranslatorView view)
{
lexemeList = new LexemeList();
this.view = view;
}
public void anlisys()
{
try
{
lexemeList = new LexemeList();
for (int numberLine = 0; numberLine <
LoaderManagerController.InputList.Count; numberLine++)
{
if
(LoaderManagerController.InputList[numberLine].Equals(TABLE_KEY_WORDS[3]))
{
//numberLine =
LoaderManagerController.InputList.Count;
view.Log = "Variables was initialized";
break;
}
if
(LoaderManagerController.InputList[numberLine].Equals(TABLE_KEY_WORDS[5]))
continue;
addLexemeInList(numberLine,LoaderManagerController.InputList[numberLine],
getTypeLexemeValue(LoaderManagerController.InputList[numberLine]));
}
}
catch(Exception ex) { view.Log = ex.Message; }
}
/// <summary>
/// Возвращает тип объекта лексемы
/// </summary>
/// <param name="line">Строка для сканирования</param>
/// <returns>Тип объекта лексемы</returns>
private String getTypeLexemeValue(string line)
{
String value;
try
{
value = line.Remove(line.IndexOf(BLANK), line.Length line.IndexOf(BLANK)).Trim();
}
catch { throw new Exception("Невозможно получить тип лексемы"); }
return value;
}
/// <summary>
/// Получить все переменные объявленныу для данного идентификатора/
константы
/// </summary>
/// <param name="line">Строка для анализа</param>
/// <param name="typeLexeme">Тип идентификатора</param>
/// <returns>Список обяъвленных переменных</returns>
private String[] getVariables(String line, String typeLexeme)
{
string[] variables = null;
line = line.Remove(line.IndexOf(typeLexeme), typeLexeme.Length);
//Удаляем тип переменных
line = line.Remove(line.IndexOf(END_LINE), END_LINE.Length);
//Удаляем символ конца строки
line = line.Trim();
variables = line.Split(SEPARATOR.ToCharArray()[0]);
return variables;
}
/// <summary>
/// Получить значение лексемы
/// </summary>
/// <param name="lexeme">Лексема</param>
/// <returns>Значение лексемы</returns>
private Object getValueLexeme(String lexeme)
{
try
{
if (lexeme.IndexOf(EQUATION) == -1) return null;
lexeme = lexeme.Remove(0, lexeme.Length lexeme.IndexOf(EQUATION));
return lexeme.Trim();
}
catch { throw new Exception("Ошибка при получении значения
лексемы"); }
}
/// <summary>
/// Получить имя лексемы
/// </summary>
/// <param name="lexeme">Лексема</param>
/// <returns>Имя лексемы</returns>
private String getNameLexeme(String lexeme)
{
try
{
if (lexeme.IndexOf(EQUATION) == -1) return lexeme.Trim();
lexeme = lexeme.Remove(lexeme.IndexOf(EQUATION),lexeme.Length
- lexeme.IndexOf(EQUATION));
return lexeme.Trim();
}
catch { throw new Exception("Ошибка при получении имени
лексемы"); }
}
private void addLexemeInList(int numberLine, String line, String
typeLexeme)
{
switch (typeLexeme)
{
case "int":
{
string[] variables = getVariables(line, typeLexeme);
for (int numberOnLine = 0; numberOnLine <
variables.Length; numberOnLine++)
{
lexemeList.add(new
Identificator(getNameLexeme(variables[numberOnLine]),
getTypeLexemeValue(line),
numberOnLine,
numberLine,
getValueLexeme(variables[numberOnLine])));
}
break;
}
case "double":
{
string[] variables = getVariables(line, typeLexeme);
for (int numberOnLine = 0; numberOnLine <
variables.Length; numberOnLine++)
{
lexemeList.add(new
Identificator(getNameLexeme(variables[numberOnLine]),
getTypeLexemeValue(line),
numberOnLine,
numberLine,
getValueLexeme(variables[numberOnLine])));
}
break;
}
case "logical":
{
string[] variables = getVariables(line, typeLexeme);
for (int numberOnLine = 0; numberOnLine <
variables.Length; numberOnLine++)
{
lexemeList.add(new
Identificator(getNameLexeme(variables[numberOnLine]),
getTypeLexemeValue(line),
numberOnLine,
numberLine,
getValueLexeme(variables[numberOnLine])));
}
break;
}
case "const":
{
//Костыль конечно, но на первое время сойдет
line = line.Remove(line.IndexOf("const"),
"const".Length);
line = line.Trim();
string[] variables = getVariables(line,
getTypeLexemeValue(line));
for (int numberOnLine = 0; numberOnLine <
variables.Length; numberOnLine++)
{
lexemeList.add(new
Const(getNameLexeme(variables[numberOnLine]),
getTypeLexemeValue(line),
numberOnLine,
numberLine,
getValueLexeme(variables[numberOnLine])));
}
break;
}
default: { throw new Exception("Неизвестная лексема '" +
typeLexeme + "'"); }
}
}
public LexemeList LexemesList
{
get { return this.lexemeList; }
}
}
public abstract class AbstractLexeme:ILexeme
{
protected String id;
protected Int32 positionInLine;
protected Int32 numberLine;
/// <summary>
/// Тип лексемы
/// </summary>
protected LexemeType.Type TYPE_LEXEME;
/// <summary>
/// Тип значения лексемы
/// </summary>
protected String typeLexemeValue;
protected Object value_;
public override bool Equals(object obj)
{
if (obj is AbstractLexeme)
{
if (value_ == obj)
return true;
else
return false;
}
else { throw new Exception("Error type"); }
}
public LexemeType.Type getType()
{
return TYPE_LEXEME;
}
public override string ToString()
{
String value = numberLine.ToString() + " " +
positionInLine.ToString() + " " + id + " " + TYPE_LEXEME.ToString() + " " +
typeLexemeValue + " ";
if (value_ != null) value += value_.ToString();
else
value += "null";
return value;
}
public String ID
{
get
{
return id;
}
set { throw new Exception("Can't setting value of field"); }
}
public Int32 PositionInLine
{
get
{
return positionInLine;
}
set
{
positionInLine = value;
}
}
public Int32 NumberLine
{
get
{
return numberLine;
}
set
{
numberLine = value;
}
}
public Object Value
{
get
{
return value_;
}
set
{
value_ = value;
}
}
public String TypeLexemeValue
{
get
{
return typeLexemeValue;
}
set
{
typeLexemeValue = value;
}
}
}
Пример работы программы:
Вывод:
В результате проделанной работы были изучены основные понятия теории регулярных
грамматик, назначения и принципы работы лексических анализаторов (сканеров).
Были получены практические навыки построения сканера на примере заданного
простейшего входного языка.
Download