ВКР. Учебно-методическое пособие Тольятти тгу 2011 удк 004 3(075) ббк. Учебнометодическое пособие по дисциплине Языки программирования предназначено для студентов очной формы обучения и содержит конспект лекций по ключевым темам курса и практикум
Скачать 0.88 Mb.
|
2КУРС ЛЕКЦИЙ2.1Языки программирования высокого уровняРазвитие вычислительной техники сопровождается созданием новых и совершенствованием существующих средств общения программистов с электронными вычислительными машинами – языков программирования. Под языком программирования понимают правила представления данных и записи алгоритмов их обработки, которые автоматически выполняются ЭВМ. В более абстрактном виде язык программирования является средством создания программных моделей объектов и явлений внешнего мира. К настоящему времени созданы тысячи различных языков программирования – от самых примитивных до близких к естественному языку человека. Чтобы разобраться во всём многообразии языков программирования, нужно знать их классификацию, а также историю создания, эволюцию и тенденции развития. 2.1.1Эволюция языков программированияЧтобы понимать тенденции развития языков программирования, нужно знать движущие силы их эволюции. Для выяснения этого вопроса будем рассматривать языки программирования с различных точек зрения. Во-первых, язык программирования является инструментом программиста для создания программ. Для создания хороших программ нужны хорошие языки программирования. Поэтому одной из движущих сил эволюции языков программирования является стремление разработчиков к созданию более совершенных программ. Во-вторых, процесс разработки программы можно сравнить с промышленным производством, в котором определяющими факторами являются производительность труда коллектива программистов, себестоимость и качество программной продукции. Создаются различные технологии разработки программ (структурное, модульное, объектно-ориентированное программирование и другие), которые должны поддерживаться языками программирования. Поэтому второй движущей силой эволюции языков программирования является стремление к повышению эффективности процесса производства программной продукции. В-третьих, программы можно рассматривать как аналог радиоэлектронных устройств обработки информации, в которых вместо радиодеталей и микросхем используют конструкции языка программирования (элементная база программы). Как и электронные устройства, программы могут быть простейшими и очень сложными, при этом уровень инструмента должен соответствовать сложности изделия. Кроме того, человеку удобнее описывать моделируемый объект в терминах предметной области, а не языком цифр. Поэтому третьей движущей силой, ведущей к созданию новых, специализированных, ориентированных на проблемную область и более мощных языков программирования, является увеличение разнообразия и повышение сложности задач, решаемых с помощью ЭВМ. В-четвёртых, совершенствование самих ЭВМ приводит к необходимости создания языков программирования, максимально реализующих новые возможности ЭВМ. В-пятых, программы являются интеллектуальным продуктом, который нужно накапливать и приумножать. Но программы, как и технические устройства, обладают свойством морального старения, одной из причин которого является их зависимость от типа ЭВМ и операционной среды. С моральным старением программ борются путём их модернизации и выпуска новых версий, однако при высокой динамике смены типов ЭВМ и операционных сред разработчики будут только тем и заниматься, что модернизировать старые программы. Поэтому, язык программирования должен обеспечивать продолжительный жизненный цикл программы, и стремление к этому является пятой движущей силой развития языков программирования. Известно, что первым программистом была женщина – леди Ада Лавлейс, дочь поэта лорда Байрона. Она разрабатывала программы для одного из первых механических компьютеров, созданного в начале XIX века английским учёным Чарльзом Беббиджом. Однако настоящее программирование в современном понимании началось с момента создания первой ЭВМ. Тем не менее, имя этой замечательной женщины – Ada – присвоено одному из самых мощных современных языков программирования, который является базовым для министерства обороны США. Первые компьютеры, созданные человеком, имели небольшой набор команд и встроенных типов данных, но позволяли выполнять программы на машинном языке. Машинный язык – единственный язык, понятный ЭВМ. Он реализуется аппаратно: каждую команду выполняет некоторое электронное устройство. Программа на машинном языке представляет собой последовательность команд и данных, заданных в цифровом виде. Например, команда вида 1А12 в 16-ричном виде или 0001101000010010 в двоичном виде означает операцию сложения (1А) содержимого регистров 1 и 2. Данные на машинном языке представлены числами и символами. Операции являются элементарными, и из них строится вся программа. Ввод программы в цифровом виде производился непосредственно в память с пульта ЭВМ либо с примитивных устройств ввода. При этом процесс программирования был очень трудоёмким, разобраться в программе даже автору было довольно сложно, а эффект от применения ЭВМ был довольно низким. Этот этап в развитии языков программирования показал, что программирование является сложной проблемой, трудно поддающейся автоматизации, но именно программное обеспечение определяет в итоге эффективность применения ЭВМ. Поэтому на всех последующих этапах усилия направлялись на совершенствование интерфейса между программистом и ЭВМ – языка программирования. Стремление программистов оперировать не цифрами, а символами, привело к созданию мнемонического языка программирования, который называют языком ассемблера, мнемокодом, автокодом. Этот язык имеет определенный синтаксис записи программ, в котором, в частности, цифровой код операции заменен мнемоническим кодом. Например, команда сложения записывается в виде AR 1,2 и означает сложение (Addition) типа регистр-регистр (Register) для регистров 1 и 2. Теперь программа имеет более наглядную форму, но её не понимает ЭВМ. Поэтому понадобилось создать специальную программу – транслятор, который преобразует программу с языка ассемблера на машинный язык. Эта проблема потребовала, в свою очередь, глубоких научных исследований и разработки различных теорий, например теорию формальных языков, которые легли в основу создания трансляторов. Практически любой класс ЭВМ имеет свой язык ассемблера. На сегодняшний день язык ассемблера используется для создания системных программ, использующих специфические аппаратные возможности данного класса ЭВМ. Следующий этап характеризуется созданием языков высокого уровня. Эти языки являются универсальными (с их помощью можно создавать любые прикладные программы) и алгоритмически полными, имеют более широкий спектр типов данных и операций, поддерживают технологии программирования. Принципиальными отличиями языков высокого уровня от языков низкого уровня являются: - использование переменных; - возможность записи сложных выражений; - расширяемость типов данных за счет конструирования новых типов из базовых; - расширяемость набора операций за счёт подключения библиотек подпрограмм; - слабая зависимость от типа ЭВМ. С усложнением языков программирования усложняются и программы для работы с ними. Теперь в набор инструментов программиста помимо транслятора входит текстовый редактор для ввода текста программ, отладчик для устранения ошибок, библиотекарь для создания библиотек программных модулей и множество других служебных программ. Комплекс этих программ называется системой программирования. Наиболее яркими представителями языков высокого уровня являются FORTRAN, PL/1, Pascal, C, Basic, Ada. Может возникнуть вопрос: почему создано столько различных языков одного класса? Почему нельзя создать один язык на все случаи жизни? Ответ на этот вопрос может быть таким же, как и на вопрос о различных языках народов мира: так уж получилось. Каждый из разработчиков языков высокого уровня стремился создать лучший и самый универсальный язык, который позволял бы быстро получать самые эффективные, надёжные и безошибочные программы. Однако в процессе этого поиска выяснилось, что дело не в самом языке, а в технологии его использования. Поэтому дальнейшее развитие языков стало определяться новыми технологиями программирования. Одновременно с развитием универсальных языков высокого уровня стали развиваться проблемно-ориентированные языки программирования, которые решали экономические задачи (COBOL), задачи реального времени (Modula-2, Ada), символьной обработки (Snobol), моделирования (GPSS, Simula, SmallTalk), численно-аналитические задачи (Analitic) и другие. Эти специализированные языки позволяли более адекватно описывать объекты и явления реального мира, приближая язык программирования к языку специалиста в проблемной области. Другим направлением развития языков программирования является создание языков сверхвысокого уровня. На языке высокого уровня программист задаёт алгоритм (процедуру) получения результата по известным исходным данным, поэтому они называются процедурными языками программирования. На языке сверхвысокого уровня программист задаёт отношения между объектами в программе, например систему линейных уравнений, и определяет, что нужно найти, но не задаёт как получить результат. Такие языки еще называют непроцедурными, так как сама процедура поиска решения встроена в язык. Такие языки используются для решения задач искусственного интеллекта (Lisp, Prolog), позволяя моделировать мыслительную деятельность человека в процессе поиска решений. К непроцедурным языкам относят и языки запросов систем управления базами данных (QBE, SQL). 2.1.2Классификация языков программированияЯзыки программирования можно классифицировать по следующим признакам. По степени ориентации на специфические возможности ЭВМ языки программирования делятся на машинно-зависимые и машинно-независимые. К машинно-зависимым языкам программирования относятся машинные языки, языки ассемблера и автокоды, которые используются в системном программировании. Программа на машинно-зависимом языке программирования может выполняться только на ЭВМ данного типа. Программа на машинно-независимом языке программирования после трансляции на машинный язык становится машинно-зависимой. Этот признак языка программирования определяет мобильность получаемых программ (возможность переноса на ЭВМ другого типа). По степени детализации алгоритма получения результата языки программирования делятся на языки низкого уровня, языки высокого уровня и языки сверхвысокого уровня. По степени ориентации на решение определенного класса задач языки делятся на проблемно-ориентированные и универсальные. По возможности дополнения новыми типами данных и операциями различают расширяемые и нерасширяемые языки. По возможности управления реальными объектами и процессами выделяют языки систем реального времени и языки систем условного времени. По способу получения результата языки программирования делятся на процедурные и непроцедурные. В свою очередь непроцедурные языки по типу встроенной процедуры поиска решений делятся на реляционные, функциональные и логические. По типу решаемых задач различают языки системного программирования и языки прикладного программирования. Рассмотренная схема классификации позволяет каждому языку программирования присвоить один из признаков каждого класса и позволяет сделать вывод о том, что языки программирования обладают определённой специализацией. Поэтому рассмотрим тенденции развития классов языков программирования. Языки системного программирования, на которых создаются операционные системы, трансляторы и другие системные программы, развиваются в направлении повышения их уровня и независимости от ЭВМ. На сегодняшний день почти 90% системного программного обеспечения создается не на языке ассемблера, а на языке Си. Например, операционная система Unix практически полностью написана на Си. Язык Си позволяет получать программы, сравнимые по своей эффективности с программами, написанными на языке ассемблера. При этом объём программ получается больше, но зато эффективность их создания гораздо выше. Машинная независимость достигается использованием стандарта языка, поддерживаемого всеми разработчиками трансляторов, и использованием так называемых кросс-систем для эквивалентного преобразования программ с одного языка низкого уровня на другой. Другим направлением является повышение уровня самого машинного языка. Например, известны LISP-машины, в которых машинным языком является язык LISP (реализован аппаратно). Другим примером являются ЭВМ пятого поколения с машинным языком искусственного интеллекта Пролог. Языки высокого уровня развиваются в направлении поддержки технологий программирования, обеспечения низкоуровневых операций (уровня ассемблера), обеспечения новых информационных технологий и независимости от среды реализации. Следует сказать, что по своим возможностям языки высокого уровня постепенно сближаются и программисту на Си всё труднее становится спорить о преимуществах языка Си с программистом, работающим на языке Basic. Тотальный бум переживает технология объектно-ориентированного программирования: практически все современные языки высокого уровня поддерживают объектно-ориентированное программирование. Да и все современные программные системы построены на принципах объектно-ориентированного программирования, и сегодня каждый программирующий студент знает, что такое инкапсуляция, наследование и полиморфизм. Для обозначения факта поддержки объектно-ориентированного программирования языки получают приставку Object (например, ObjectPascal) или другие (например, C++). Операционные системы, сети ЭВМ, серверы, базы данных и Internet оказывают сильнейшее влияние на современные языки программирования. Разработчики языков программирования просто обязаны включать в языки средства поддержки новых информационных технологий, чтобы привлечь программистов на свою сторону. Для поддержки оконного интерфейса Windows создаются системы визуального программирования с приставкой Visual, например Visual C++, Visual Basic и др. Для работы с базами данных, сетями и Internet в языки программирования включаются специальные внутренние или внешние средства. Стремление к созданию программ, независимых от типа ЭВМ и операционной системы, привело к созданию языка Java. Основная задача Java – обеспечить выполнение программ, распространяемых через Web-страницы Internet, на любой рабочей станции. Кроме того, Java поддерживает все средства новых информационных технологий и в ближайшее время, очевидно, станет самым популярным языком программирования. Популярность языков искусственного интеллекта за последние 10 лет, к сожалению, заметно упала. Это может быть связано с психологическими проблемами, которые испытывают программисты при использовании этих языков. Например, в мощнейшем языке LISP программа имеет очень сложную для понимания списочную структуру и небольшой по объёму проект быстро выходит из-под контроля. В языке Prolog программист должен точно знать логику работы встроенной машины логического вывода, а работа программы зависит от структуры и содержимого базы знаний. Если с проектированием программы и структуры базы знаний программист справляется, то для заполнения базы он должен быть экспертом в предметной области либо тесно контактировать с экспертом и извлекать из него знания, а то и другое является сложной задачей. Поэтому необходимы дополнительные обеспечивающие средства для возврата популярности этих языков. Изучение вопросов эволюции языков программирования призвано облегчить программисту выбор языка для решения определенных задач. Однако следует осознавать, что не нужно изучать все существующие языки программирования – достаточно изучать по одному языку каждого класса по мере необходимости, так как в процессе эволюции все языки одного класса сближаются. 2.1.3Структуры и типы данных языка программированияСтруктуры данных служат теми материалами, из которых строятся программы. Более того, сам компьютер состоит из структур данных. Встроенные структуры данных представлены теми регистрами и элементами памяти, где хранятся двоичные величины. Поэтому в основе работы всякого компьютера лежит умение оперировать только с одним видом данных – с отдельными битами, или двоичными цифрами. Работает с этими данными компьютер только в соответствии с неизменным набором алгоритмов, которые определяются системой команд центрального процессора. Задачи, решаемые с помощью компьютера, редко выражаются на языке битов. Как правило, данные имеют форму чисел, литер, текстов, символов и более сложных структур типа последовательностей, списков и деревьев. Ещё разнообразнее алгоритмы, применяемые для решения различных задач; фактически алгоритмов не меньше чем вычислительных задач. Для точного описания абстрактных структур данных в языках программирования смысл всякого предложения определяется точно и однозначно. Среди средств, представляемых почти всеми языками программирования, имеется возможность ссылаться на структуру данных, пользуясь присвоенным ей именем, или, иначе, идентификатором. Одни именованные величины являются константами, которые сохраняют постоянное значение в той части программы, где они определены, другие – переменными, которым с помощью оператора в программе может быть присвоено новое значение в определённом с помощью типа данных диапазоне. До тех пор, пока программа не начала выполняться, значение переменных не определено. Имя константы или переменной помогает программисту, но компьютеру оно ни о чём не говорит. Компилятор, транслирующий текст программы в двоичный код, связывает каждый идентификатор с определенным адресом памяти. Для того чтобы компилятор смог это выполнить, нужно сообщить о «типе» каждой именованной величины. Человек, решающий какую-нибудь задачу «вручную», обладает интуитивной способностью быстро разобраться в типах данных и тех операциях, которые для каждого типа справедливы. Например, нельзя извлечь квадратный корень из слова или написать число с заглавной буквы. Одна из причин, позволяющих легко провести такое распознавание, заключается в том, что слова, числа и другие обозначения выглядят по-разному. Однако для компьютера все типы данных сводятся в конечном счёте к последовательности битов, поэтому различие в типах следует делать явным. Типы данных, принятые в языках программирования, включают натуральные и целые числа, вещественные числа (в виде приближенных десятичных дробей), литеры, строки и т.п. В некоторых языках программирования тип каждой константы или переменной определяется компилятором по записи присваиваемого значения: наличие десятичной точки, например, может служить признаком вещественного числа. В других языках требуется, чтобы программист явно задал тип каждой переменной, и это даёт одно важное преимущество. Хотя при выполнении программы значение переменной может многократно меняться, тип её меняться не должен никогда. Это значит, что компилятор может проверить операции, выполняемые над этой переменной, и убедиться в том, что все они согласуются с описанием типа переменной. Такая проверка может быть проведена путём анализа всего текста программы, и в этом случае она охватит все возможные действия, определяемые данной программой. В зависимости от назначения языка программирования защита типов, осуществляемая на этапе компиляции, может быть более или менее жёсткой. Так, например, язык PASCAL, изначально являвшийся, прежде всего, инструментом для иллюстрирования структур данных и алгоритмов, сохраняет от своего первоначального назначения весьма строгую защиту типов. PASCAL-компилятор в большинстве случаев расценивает смешение в одном выражении данных разных типов или применение к типу данных несвойственных ему операций как фатальную ошибку. Напротив, язык Си, предназначенный, прежде всего, для системного программирования, является языком с весьма слабой защитой типов. Си-компиляторы в таких случаях лишь выдают предупреждения. Отсутствие жёсткой защиты типов даёт системному программисту, разрабатывающему программу на языке Си, дополнительные возможности, но такой программист сам отвечает за правильность своих действий. Структура данных относится, по существу, к «пространственным» понятиям: её можно свести к схеме организации информации в памяти компьютера. Структуры данных, используемые в языках программирования, могут быть чрезвычайно сложными. В результате выбор правильного представления данных часто является ключом к удачному программированию и может в большей степени сказываться на производительности программы, чем детали используемого алгоритма. Вряд ли в будущем появится общая теория выбора структур данных. Самое лучшее, что можно сделать, – это разобраться во всех базовых «кирпичиках» и в собранных из них структурах. Способность приложить эти знания к конструированию больших систем – это, прежде всего, дело инженерного мастерства и практики. Под структурой данных в общем случае понимают множество элементов данных и связей между ними. Такое определение охватывает все возможные подходы к структуризации данных, но в каждой конкретной задаче используются те или иные его аспекты. Поэтому вводится дополнительная классификация структур данных, направления которой соответствуют различным аспектам их рассмотрения. Прежде чем приступать к изучению конкретных структур данных, дадим их общую классификацию по нескольким признакам. Понятие «физическая структура данных» отражает способ физического представления данных в памяти машины и называется еще структурой хранения, внутренней структурой или структурой памяти. Рассмотрение структуры данных без учёта её представления в машинной памяти называется абстрактной или логической структурой. В общем случае между логической и соответствующей ей физической структурами существует различие, степень которого зависит от самой структуры и особенностей той среды, в которой она должна быть отражена. Вследствие этого различия существуют процедуры, осуществляющие отображение логической структуры в физическую и, наоборот, физической структуры в логическую. Эти процедуры обеспечивают, кроме того, доступ к физическим структурам и выполнение над ними различных операций, причём каждая операция рассматривается применительно к логической или физической структуре данных. Различаются простые (базовые, примитивные) структуры (типы) данных и интегрированные (структурированные, композитные, сложные). Простыми называются такие структуры данных, которые не могут быть расчленены на составные части, большие, чем биты. С точки зрения физической структуры важным является то обстоятельство, что в данной машинной архитектуре, в данной системе программирования мы всегда можем заранее сказать, каков будет размер данного простого типа и какова структура его размещения в памяти. С логической точки зрения простые данные являются неделимыми единицами. Интегрированными называются такие структуры данных, составными частями которых являются другие структуры данных – простые или в свою очередь интегрированные. Интегрированные структуры данных конструируются программистом с использованием средств интеграции данных, предоставляемых языками программирования. В зависимости от отсутствия или наличия явно заданных связей между элементами данных следует различать несвязные структуры (векторы, массивы, строки, стеки, очереди) и связные структуры (связные списки). Весьма важный признак структуры данных – её изменчивость – изменение числа элементов и (или) связей между элементами структуры. В определении изменчивости структуры не отражён факт изменения значений элементов данных, поскольку в этом случае все структуры данных имели бы свойство изменчивости. По признаку изменчивости различают структуры статические, полустатические, динамические. Классификация структур данных по признаку изменчивости приведена на рис. 1. Базовые структуры данных, статические, полустатические и динамические характерны для оперативной памяти и часто называются оперативными структурами. Файловые структуры соответствуют структурам данных для внешней памяти. Важный признак структуры данных – характер упорядоченности её элементов. По этому признаку структуры можно делить на линейные и нелинейные структуры. В зависимости от характера взаимного расположения элементов в памяти линейные структуры можно разделить на структуры с последовательным распределением элементов в памяти (векторы, строки, массивы, стеки, очереди) и структуры с произвольным связным распределением элементов в памяти (односвязные, двусвязные списки). Пример нелинейных структур – многосвязные списки, деревья, графы. В языках программирования понятие «структуры данных» тесно связано с понятием «типы данных». Любые данные, т.е. константы, переменные, значения функций или выражения, характеризуются своими типами. Рис. 1. Классификация структур данных Информация по каждому типу однозначно определяет: 1) структуру хранения данных указанного типа, т.е. выделение памяти и представление данных в ней, с одной стороны, и интерпретирование двоичного представления, с другой; 2) множество допустимых значений, которые может иметь тот или иной объект описываемого типа; 3) множество допустимых операций, которые применимы к объекту описываемого типа. Над любыми структурами данных могут выполняться четыре общие операции: создание, уничтожение, выбор (доступ), обновление. Операция создания заключается в выделении памяти для структуры данных. Память может выделяться в процессе выполнения программы или на этапе компиляции. В ряде языков (например, в Си) для структурированных данных, конструируемых программистом, операция создания включает в себя также установку начальных значений параметров, создаваемой структуры. Например, в Pascal (i:integer), в Си (int i) в результате описания типа будет выделена память для соответствующих переменных. Для структур данных, объявленных в программе, память выделяется автоматически средствами систем программирования либо на этапе компиляции, либо при активизации процедурного блока, в котором объявляются соответствующие переменные. Программист может и сам выделять память для структур данных, используя имеющиеся в системе программирования процедуры или функции выделения или освобождения памяти. В объектно-ориентированных языках программирования при разработке нового объекта для него должны быть определены процедуры создания и уничтожения. Главное заключается в том, что независимо от используемого языка программирования, имеющиеся в программе структуры данных не появляются «из ничего», а явно или неявно объявляются операторами создания структур. В результате этого всем экземплярам структур в программе выделяется память для их размещения. Операция уничтожения структур данных противоположна по своему действию операции создания. Некоторые языки (например, Basic) не дают возможности программисту уничтожать созданные структуры данных. В языках Си и Pascal структуры данных, имеющиеся внутри блока, уничтожаются в процессе выполнения программы при выходе из этого блока. Операция уничтожения помогает эффективно использовать память. Операция выбора используется программистами для доступа к данным внутри самой структуры. Форма операции доступа зависит от типа структуры данных, к которой осуществляется обращение. Метод доступа – один из наиболее важных свойств структур, особенно в связи с тем, что это свойство имеет непосредственное отношение к выбору конкретной структуры данных. Операция обновления позволяет изменить значения данных в структуре данных. Примером операции обновления является операция присваивания, или, более сложная форма – передача параметров. Вышеуказанные четыре операции обязательны для всех структур и типов данных. Помимо этих общих операций для каждой структуры данных могут быть определены операции специфические, работающие только с данными данного типа (данной структуры). Специфические операции рассматриваются при рассмотрении каждой конкретной структуры данных. 2.1.4Транслятор, компилятор, интерпретаторТранслятор (англ. translator – переводчик) – это программа-переводчик, преобразующая программу, написанную на одном из языков высокого уровня, в программу, состоящую из машинных команд. В настоящее время трансляторы разделяются на три основные группы: ассемблеры, компиляторы и интерпретаторы. У каждой из транслирующих программ имеются свои особенности по организации процесса трансляции. Ассемблер – системная обслуживающая программа, которая преобразует символические конструкции в команды машинного языка. Специфической чертой ассемблеров является то, что они осуществляют дословную трансляцию одной символической команды в одну машинную. Таким образом, язык ассемблера (ещё называется автокодом) предназначен для облегчения восприятия системы команд компьютера и ускорения программирования в этой системе команд. Программисту гораздо легче запомнить мнемоническое обозначение машинных команд, чем их двоичный код. Поэтому, основной выигрыш достигается не за счёт увеличения мощности отдельных команд, а за счёт повышения эффективности их восприятия. Вместе с тем, язык ассемблера, кроме аналогов машинных команд, содержит множество дополнительных директив, облегчающих, в частности, управление ресурсами компьютера, написание повторяющихся фрагментов, построение многомодульных программ. Поэтому выразительность языка намного богаче, чем просто языка символического кодирования, что значительно повышает эффективность программирования. Компилятор (англ. compiler – составитель, собиратель) читает всю программу целиком, делает её перевод и создаёт законченный вариант программы на машинном языке, который затем и выполняется. Также как и ассемблер, компилятор обеспечивает преобразование программы с одного языка на другой (чаще всего, в язык конкретного компьютера). Вместе с тем, команды исходного языка значительно отличаются по организации и мощности от команд машинного языка. Существуют языки, в которых одна команда исходного языка транслируется в 7-10 машинных команд. Однако есть и такие языки, в которых каждой команде может соответствовать 100 и более машинных команд (например, Пролог). Кроме того, в исходных языках достаточно часто используется строгая типизация данных, осуществляемая через их предварительное описание. Программирование может опираться не на кодирование алгоритма, а на тщательное обдумывание структур данных или классов. Процесс трансляции с таких языков обычно называется компиляцией, а исходные языки обычно относятся к языкам программирования высокого уровня (или высокоуровневым языкам). Абстрагирование языка программирования от системы команд компьютера привело к независимому созданию самых разнообразных языков, ориентированных на решение конкретных задач. Появились языки для научных расчётов, экономических расчётов, доступа к базам данных и другие. Интерпретатор (англ. interpreter – истолкователь, устный переводчик) переводит и выполняет программу строка за строкой. В отличие от компилятора, интерпретатор не порождает на выходе программу на машинном языке. Распознав команду исходного языка, он тут же выполняет её. Как в компиляторах, так и в интерпретаторах используются одинаковые методы анализа исходного текста программы. Но интерпретатор позволяет начать обработку данных после написания даже одной команды. Это делает процесс разработки и отладки программ более гибким. Кроме того, отсутствие выходного машинного кода позволяет не «захламлять» внешние устройства дополнительными файлами, а сам интерпретатор можно достаточно легко адаптировать к любым машинным архитектурам, разработав его только один раз на широко распространённом языке программирования. Поэтому, интерпретируемые языки, типа JavaScript и VBScript, получили широкое распространение. Недостатком интерпретаторов является низкая скорость выполнения программ. Обычно интерпретируемые программы выполняются в 50-100 раз медленнее программ, написанных в машинных кодах. После того, как программа откомпилирована, ни сама исходная программа, ни компилятор более не нужны. В то же время программа, обрабатываемая интерпретатором, должна заново переводиться на машинный язык при каждом очередном запуске программы. Откомпилированные программы работают быстрее, но интерпретируемые проще исправлять и изменять. Каждый конкретный язык ориентирован либо на компиляцию, либо на интерпретацию — в зависимости от того, для каких целей он создавался. Например, Паскаль обычно используется для решения довольно сложных задач, в которых важна скорость работы программ. Поэтому данный язык обычно реализуется с помощью компилятора. С другой стороны, Бейсик создавался как язык для начинающих программистов, для которых построчное выполнение программы имеет неоспоримые преимущества. Иногда для одного языка имеется и компилятор, и интерпретатор. В этом случае для разработки и тестирования программы можно воспользоваться интерпретатором, а затем откомпилировать отлаженную программу, чтобы повысить скорость её выполнения. Эмулятор – программа или программно-техническое средство, обеспечивающее возможность без перепрограммирования выполнять на данной ЭВМ программу, использующую коды или способы выполнения операций, отличные от данной ЭВМ. Эмулятор похож на интерпретатор тем, что непосредственно исполняет программу, написанную на некотором языке. Однако, чаще всего это машинный язык или промежуточный код. И тот и другой представляют команды в двоичном коде, которые могут сразу исполняться после распознавания кода операций. В отличие от текстовых программ, не требуется распознавать структуру программы, выделять операнды. Эмуляторы используются достаточно часто в самых различных целях. Например, при разработке новых вычислительных систем, сначала создается эмулятор, выполняющий программы, разрабатываемые для еще несуществующих компьютеров. Это позволяет оценить систему команд и наработать базовое программное обеспечение ещё до того, как будет создано соответствующее оборудование. Очень часто эмулятор используется для выполнения старых программ на новых вычислительных машинах. Обычно новые компьютеры обладают более высоким быстродействием и имеют более качественное периферийное оборудование. Это позволяет эмулировать старые программы более эффективно по сравнению с их выполнением на старых компьютерах. Примером такого подхода является разработка эмуляторов домашнего компьютера ZX Spectrum с микропроцессором Z80. До сих пор находятся любители поиграть на эмуляторе в устаревшие, но все еще не утратившие былой привлекательности, игровые программы. Эмулятор может также использоваться как более дешевый аналог современных компьютерных систем, обеспечивая при этом приемлемую производительность, эквивалентную младшим моделям некоторого семейства архитектур. В качестве примера можно привести эмуляторы IBM PC-совместимых компьютеров, реализованные на более мощных компьютерах фирмы Apple. Ряд эмуляторов, написанных для IBM PC, с успехом заменяют различные игровые приставки. Эмулятор промежуточного представления, как и интерпретатор, могут легко переноситься с одной компьютерной архитектуры на другую, что позволяет создавать мобильное программное обеспечение. Именно это свойство предопределило успех языка программирования Java, с которого программа транслируется в промежуточный код. Исполняющая этот код виртуальная Java машина, является ни чем иным как эмулятором, работающим под управлением любой современной операционной системы. Перекодировщик – программа или программное устройство, переводящие программы, написанные на машинном языке одной ЭВМ в программы на машинном языке другой ЭВМ. Если эмулятор является менее интеллектуальным аналогом интерпретатора, то перекодировщик выступает в том же качестве по отношению к компилятору. Точно также исходный (и обычно двоичный) машинный код или промежуточное представление преобразуются в другой аналогичный код по одной команде и без какого-либо общего анализа структуры исходной программы. Перекодировщики могут быть полезны при переносе программ с одних компьютерных архитектур на другие. Они могут также использоваться для восстановления текста программы на языке высокого уровня по имеющемуся двоичному коду. Макропроцессор – программа, обеспечивающая замену одной последовательности символов другой. Это разновидность компилятора. Он осуществляет генерацию выходного текста путем обработки специальных вставок, располагаемых в исходном тексте. Эти вставки оформляются специальным образом и принадлежат конструкциям языка, называемого макроязыком. Макропроцессоры часто используются как надстройки над языками программирования, увеличивая функциональные возможности систем программирования. Практически любой ассемблер содержит макропроцессор, что повышает эффективность разработки машинных программ. Такие системы программирования обычно называются макроассемблерами. Макропроцессоры используются и с языками высокого уровня. Они увеличивают функциональные возможности таких языков как PL/1, Си, Си++. Особенно широко макропроцессоры применяются в C и C++, позволяя упростить написание программ. Примером широкого использования макропроцессоров является библиотека классов Microsoft Foundation Classes (MFC). Через макровставки в ней реализованы карты сообщений и другие программные объекты. При этом макропроцессоры повышают эффективность программирования без изменения синтаксиса и семантики языка. Синтаксис – совокупность правил некоторого языка, определяющих формирование его элементов. Иначе говоря, это совокупность правил образования семантически значимых последовательностей символов в данном языке. Синтаксис задаётся с помощью правил, которые описывают понятия некоторого языка. Примерами понятий являются: переменная, выражение, оператор, процедура. Последовательность понятий и их допустимое использование в правилах определяет синтаксически правильные структуры, образующие программы. Именно иерархия объектов, а не то, как они взаимодействуют между собой, определяются через синтаксис. Например, оператор может встречаться только в процедуре, а выражение в операторе, переменная может состоять из имени и необязательных индексов и т.д. Синтаксис не связан с такими явлениями в программе как «переход на несуществующую метку» или «переменная с данным именем не определена». Этим занимается семантика. Семантика – правила и условия, определяющие соотношения между элементами языка и их смысловыми значениями, а также интерпретацию содержательного значения синтаксических конструкций языка. Объекты языка программирования не только размещаются в тексте в соответствии с некоторой иерархией, но и дополнительно связаны между собой посредством других понятий, образующих разнообразные ассоциации. Например, переменная, для которой синтаксис определяет допустимое местоположение только в описаниях и некоторых операторах, обладает определенным типом, может использоваться с ограниченным множеством операций, имеет адрес, размер и должна быть описана до того, как будет использоваться в программе. Синтаксический анализатор – компонент компилятора, осуществляющий проверку исходных операторов на соответствие синтаксическим правилам и семантике данного языка программирования. Несмотря на название, анализатор занимается проверкой и синтаксиса, и семантики. Он состоит из нескольких блоков, каждый из которых решает свои задачи. 2.1.5Интегрированные среды программированияИнтегрированная среда программирования – система программных средств, используемая программистами для разработки программного обеспечения. Обычно среда программирования включает в себя: текстовый редактор; компилятор и/или интерпретатор; средства автоматизации сборки; отладчик. Иногда интегрированная среда программирования содержит также средства для интеграции с системами управления версиями и разнообразные инструменты для упрощения конструирования графического интерфейса пользователя. Многие современные среды программирования также включают браузер классов, инспектор объектов и диаграмму иерархии классов – для использования при объектно-ориентированной разработке программного обеспечения. Хотя, и существуют среды разработки, предназначенные для нескольких языков программирования – такие, как Eclipse, NetBeans, Embarcadero RAD Studio, Qt Creator или Microsoft Visual Studio, обычно среда разработки предназначается для одного определённого языка программирования – как, например, Visual Basic, Delphi, Dev-C++. Частный случай интегрированных сред программирования – среды визуальной разработки, которые включают в себя возможность визуального редактирования интерфейса программы. Среда визуальной разработки – среда разработки программного обеспечения, в которой наиболее распространенные блоки программного кода представлены в виде графических объектов. Применяются в основном для создания прикладных программ и разработки графического интерфейса пользователя (GUI). Преимущества: быстрота разработки; лёгкость освоения; стандартизация внешнего вида программ. Недостатки: привязка к конкретной среде разработки связана с проблематичностью перехода на другую среду разработки; затруднённое использование нестандартных компонентов; наличие недокументированных особенностей компонентов. Некоторые визуальные среды разработки имеют собственный формат хранения проекта, и при переходе на другую среду может возникнуть непереносимость свойств проекта и некоторых частей проекта, таких как собственные библиотеки используемой среды разработки. Некоторые изменения могут вноситься и в язык программирования. Так, например, несмотря на то, что в среде разработки Delphi за основу взят Pascal, она представляет собой уже новый язык программирования. Среду разработки, как и язык программирования, следует выбирать на этапе проектирования программного обеспечения. Правильно спроектированное программное обеспечение должно учитывать развитие и внедрение новых технологий, поэтому перенос разработки такого программного обеспечения в другую среду разработки не должен представлять трудностей. 2.1.6Вопросы для самоконтроляПривести классификацию языков программирования. Рассказать об эволюции языков программирования. Привести примеры применения языков программирования высокого уровня. Что такое уровень языка программирования? Какие у машинных языков достоинства и недостатки? Что такое язык ассемблера? В чём преимущества алгоритмических языков перед машинными? Какие компоненты образуют алгоритмический язык? Какие понятия используют алгоритмические языки? В какой последовательности возникали известные вам языки программирования? Что такое транслятор, компилятор, интерпретатор? Что такое тип данных? Какие типы данных относятся к простым? Что понимают под языками программирования? К какому классу языков относится язык Ассемблер? Перечислите первые алгоритмические языки. Перечислите фундаментальные структуры данных. Чем отличается компилятор от интерпретатора? Что понимают под интегрированной средой программирования? |