Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Diploma_All

.pdf
Скачиваний:
20
Добавлен:
05.06.2015
Размер:
1.37 Mб
Скачать

3.1.4 Разработка приложений на разных языках

Как следует из ее названия, общеязыковая среда выполнения CLR поддерживает многие языки программирования. Для каждого такого языка должен быть реализован компилятор, который генерирует управляемый код. Сама компания Microsoft реализовала компиляторы для управляемого C++, Visual Basic .NET, JScript, J# (компилятор языка Java), а также для совершенно нового языка программирования С#.

Компиляторы для более чем дюжины других языков реализуются усилиями независимых разработчиков. К числу этих языков программирования принадле-

жат языкиAlice, APL, COBOL, Component Pascal, Eiffel, Fortran, Haskell, Mercury, ML, Mondrian, Oberon, Perl, Python, RPG, Scheme и Smalltalk. Чтобы воспользо-

ваться преимуществами среды .NET, программистам, которые пишут приложения, например на языке COBOL, не придется переучиваться и с начала изучать совершенно новый язык программирования.

На рисунке 3.1 показан процесс компиляции файлов с исходным кодом.

C#

Perl

Fortran

C++

исходный код

исходный код

исходный код

исходный код

Компилятор

Компилятор

Компилятор

Компилятор

C#

Perl

Fortran

C++

MSIL и метаданные (DLL или EXE)

Рисунок 3.1. Компиляция исходного кода в управляемые модули

Для того, чтобы интегрировать совершенно различные языки необходимо учитывать их особенности. Так, например, некоторые языки не позволяют учитывать регистр символов, не допускают целые числа без знака, перегрузку операторов или не поддерживают методы с переменным числом параметров. Если требуется создать тип, доступный из других языков, то приходится задействовать

51

только те возможности языка, которые гарантированно доступны в других, поэтому Microsoft определила общеязыковую спецификацию (Common Language Specification, CLS), описывающую минимальный набор возможностей, который должен быть реализован производителями компиляторов, чтобы их компиляторы работали в CLR. На рисунке 3.2 показано, как языки реализуют подмножество возможностей CLR/CTS и расширяют возможности CLS — каждый в своей степени.

Однако, если нет необходимости в поддержке межъязыкового взаимодействия написанного кода, то можно разрабатывать очень мощные типы, ограничившись возможностями языка, потому что CLR/CTS поддерживают гораздо больше возможностей в сравнении с подмножеством, определенном CLS (это видно из рисунка 3.2).

3.1.5 Инструментальные средства разработки

Настоящим ключом к успеху в разработке программного обеспечения является наличие набора эффективных инструментальных средств разработки. Компания Microsoft уже давно предлагает инструментальные средства разработки, к числу которых принадлежат Visual C++ и Visual Basic. Платформа .NET

52

объединяет средства разработки в единую интегрированную среду, которая имеет название Visual Studio.NET.

Среда разработки Visual Studio.NET включает средства управления проектами, редактор исходного текста, конструкторы пользовательского интерфейса, помощники, компиляторы, компоновщики, инструменты, утилиты, документацию и отладчики. Она позволяет создавать приложения для 32- и 64-разрядных Windows платформ, а также новой платформы .NET Framework. Одно из важнейших усовершенствований — возможность работы с разными языками в единой среде разработки.

Среда VS.NET обладает широкими функциональными возможностями, которые могут быть использованы при создании приложения на любом языке, поддерживаемом платформой .NET. Платформа .NET позволяет использовать несколько языков программирования для написания приложений и имеет необходимые средства отладки. Среда VS.NET предоставляет множество различных конструкторов форм, баз данных и других программных элементов.

Независимые разработчики могут и в дальнейшем разрабатывать расширения среды Visual Studio.NET, а также предлагать дополнительные языки программирования и соответствующие полноценные среды разработки, поддерживаемые платформой .NET. Программы на предложенных независимыми разработчиками языках программирования смогут взаимодействовать с программами на любых языках, поддерживаемых платформой .NET. Существующий набор инструментальных средств разработки обладает широкими возможностями, которые используются при создании веб-приложений и веб-служб. Обеспечивается также всесторонняя поддержка разработки приложений с базами данных.

53

На рисунке 3.3 показан внешний вид среды Visual Studio .NET при разработке в режиме отладки.

Рисунок 3.3. Внешний вид среды разработки Visual Studio

54

3 . 2 Генератор лексических анализатор ов GPLEX

3.2.1 Описание

Gardens Point LEX (GPLEX) — это генератор лексических анализаторов, который принимает на входе «LEX-подобную» спецификацию и производит на выходе файл на языке C#. Последние версии программы практически полностью поддерживают спецификацию POSIX для LEX. В некоторых областях программа превосходит возможности LEX — например, в ней реализована поддержка Юникода.

Лексические анализаторы, производимые GPLEX, поточно-ориентирован- ны, в том смысле, что все состояния анализатора хранятся внутри экземпляра анализатора. Переменные, которые являются глобальными в традиционном LEX, являются переменными экземпляра анализатора, большинство из которых доступны только для чтения через свойства объекта.

