Справочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией
Скачать 5.05 Mb.
|
726 Часть III. Применение языка C# // Получаем значение числа или переменной. void Atom(out double result) { switch(tokType) { case Types.NUMBER: try { result = Double.Parse(token); } catch (FormatException) { result = 0.0; SyntaxErr(Errors.SYNTAX); } GetToken(); return; case Types.VARIABLE: result = FindVar(token); GetToken(); return; default: result = 0.0; SyntaxErr(Errors.SYNTAX); break; } } // Возвращаем значение переменной. double FindVar(string vname) { if(Char.IsLetter(vname[0]) ) { SyntaxErr(Errors.SYNTAX); return 0.0; } return vars[Char.ToUpper(vname[0])-'A']; } // Возвращаем лексему во входной поток. void PutBack() { for(int i=0; i < token.Length; i++) expIdx--; } // Обрабатываем синтаксическую ошибку. void SyntaxErr(Errors error) { string[] err = { "Синтаксическая ошибка", "Дисбаланс скобок", "Выражение отсутствует", "Деление на нуль" }; throw new ParserException(err[(int)error]); } // Получаем следующую лексему. void GetToken() { tokType = Types.NONE; token = ""; Глава 26. Синтаксический анализ методом рекурсивного спуска 727 if(expIdx == exp.Length) return; // Конец выражения. // Опускаем пробел. while(expIdx < exp.Length && Char.IsWhiteSpace(exp[expIdx])) ++expIdx; // Хвостовой пробел завершает выражение. if(expIdx == exp.Length) return; if(IsDelim(exp[expIdx])) { // Это оператор? token += exp[expIdx]; expIdx++; tokType = Types.DELIMITER; } else if(Char.IsLetter(exp[expIdx])) { // Это // переменная? while(!IsDelim(exp[expIdx])) { token += exp[expIdx]; expIdx++; if(expIdx >= exp.Length) break; } tokType = Types.VARIABLE; } else if(Char.IsDigit(exp[expIdx])) { // Это число? while(!IsDelim(exp[expIdx])) { token += exp[expIdx]; expIdx++; if(expIdx >= exp.Length) break; } tokType = Types.NUMBER; } } // Метод возвращает значение true, // если с — разделитель. bool IsDelim(char c) { if((" +-/*%^=()".IndexOf(c) != -1)) return true; return false; } } Чтобы опробовать этот усовершенствованный анализатор, используйте ту же программу, которую мы применяли для запуска упрошенного варианта. Но теперь можно вводить выражения, подобные следующим: А = 10/4 А - В C = А * (F - 21) 728 Часть III. Применение языка C# Синтаксический контроль в рекурсивном нисходящем анализаторе В процессе анализа выражений под синтаксической ошибкой понимается ситуация, когда входное выражение не соответствует правилам функционирования анализатора. В большинстве случаев имеет место ошибка оператора — обычно это просто опечатка (ошибка, допускаемая при вводе с клавиатуры). Например, следующие выражения недействительны для анализаторов, представленных в этой главе: 10 ** 8 ((10 - 5) * 9 /8 Первое выражение содержит два оператора рядом, во втором — дисбаланс скобок, а в последнем знак деления стоит в начале выражения. Все эти ситуации недопустимы для анализатора. Поскольку синтаксические ошибки могут “спровоцировать” анализатор на выдачу неверных результатов, необходимо позаботиться о защите от них. При изучении кода анализатора вы, вероятно, обратили внимание на метод SyntaxErr() , который вызывается при определенных обстоятельствах. В отличие от других типов анализаторов, в рекурсивно-нисходящем используется простой контроль синтаксиса, который реализован в методах Atom() , FindVar() или EvalExp6() , где проверяется баланс скобок. При вызове метода SyntaxErr() генерируется исключение типа ParserException , которое содержит описание ошибки. Это исключение перехватывается в методе Evaluate() . Следовательно, при обнаружении ошибки работа анализатора немедленно останавливается. При необходимости такое поведение можно изменить. Что еще можно сделать Как упоминалось выше в этой главе, в анализаторе предусмотрена проверка ошибок лишь в минимальном диапазоне. Возможно, вы хотели бы детализировать описание ошибок, например, выделять в выражении позицию, в которой обнаружена ошибка. Это позволило бы быстро находить и исправлять ошибки. Приведенный здесь анализатор предназначен для вычисления только числовых выражений. Но, внеся определенные дополнения, можно “научить” его вычислять другие типы выражений, обрабатывать строки, пространственные координаты или комплексные числа. Например, чтобы анализатор мог обрабатывать строковые объекты, необходимо внести следующие изменения: ■ определить новый тип лексемы STRING ; ■ усовершенствовать метод GetToken() , чтобы он мог распознавать строки; ■ добавить новую case-ветвь в методе Atom() для обработки лексем типа STRING После реализации этих действий анализатор сможет обрабатывать строковые выражения, подобные следующим: а = "стерео" b = "звучание" c = а + b В результате строка с должна содержать конкатенацию строк а и b , те, "стереозвучание". Глава 26. Синтаксический анализ методом рекурсивного спуска 729 Предлагаем вам неплохое применение для анализатора: создайте простой всплывающий мини-калькулятор, который принимает вводимое пользователем выражение и отображает результат. Такой калькулятор будет прекрасным дополнением почти к любому коммерческому приложению. Наконец, попробуйте преобразовать класс Parser в компонент. Это совсем нетрудно сделать. Сначала сделайте класс Parser производным от класса Component Затем реализуйте метод Dispose(bool) . И все! После этого калькулятор будет доступным для любого приложения. Полный справочник по Приложения Создание языка C# Полный справочник по Приложение А Краткий обзор языка комментариев XML Приложение A. Краткий обзор языка XML 733 зык C# поддерживает три типа комментариев. Первые два характеризуются символами // и /* */. Третий тип основан на XML-тегах и называется XML- комментарием. (XML-комментарии также называется комментариями документации.) Каждая строка XML-комментария начинается с символов ///, XML-комментариями обычно предваряется определение классов, пространств имен, методов, свойств и событий. Используя XML-комментарии, можно встраивать информацию о программе в саму программу. При компиляции такой программы вы получите XML-комментарии собранными в XML-файле. XML-комментарии можно утилизировать с помощью средства IntelliSense системы Visual Studio. Теги языка комментариев XML C# поддерживает теги XML-документации, представленные в табл. A.1. Назначение большинства из них можно понять по описанию, да и работают они подобно другим XML- тегам, с которыми многие программисты уже знакомы. Однако тег
(<список>) несколько сложнее других. Список содержит два компонента: заголовок списка и элементы списка. Базовый формат заголовка списка такой: Здесь текст описывает имя. Для таблицы элемент текст не используется. Базовый формат элемента списка таков: Здесь текст описывает имя_элемента . Для маркированных или нумерованных списков или таблиц элемент имя_элемента не используется. Можно использовать несколько тегов 734 Часть IV. Приложения Окончание табл. A.1 Тег Описание текст Определяет абзац текста в другой теге ' имя_параметра ' > трактовка Описывает параметр, заданный элементом имя_параметра . Описание содержится в тексте, соответствующем элементу трактовка name = " имя_параметра " /> Означает, что элемент имя_параметра представляет собой имя параметра " идентификатор "> трактовка Описывает параметр разрешения, связанный с членами класса, заданными элементом идентификатор Параметры разрешения описаны в тексте, соответствующем элементу трактовка трактовка Текст, заданный элементом трактовка , представляет собой общие комментарии, которые часто используются для описания класса или структуры трактовка Текст, заданный элементом трактовка , описывает значение, возвращаемое методом идентификатор " /> Объявляет ссылку на другой элемент, заданный элементом идентификатор идентификатор " /> Объявляет перекрестную ссылку типа "см. также" на идентификатор трактовка Текст, заданный элементом трактовка , представляет собой общие комментарии, которые часто используются для описания метода или другого члена класса трактовка Текст, заданный элементом трактовка , описывает свойство Компиляция XML-документа Чтобы создать XML-файл, который содержит комментарии к документу, задайте опцию /doc . Например, чтобы скомпилировать файл DocTest.cs , содержащий XML- комментарии, используйте такую командную строку: csc DocTest.cs /doc:DocTest.xml Чтобы создать выходной XML-файл при использовании интегрированной среды Visual Studio IDE, необходимо использовать диалоговое окно Property Pages (Страницы свойств), которое активизируется при выборе команды View , Property Pages (Вид, Страницы свойств). Затем выберите команду Configuration Properties ,Build (Свойства конфигурации , Построить). После этого укажите имя XML-файла в свойстве XML Documentation File (XML-файл документации). Пример XML-документа Рассмотрим пример использования XML-комментариев: // Пример XML-документа. using System; Приложение A. Краткий обзор языка XML 735 /// /// Это пример XML-документа. /// В классе Test показано использование ряда тегов. /// /// /// Выполнение начинается с метода Main(). /// Console.WriteLine("Сумма последовательных " + 5 + " чисел равна " + sum); } /// /// Метод Summation() возвращает сумму ряда чисел. /// /// Последнее слагаемое передается в параметре val. /// /// /// /// Результат возвращается как int-значение. /// /// += i; return result; } } Предположим, что приведенная выше программа называется XmlTest.cs . С помощью следующей строки csc XmlTest.cs /doc:XmlTest.xml эту программу можно скомпилировать, а в результате компиляции будет создан файл XmlTest.xml , который должен содержать следующие комментарии: Это пример XML-документа. В классе Test показано использование ряда тегов. Выполнение начинается с метода Main(). 736 Часть IV. Приложения Метод Summation() возвращает сумму ряда чисел. name="val"> Последнее слагаемое передается в параметре val. Результат возвращается как int-значение. Обратите внимание на то, что каждому документированному элементу присваивается уникальный идентификатор. Эти идентификаторы могут использовать другие программы, которые включают XML-комментарии. Полный справочник по Приложение Б C# и робототехника 738 Часть IV. Приложения воим хобби я считаю робототехнику Много лет тому назад это было также моей работой, поскольку я разрабатывал и внедрял язык управления промышленными роботами Мне было очень интересно заниматься роботами, потому что они оживляли логику программ, которые мы писали Кроме того, они взаимодействовали с реальным миром Несмотря на то что в течение долгого времени я уже не сталкивался с робототехникой на профессиональном уровне, эта область всегда оставалась для меня очень важной и волнующей И здесь я вспомнил о своем давнем увлечении по той простой причине, что язык C# предлагает специалистам в области подготовки программ для роботов воспользоваться некоторыми преимуществами Обычно, когда говорят о программах управления роботами, подразумевают высокоэффективные процедуры, написанные на языке C++ Но C# может изменить это устоявшееся мнение Дело в том, что программы управления роботами часто имеют огромный размер и содержат множество таких подсистем, как дистанционное управление, искусственное (техническое) зрение, распознавание образов, управление двигателем и т.д. Эти подсистемы можно организовать (и реализовать) в виде коллекции C#-компонентов Применение компонентов к программированию роботов поможет преодолеть сложность, которая прежде была присуща программам, создаваемым в этой области Компоненты позволят также легко изменять подсистемы и модернизировать их Если вам близка тема робототехники (особенно, если вы занимаетесь созданием собственного робота), то робот, показанный на рис Б 1, может вас заинтересовать Это мой тестовый робот И интересен он вот чем Во-первых, он содержит встроенный микропроцессор, который обеспечивает базовое управление двигателем и сенсорную обратную связь Во-вторых, он содержит приемопередатчик RS-232, который используется для получения инструкций от главного компьютера и возвращения результатов Такая организация позволяет удаленному компьютеру выполнять интенсивную обработку данных (и это помимо того, чем нагружен сам робот) В-третьих, он содержит видеокамеру, которая связана с беспроводным видеопередатчиком Рис Б 1 Простои, но действующий тестовый робот С Приложение Б. C# и робототехника 739 Этот робот создан на базе ходовой части танка Hobbico M1 Abrams R/C. (Я обнаружил, что шасси модели R/C танков и автомобилей можно успешно использовать для робота.) Из танка была убрана большая часть внутрикорпусных устройств, включая приемник (ресивер) и устройство переключения передач, но оставлены двигатели. Танк Hobbico прекрасно подходит для платформы робота благодаря его устойчивости и отличным двигателям; он может перевозить большой груз, а гусеницы не дают ему опрокинуться. Кроме того, благодаря гусеницам, робот обладает нулевым радиусом поворота и может перемещаться по неровной поверхности. Длина ходовой части около 18, а ширина — около 8 дюймов. К пустой ходовой части я добавил детали. Для обеспечения автономного управления я использовал микропроцессор BASIC Stamp 2, который отличается простотой и мощностью (фирма-изготовитель— Parallax, Inc. ( www.parallaxinc.com ). Приемопередатчик RS-232, видеокамера и радиопередатчик также от компании Parallax. Как радиопередатчик RS-232, так и видеопередатчик имеют диапазон покрытия около 300 футов. Я также добавил для танкового двигателя электронные регуляторы скорости, которые управляются микропроцессором BASIC Stamp. Рассмотрим теперь, как функционирует робот. Удаленный компьютер запускает основную программу управления роботом. Эта программа отрабатывает такие “тяжелые” подсистемы, как техническое зрение, дистанционное управление и пространственная ориентация. Она также может запомнить последовательность действий, а затем повторить их. Удаленный компьютер передает роботу команды управления перемещением (через радиосвязь RS-232). Микропроцессор BASIC Stamp принимает эти команды и выполняет соответствующие действия. Например, при получении команды “вперед” микропроцессор BASIC Stamp посылает соответствующие сигналы электронным регуляторам скорости, связанным с двигателями. После выполнения команды робот возвращает код подтверждения приема. Таким образом, между удаленным компьютером и роботом имеется двунаправленную связь, благодаря которой робот может подтверждать успешное выполнение каждой команды. Поскольку основная обработка данных по роботу выполняется в удаленном компьютере, на объем обрабатываемых данных не налагается строгих ограничений. Например, на момент написания книги робот мог следить за объектом с помощью системы технического зрения. Реализация этой возможности требует обработки довольно большого объема данных, которую было бы трудно перенести на микропроцессор робота. Насколько мне известно, большинство программ управления роботами по-прежнему пишется на языке C++. Но как только у меня появится свободное время, я обязательно займусь их переводом на C#. И начать эту работу я планирую с подсистемы, которая повторяет заданную последовательность команд. Эту “списочную” задачу нетрудно решить, опираясь на соответствующую C#-коллекцию. |