Технология программирования. 1. введение том Сойер рисует на заборе
Скачать 209.98 Kb.
|
Тема 2. Языки программирования Содержание темы: первые языки программирования, области применения языков программирования, парадигмы программирования, состав языка программирования, стандартизация языков программирования, среда проектирования, трансляторы, процесс трансляции Цели и задачи изучения темы: получить знания о существующих языках программирования, области их применения, составе языка, средствах разработки программ, методах преобразования программы, написанной на языке высокого уровня в машинный код Изучая тему, необходимо акцентировать внимание на следующих понятиях: языки высокого уровня – языки, не зависящие от конкретной архитектурыкомпьютера среда программирования – предназначена для разработки приложений на конкретном языке программирования синтаксис языка – описывает систему правил написания различных языковых конструкций семантика языка – определяет смысл языковых конструкций; транслятор или компилятор - специальная программа, выполняющая перевод программы написанной на языке высокого уровня в язык машинных команд средства разработки программ – графический интерфейс разработки программы, включающий управление версиями хранимых данных, утилиты просмотра и управления информацией, библиотеки классов, мастера создания шаблонов приложений и т.п. 2.1. Первые языки программирования Языком программирования называется система обозначений и правил, позволяющая записать программу решения задачи в виде последовательного текста в удобном для человека виде В пятидесятые годы двадцатого века с появлением компьютеров на электронных лампах началось бурное развитие языков программирования. Программирование начиналось с записи программ непосредственно в виде машинных команд (в кодах, как говорят программисты). Компьютеры, стоившие в то время значительно дороже, чем разработка любой программы, требовали высокоэффективного кода. Для облегчения кодирования был разработан машинно-ориентированный язык Ассемблера, который позволял записывать машинные команды в символическом виде. Язык Ассемблера зависел от системы команд конкретного компьютера. Он был достаточно удобен для программирования небольших задач, требующих максимальной скорости выполнения. Однако крупные проекты разрабатывать на языке Ассемблера было трудно. Главная проблема состояла в том, что программа, написанная на Ассемблере, привязана к архитектуре конкретного компьютера и не могла быть перенесена на другие машины. При усовершенствовании компьютера все программы на Ассемблере приходилось переписывать заново. Почти сразу с возникновением компьютеров были разработаны языки высокого уровня, т.е. языки, не зависящие от конкретной архитектуры. Для выполнения программы на языке высокого уровня ее нужно сначала перевести на язык машинных команд. Специальная программа, выполняющая такой перевод, называется транслятором или компилятором. Оттранслированная программа затем выполняется непосредственно компьютером. Существует также возможность перевода программы на промежуточный язык, не зависящий от архитектуры конкретного компьютера, но, тем не менее, максимально приближенный к языку машинных команд. Затем программа на промежуточном языке выполняется специальной программой, которая называется интерпретатором. Возможен также вариант компиляции "на лету", когда выполняемый фрагмент программы переводится с промежуточного языка на язык машинных команд непосредственно перед выполнением. В середине 50-х годов под руководством Джона Бэкуса для фирмы IBM был разработан алгоритмический язык программирования высокого уровня FORTRAN. Несмотря на то, что уже существовали разработки языков, выполняющие преобразование арифметических выражений в машинный код, создание языка FORTRAN (FORmula TRANslator), предоставляющего возможность записи алгоритма вычислений с использованием условных операторов и операторов ввода/вывода, стало точкой отсчета эры языков программирования высокого уровня. К языку FORTRAN предъявлялись требования создания высокоэффективного кода. Поэтому многие конструкции языка первоначально разрабатывались с учетом архитектуры IBM 407. Успех разработки этого языка привел к тому, что производители других вычислительных систем стали создавать свои версии трансляторов. С целью некоторой возможной на тот момент унификации языка язык FORTRAN IV, разработанный в 1966 году, стал первым стандартом, именуемым FORTRAN 66. Как альтернатива языку FORTRAN, первоначально ориентированному на архитектуру IBM, под руководством Питера Наура в конце 50-х годов был разработан язык ALGOL (ALGOrithmic Language). Основной целью, преследуемой разработчиками этого языка, была независимость от конкретной архитектуры вычислительной системы. Кроме того, создатели языка ALGOL стремились разработать язык, удобный для описания алгоритмов и применяющий систему обозначений, близкую к той, что принята в математике. Языки FORTRAN и ALGOL были первыми языками, ориентированными на программирование вычислений. Язык PL/I, первые версии которого появились в начале 60-х годов, был первоначально ориентирован на IBM 360 и расширял возможности языка FORTRAN некоторыми средствами языка COBOL, разработанного в эти же годы. Несмотря на определенную популярность языка PL/I у программистов, работавших на компьютерах IBM и машинах серии ЕС, в настоящее время он представляет чисто теоретический интерес. В конце 60-х годов под руководством Найарда и Дала был разработан язык Simula-67, использующий концепцию пользовательских типов данных. Фактически это первый язык, применяющий понятие классов. В середине 70-х годов Вирт предложил язык Pascal, который сразу стал широко использоваться. В это же время по инициативе Министерства обороны США началась работа по созданию языка высокого уровня, получившего название Ada – в честь Ады Лавлейс, программистки и дочери лорда Байрона. Создание языка началось с определения требований и выработки спецификаций. Над проектом работали четыре независимые группы, но все они использовали как основу язык Pascal. В начале 80-х годов был разработан первый промышленный компилятор языка Ada. Наконец, самый успешный язык программирования - язык Си и связанная с ним линия объектно-ориентированных языков: C++, Java, C#. Универсальный язык программирования С был разработан в середине 70-х годов Денисом Ритчи и Кеном Томпсоном. Этот язык стал популярным языком системного программирования и в свое время использовался для написания ядра операционной системы UNIX. Стандарт языка С начал разрабатываться рабочей группой института стандартов ANSI в 1982 году. Международный стандарт языка С принят в 1990 году. Язык С лег в основу разработки языков программирования C++ и Java. Язык Си был создан не теоретиками, а практическими программистами, обладающими при этом высокой математической культурой. Язык был разработан в конце 60-х годов XX века. Он впервые позволил реально избавиться от Ассемблера при создании операционных систем. Например, практически весь текст операционной системы Unix написан на языке Си и, таким образом, не зависит от конкретного компьютера. Главным достоинством Си является его простота и отсутствие псевдонаучных решений (таких, как вложенность блоков программ друг в друга: в Си функция не может содержать внутри себя другую функцию, а переменные четко разделяются на глобальные и локальные - не так, как в Алголе, где локальные переменные подпрограммы являются глобальными для всех вложенных в нее подпрограмм). Просто и ясно описан механизм передачи параметров в функцию (только по значению). Программист, создающий программу на Си, всегда четко понимает, как эта программа будет выполняться. Понятие указателя, статические и автоматические (стековые) переменные языка Си максимально близко отражают устройство любого современного компьютера, поэтому программы на Си эффективны и удобны для отладки. В настоящее время подавляющая часть программ пишется на языках Си и C++. Интерфейс любой операционной системы (так называемый API - Application Program Interface), т.е. набор системных вызовов, предназначенных для разработчиков прикладных программ, как правило, представляет собой набор функций на языке Си. Наконец, современные объектно-ориентированные языки также основаны на языке Си. Это язык C++, занимающий промежуточное положение между традиционными и объектно-ориентированными языками, а также объектно-ориентированные языки Java и C#. Наряду с алгоритмическими языками параллельно развивались и языки, предназначаемые для обработки деловой информации, а также языки искусственного интеллекта. К первым относится язык COBOL (COmmon Business Oriented Language), а ко вторым – языки LISP (LISt Processing) и Prolog. Язык LISP, разработанный в 60-х годах под руководством Дж. Маккарти, был первым функциональным языком обработки списков, который нашел широкое применение в теории игр. С появлением персональных компьютеров языки стали составными частями интегрированных сред разработки. Появились языки, применяемые в различных офисных программах, например VBA (Visual Basic for Application). В 90-х годах с распространением сети Интернет расширяется возможность распределенной обработки данных, что отражается и на развитии языков программирования. Появляются языки, ориентированные на создание серверных приложений, такие как Java, Perl и PHP, языки описания документов – HTML и XML. Традиционные языки программирования С++ и Pascal также претерпевают изменения: под языком программирования начинает пониматься не только функциональность самого языка, а также библиотеки классов, предоставляемые средой программирования. Акцент со спецификации самих языков программирования переносится на стандартизацию механизмов взаимодействия распределенных приложений. Появляются новые технологии – COM и CORBA, специфицирующие взаимодействие распределенных объектов. 2.2. Области применения языков программирования В настоящее время языки программирования применяются в самых различных областях человеческой деятельности, таких как: научные вычисления (языки C++, FORTRAN, Java); системное программирование (языки C++, Java); обработка информации (языки C++, COBOL, Java); искусственный интеллект (LISP, Prolog); издательская деятельность (Postscript, TeX); удаленная обработка информации (Perl, PHP, Java, C++); описание документов (HTML, XML). С течением времени одни языки развивались, приобретали новые черты и остались востребованы, другие утратили свою актуальность и сегодня представляют в лучшем случае чисто теоретический интерес. В значительной степени это связано с такими факторами, как: наличие среды программирования, поддерживающей разработку приложений на конкретном языке программирования; удобство сопровождения и тестирования программ; стоимость разработки с применением конкретного языка программирования; четкость и ортогональность конструкций языка; применение объектно-ориентированного подхода. 2.3. Парадигмы программирования Синтаксис языка описывает систему правил написания различных языковых конструкций, а семантика языка программирования определяет смысл этих конструкций. Семантика языка взаимосвязана с используемой вычислительной моделью. В настоящее время языки программирования в зависимости от применяемой вычислительной модели делятся на четыре основные группы: Процедурные языки, которые представляют собой последовательность выполняемых операторов. Если рассматривать состояние ПК как состояние ячеек памяти, то процедурный язык – это последовательность операторов, изменяющих значение одной или нескольких ячеек. К процедурным языкам относятся FORTRAN, C, Ada, Pascal, Smalltalk и некоторые другие. Процедурные языки иногда также называются императивными языками. Аппликативные языки, в основу которых положен функциональный подход. Язык рассматривается с точки зрения нахождения функции, необходимой для перевода памяти ПК из одного состояния в другое. Программа представляет собой набор функций, применяемых к начальным данным, позволяющий получить требуемый результат. К аппликативным языкам относится язык LISP. Языки системы правил, называемые также языками логического программирования, основываются на определении набора правил, при выполнении которых возможно выполнение определенных действий. Правила могут задаваться в виде утверждений и в виде таблиц решений. К языкам логического программирования относится язык Prolog. Объектно-ориентированные языки, основанные на построении объектов как набора данных и операций над ними. Объектно-ориентированные языки объединяют и расширяют возможности, присущие процедурным и аппликативным языкам. К объектно-ориентированным языкам относятся C++, Object Pascal, Java. В настоящий момент наибольшее распространение получили языки, основанные на объектно-ориентированной модели. Они, реализуя процедурную модель построения языка, поддерживают аппликативность конструкций, позволяя представлять блок-схему выполнения структурированной программы как некоторый набор аппликативных функций. 2.4. Состав языка программирования В тексте на любом естественном языке можно выделить четыре основных элемента: символы, слова, словосочетания и предложения. Подобные элементы содержит и алгоритмический язык, только слова называют лексемами (элементарными конструкциями), словосочетания – выражениями, а предложения – операторами. Лексемы образуются из символов, выражения – из лексем и символов, а операторы – из символов, выражений и лексем (рис. 2.1): Рис. 2.1.Состав алгоритмического языка Алфавит языка, или его символы — это основные неделимые знаки, с помощью которых пишутся все тексты на языке. Лексема, или элементарная конструкция, — минимальная единица языка, имеющая самостоятельный смысл. Выражение задает правило вычисления некоторого значения. Оператор задает законченное описание некоторого действия. Для описания сложного действия требуется последовательность операторов. Операторы могут быть объединены в составной оператор, или блок. В этом случае они рассматриваются как один оператор. Операторы бывают исполняемые и неисполняемые. Исполняемые операторы задают действия над данными. Неисполняемые операторы служат для описания данных, поэтому их часто называют операторами описания или просто описаниями. Каждый элемент языка определяется синтаксисом и семантикой. Синтаксические определения устанавливают правила построения элементов языка, а семантика определяет их смысл и правила использования. Объединенная единым алгоритмом совокупность описаний и операторов образует программу на алгоритмическом языке. 2.5. Стандартизация языков программирования Концепция языка программирования неотрывно связана с его реализацией. Для того чтобы компиляция одной и той же программы различными компиляторами всегда давала одинаковый результат, разрабатываются стандарты языков программирования. Существует ряд организаций, целенаправленно занимающихся вопросами стандартизации. Это Американский национальный институт стандартов ANSI (American National Standards Institute), Институт инженеров по электротехнике и электронике IEEE (Institute of Electrical and Electronic Engineers), Организация международных стандартов ISO (International Organization for Standardization). Как правило, при создании языка выпускается частный стандарт, определяемый разработчиками языка. Если язык получает широкое распространение, то со временем появляются различные версии компиляторов, которые не точно следуют частному стандарту. В большинстве случаев идет расширение зафиксированных первоначально возможностей языка. Для приведения наиболее популярных реализаций языка в соответствие друг с другом разрабатывается согласительный стандарт. Очень важным фактором стандартизации языка программирования является своевременность появления стандарта – до широкого распространения языка и создания множества несовместимых реализаций. В процессе развития языка могут появляться новые стандарты, отражающие современные нововведения. Так, язык FORTRAN первоначально был стандартизирован в 1966 году. В результате был издан стандарт FORTRAN 66. Далее этот стандарт несколько раз пересматривался (в 1977 году был выпущен FORTRAN 77, затем появился и FORTRAN 90). В процессе развития языка некоторые его конструкции и функции устаревают. Однако с целью обратной совместимости новые версии должны поддерживать и все устаревающие возможности. Это ведет к "разбуханию" компиляторов. В последнее время в реализациях введено понятие не рекомендуемой и устаревшей возможности. В первом случае следующий стандарт еще будет поддерживать не рекомендуемую возможность, но может перевести ее в категорию устаревшей. Во втором случае стандарт может исключить поддержку возможности, объявленной ранее как устаревшая. 2.6. Среда проектирования С развитием языков программирования совершенствовались и средства разработки программ – от режима командной строки до интегрированной среды проектирования. Такая среда предоставляет удобный графический интерфейс разработки и большой спектр сервисов, включающих управление версиями хранимых данных, утилиты просмотра и управления информацией, библиотеки классов, мастера создания шаблонов приложений и т.п. Компилятор языка программирования выступает как составная часть среды проектирования. Сама программа наряду с конструкциями, предусмотренными стандартом, как правило, использует библиотечные функции и классы, предоставляемые средой проектирования. Так, интегрированная среда разработки VisualStudio содержит библиотеку классов MFC (Microsoft Foundation Classes), значительно упрощающую процесс разработки приложений, использующих оконный интерфейс. 2.7. Трансляторы Программа, написанная на языке высокого уровня, перед исполнением должна быть преобразована в программу на "машинном языке". Такой процесс называется трансляцией, или компиляцией. По типу выходных данных различают два основных вида трансляторов: компилирующие окончательный выполнимый код; компилирующие интерпретируемый код, для выполнения которого требуется дополнительное программное обеспечение. Окончательным выполнимым кодом являются приложения, реализованные как EXE-файлы, DLL-библиотеки, COM-компоненты. К интерпретируемому коду можно отнести байт-код JAVA-программ, выполняемый посредством виртуальной машины JVM. Языки, формирующие окончательный выполнимый код, называются компилируемыми языками. К ним относятся языки С, C++, FORTRAN, Pascal. Языки, реализующие интерпретируемый код, называются интерпретируемыми языками. К таким языкам относятся язык Java, LISP, Perl, Prolog. В большинстве случаев код, получаемый в результате процесса трансляции, формируется из нескольких программных модулей. Программным модулем называется определенным образом оформленный код на языке высокого уровня. Процесс трансляции в этом случае может выполняться как единое целое – компиляция и редактирование связей, или как два отдельных этапа – сначала компиляция объектных модулей, а затем вызов редактора связей, создающего окончательный код. Последний подход более удобен для разработки программ. Он реализован в трансляторах языков С и С++. Объектный код, создаваемый компилятором, представляет собой область данных и область машинных команд, имеющих адреса, которые в дальнейшем "согласуются" редактором связи (иногда называемым загрузчиком). Редактор связи размещает в едином адресном пространстве все по отдельности откомпилированные объектные модули и статически подключаемые библиотеки. Будем называть выполнимой формой программы код, получаемый в результате трансляции исходной программы. 2.8. Процесс трансляции Программу, написанную на языке программирования высокого уровня, называют исходной программой, а каждую самостоятельную программную единицу, образующую данную программу, - программным модулем. Для преобразования исходной программы в ее выполняемую форму (выполнимый файл) транслятор выполняет некоторую последовательность действий. Эта последовательность зависит как от языка программирования, так и от конкретной реализации самого транслятора. В ходе трансляции важно не просто откомпилировать программу, а получить при этом достаточно эффективный код. В процессе трансляции выполняется анализ исходной программы, а затем синтез выполнимой формы данной программы. В зависимости от числа просмотров исходной программы, выполняемых компилятором, трансляторы разделяются на однопроходные, двухпроходные и трансляторы, использующие более двух проходов. К достоинствам однопроходного компилятора можно отнести высокую скорость компиляции, а к недостаткам - получение, как правило, не самого эффективного кода. Широкое распространение получили двухпроходные компиляторы. Они позволяют при первом проходе выполнить анализ программы и построить информационные таблицы, используемые при втором проходе для формирования объектного кода. Фаза анализа программы состоит из: лексического анализа; синтаксического анализа; семантического анализа. При анализе исходной программы транслятор последовательно просматривает текст программы, представимой как набор символов, выполняя разбор структуры программы. На этапе лексического анализа выполняется выделение основных составляющих программы – лексем. Лексемами являются ключевые слова, идентификаторы, символы операций, комментарии, пробелы и разделители. Лексический анализатор не только выделяет лексемы, но и определяет тип каждой лексемы. При этом на этапе лексического анализа составляется таблица символов, в которой каждому идентификатору сопоставлен свой адрес. Это позволяет при дальнейшем анализе вместо конкретного значения (строки символов) использовать его адрес в таблице символов. Процесс выделения лексем достаточно трудоемок и требует применения сложных контекстно-зависимых алгоритмов. На этапе синтаксического анализа выполняется разбор полученных лексем с целью получения семантически понятных синтаксических единиц, которые затем обрабатываются семантическим анализатором. Так, синтаксическими единицами выступают выражения, объявление, оператор языка программирования, вызов функции. На этапе семантического анализа выполняется обработка синтаксических единиц и создание промежуточного кода. В зависимости от наличия или отсутствия фазы оптимизации результатом семантического анализа может быть оптимизируемый далее промежуточный код или готовый объектный модуль. К наиболее общим задачам, решаемым семантическим анализатором, относятся: обнаружение ошибок времени компиляции; заполнение таблицы символов, созданной на этапе лексического анализа, конкретными значениями, определяющими дополнительную информацию о каждом элементе таблицы; замена макросов их определениями; выполнение директив времени компиляции. Макросом называется некоторый предварительно определенный код, который на этапе компиляции вставляется в программу во всех местах указания вызова данного макроса. На фазе синтеза программы производится: генерация кода; редактирование связей. Процесс генерации кода состоит из преобразования промежуточного кода (или оптимизированного кода) в объектный код. При этом в зависимости от языка программирования получаемый объектный код может быть представлен в выполнимой форме или как объектный модуль, подлежащий дальнейшей обработке редактором связей. Так, процесс генерации кода является неотъемлемой частью фазы синтеза программы, а необходимость выполнения редактора связей зависит от конкретного языка программирования. Следует учесть, что на практике термин «генерация кода» часто применяют ко всем действиям фазы синтеза программы, ведущим к получению выполнимой формы программы. Редактор связей приводит в соответствие адреса фрагментов кода, расположенных в отдельных объектных модулях: определяются адреса вызываемых внешних функций, адреса внешних переменных, адреса функций и методов каждого модуля. Для редактирования адресов редактор связей использует специальные, создаваемые на этапе трансляции, таблицы загрузчика. После обработки объектных модулей редактором связей генерируется выполнимая форма программы. Методические указания: читать учебное пособие |