Реализация GPLEX написана с интенсивным использованием возможностей языка C# версии 2.0.

Существует два основных способа использования GPLEX. В самом общем случае, лексический анализатор реализует или расширяет некоторые типы, определенные в синтаксическом анализаторе, от имени которого он работает.

В частности, лексические анализаторы, сгенерированные GPLEX спроектированы для использования синтаксическими анализаторами, построенными с по-

мощью Gardens Point Parser Generator (GPPG) — генераторе синтаксических ана-

лизаторов, который будет рассмотрен в разделе 3.3 «Генератор синтаксических анализаторов GPPG».

Также могут быть сгенерированы лексические анализаторы, независимые ни от какого синтаксического анализатора, и производить поиск по шаблону в потоках символов. В таком «отдельно стоящем» случае GPLEX добавляет определения соответствующих супертипов в исходный файл лексического анализатора.

Исходный код лексического анализатора происходит из трех источников. Существует неизменяемая часть, которая определяет структуру классов лексического анализатора и механизм распознавания шаблонов. Эта часть определяется

55

в так называемом «фрейм» файле («gplexx.frame»). Вторая часть содержит таблицы, которые определяют конечный автомат, производящий распознавание шаблонов, и семантические правила, которые вызываются при распознавании каждого шаблона. Эта часть создается GPLEX из входного файла «*.lex», определяемого пользователем. И, наконец, третья часть — код, определенный пользователем, который может быть внедрен во входной файл.

Важно отметить, что этот программный продукт является основой для

MPLEX «Managed Package LEX», поставляемый с Microsoft Visual Studio SDK,

который предоставляет дополнительные специфичные для Visual Studio интерфейсы.

3.2.2 Использование

Типичное использование GPLEX в простом случае состоит из двух частей. Синтаксический анализатор конструируется с помощью GPPG, вызываемого с параметром /gplex, а лексический анализатор создается с использованием GPLEX. Объект лексического анализатора всегда содержит поле «scanner» абстрактного типа IScanner.

Файл спецификации лексического анализатора будет содержать строчку:

%using ParserNamespace

где ParserNamespace — пространство имен модуля синтаксического анализатора, определенного в его спецификации. Метод Main() приложения откроет входной поток, создаст объект синтаксического анализатора и лексического анализатора, используя код, похожий на тот, что приведен ниже:

static void Main(string[] args)

{

Stream file;

//Обработать входные аргументы (args) и

//открыть входной файл

parser = new Parser(); parser.scanner = new Scanner(file); parser.Parse();

// и так далее...

}

В простых приложениях синтаксический анализатор и лексический анализатор могут перенаправлять свои сообщения об ошибках в стандартный поток консоли. Однако когда сообщения об ошибках требуется помещать в буфер для

56

дальнейшего отчета, тогда лексическому анализатору и синтаксическому анализатору нужно содержать ссылку на некоторый объект-обработчик ошибок. Если предположить, что лексический анализатор имеет поле «yyhdlr» чтобы хранить такую ссылку, то тело метода Main() будет примерно таким:

parser = new Parser(); parser.handler = new ErrorHandler(); parser.scanner = new Scanner(file);

// ссылка на однин и тот же обработчик parser.scanner.yyhdlr = parser.handler; parser.Parse(); // и так далее...

3.2.3 Интерфейсы

Весь код лексического анализатора определен в едином классе «Scanner», содержащегося в пространстве имен, определенном пользователем. Весь код, определенный пользователем помещается в этот класс. Неизменяемый код, предоставленный «фрейм»-файлом определяет несколько классов буферов, вложенных в класс лексического анализатора. Scanner.StreamBuff работает с входными байт-потоками типа System.IO.Stream, в то время как остальные работают с текстовыми файлами в различных кодировках.

Scanner.StringBuff и Scanner.LineBuff работают с входными данными типа System.String.

Для пользователя GPLEX открыты некоторые средства модуля лексического анализатора. Во-первых, есть средства, доступные синтаксическому анализатору и остальному коду приложения. К ним относятся вызовы, которые создают новые экземпляры лексического анализатора, присоединяют входной текст к лексическому анализатору, вызывают механизм распознавания токенов и получают информацию о текущей позиции и информацию о токенах.

Также существуют средства, которые видны коду семантических действий и другому коду, определенному пользователем и включенному во входной файл спецификации. К этим средствам относятся свойства текущего токена и средства доступа ко входному буферу.

Наконец, существуют средства, доступные механизму сообщения об ошибках, которые являются общими для лексического и синтаксического анализаторов.

57

Интерфейс синтаксического анализатора

Интерфейс синтаксического анализатора удовлетворяет требованиям YACC-подобных синтаксических анализаторов, генерируемых утилитой Gardens Point Parser Generator (GPPG). Следующий код иллюстрирует сигнатуру этого интерфейса:

public abstract class IScanner<YYSTYPE, YYLTYPE>

where YYLTYPE : IMerge<YYLTYPE>

{

public YYSTYPE yylval;

public YYLTYPE yylloc { get; set; } public abstract int yylex();

public virtual void yyerror(string msg, params object[] args) {}

}

Несмотря на свое имя, IScanner — это абстрактный класс, а вовсе не ин-

терфейс. Этот абстрактный класс определяет программный интерфейс приложения (API), который требует компонент времени выполнения GPPG — библиотека ShiftReduceParser.dll. Семантические действия сгенерированного синтаксического анализатора могут использовать более богатый API конкретного класса Scanner, но механизм синтаксического анализа требует только IScanner.

IScanner — это обобщенный тип с двумя параметрами типа. Первый из них, YYSTYPE — это семантический тип токенов лексического анализатора. Если грамматика не определяет семантический тип, то по умолчанию он int.

Второй параметр типа, YYLTYPE, является «типом позиции», который нужен для отслеживания текущего положения в тексте, который подвергается синтаксическому анализу. Большинство приложений либо используют типа по умолчанию (gppg.LexLocation), либо не производят отслеживание положения вооб-

ще и игнорируют это поле.

Абстрактный базовый класс определяет две переменные, с помощью которых лексический анализатор передает семантические значения и значения положения синтаксическому анализатору. Первая — это поле «yylval», которое от-

вечает за семантический тип, каким бы он ни был. Этот тип определяет синтаксический анализатор. Вторая — это свойство «yyloc» типа, определенного для

«типа позиции».

58

Первый метод класса IScanner, yylex(), возвращает порядковый номер, соответствующий следующему токену. Это абстрактный метод, который переопределяется во «фрейм»-файле.

Второй метод, низкоуровневая процедура yyerror(), вызывается механиз-

мом синтаксического анализа при восстановлении после ошибки. Этот метод включен для обратной совместимости.

Метод по умолчанию в базовом классе пуст. Код пользователя в лексическом анализаторе может переопределять yyerror(). В таком случае возможно использование сообщений об ошибках, предоставляемые ПС-анализатором (анализатором типа «перенос-свертка» — «shift-reduce parser», известный также как «восходящий синтаксический анализ»). Как альтернатива, низкоуровневый метод yyerror() может быть полностью проигнорирован, использованы сообщения об ошибках, явно созданные семантическими действиями синтаксического анализатора и лексического анализатора. В этом случае действия используют класс ErrorHandler, объекты позиции типа YYLTYPE и числовые коды ошибок. В большинстве случаев, это наиболее предпочтительный подход, так как это позволяет перевести сообщения об ошибках на родной для пользователя язык.

Все генерируемые GPPG синтаксические анализаторы определяют абстрактный класс-обертку, который реализует обобщенный класс IScanner с па-

раметрами типа, заключенными в «*.y» файле, какими бы они ни были. Этот класс называется ScanBase.

Класс лексического анализатора расширяет ScanBase и объявляет откры-

тое поле типа ScanBuff. ScanBuff — это абстрактный базовый класс потока и строковых буферов лексических анализаторов. Важными особенностями этого класса, открытыми для пользователя, являются свойство, позволяющее устанавливать и запрашивать позицию буфера, и возможность создания строк, соответствующих всему тексту, находящемуся между заданными позициями буфера. Свойство Pos возвращает текущую позицию нижележащего входного потока.

Свойство ReadPos возвращает позицию текущего символа в потоке. Для некото-

рых типов потоков текста оно не просто связано с текущем значением Pos.

Следующий фрагмент кода иллюстрирует возможности класса Scanner.

59

public abstract class Scanner : Parser.ScanBase

{

public ScanBuff buffer;

public void SetSource(string s, int ofst);

...

}

public abstract class ScanBuff

{

...

public abstract int Pos { get; set; } public abstract int ReadPos { get; }

public abstract string GetString(int begin, int end);

}

Метод SetSource присоединяет новый текстовый буфер к текущему экзем-

пляру лексического анализатора с текстом «s» и с началом позиции для разбора со смещением «ofst».

Последние важные открытые свойства лексических анализаторов — это конструкторы. Существует два конструктора, определенных во «фрейм»-файле. Код пользователя также может объявлять и собственные, если это требуется. Конструктор по умолчанию без параметров создает экземпляр лексического анализатора, который изначально не имеет буфера. Другой конструктор принимает параметр типа System.IO.Stream и создает буфер потока, который инициали-

зируется передаваемым потоком.

Внутренний API лексического анализатора

Семантические действия и код пользователя в лексическом анализаторе имеют доступ ко всем средствам супертипов IScanner и ScanBase. «Фрейм»- файл предоставляет дополнительные методы:

public string yytext {

get; } // текст текущего токена

int yyleng { get; } //

длина текущего токена

int yypos { get; } //

позиция буфера в начале токена

int yyline { get; } //

номер строки

в начале токена

int yycol { get; } //

номер столбца

в начале токена

void yyless(int n); //

перемещает входную позицию на

//yypos + n

 

internal void BEGIN(int next);

yytext в StdOut

internal void ECHO();

// записывает

internal int YY START

{ get; set; }

// Читает и

 

//устанавливает стартовое условие

60

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]