Sign by Dealighted - Coupons & Discount Shopping

Студент "Информатик"

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Студент "Информатик" » Библиотека » Экскурс в историю


Экскурс в историю

Сообщений 1 страница 12 из 12

1

Данный материал был наглым образом взят со страниц журнала Root#UA.

История языков программирования

Как все начиналось
На первый взгляд это может показаться странным, но программирование старше, чем языки программирования. Первые программисты обходились вовсе без языков программирования. Самые первые цифровые электронно-вычислительные машины создавались для конкретных, узкоспециализированных задач (например, для решения систем линейных уравнений методом Гаусса), и программу их работы изменить было невозможно в принципе. Естественно, вопрос программирования подобных вычислительных систем отпадал сам собой – можно было только менять входные данные.
Последовавшие за ними вычислительные машины с изменяемой программой также были лишены возможности использования языков программирования: программы вводились в них посредством соединения гнезд на специальной коммутационной панели, которая управляла последовательностью выполняемых операций. Разумеется, автоматизировать этот трудоемкий и сложный процесс не представлялось возможным. Хотя к этому времени (40-е годы XX столетия) уже была известна модель хранимой программы фон Неймана, элементная база еще не позволяла создавать оперативные запоминающие
устройства достаточного объема для хранения кодов инструкций, их едва хватало для хранения данных (память размером в 1000 машинных слов считалась огромной и стоила астрономическую сумму). Поэтому между теорией и практическим ее воплощением прошло несколько лет, пока, наконец, не появились действительно универсальные цифровые ЭВМ, позволяющие быстро менять программы путем загрузки их в оперативную память. Громоздкие коммутационные панели, опутанные клубками проводов, исчезли, их заменили массивы кодов инструкций, загружаемых с различных устройств хранения информации: перфолент и перфокарт, магнитных лент, барабанов…
С появлением таких устройств и зародилось явление, которое довольно быстро из досадной проблемы переросло в настоящий кризис, кризис программирования. Выяснилось, что разрабатывать программы в машинных кодах слишком трудно и долго, а следовательно, дорого. На фоне непрерывного снижения цен на оборудование увеличение затрат на программное обеспечение раздражало владельцев компьютеров (если бы они только знали, что ждет их в будущем!). Поиск решения этой проблемы и привел к появлению ныне столь многочисленной семьи языков программирования.

0

2

Ассемблер
Поскольку большинство промышленных компьютеров обладало фон-неймановской архитектурой, их программы представляли собой не что иное, как последовательности машинных слов определенной структуры. А если так, то ничто не мешает разработать программу, которая будет выдавать такие последовательности в качестве своих выходных данных.
Разумеется, все выглядит так просто лишь на первый взгляд. Для того, чтобы сделать эту идею реальностью, потребовалось много лет упорнейшего труда математиков, лингвистов и инженеров, которые разработали теорию формальных языков и превратили разработку компиляторов из занятия, доступного
лишь избранным, в хорошо формализованный процесс, которому обучают в большинстве учебных заведений компьютерного профиля.
Самым первым и очевидным шагом на пути автоматизации программирования было освободить программистов от самой рутинной части их работы. Самыми рутинными операциями при программировании в кодах были:
• формирование кода команды;
• вычисление физических адресов ячеек с данными;
• вычисление смещений для команд условного и безусловного ветвлений.
Для первой проблемы было найдено следующее решение: для каждой машинной команды были подобраны краткие мнемоники, отражающие ее суть. Например, для команды пересылки данных – MOV, для команды сложения – ADD и т.п. Такие мнемоники намного легче запомнить, чем двоичные, восьмеричные или шестнадцатеричные коды команды; кроме того, их не в пример легче читать, а это тоже немаловажно при отладке программы или ее изменении.
Вторая и третья проблемы также были решены без особых усилий: вместо использования реальных адресов в тексте программы располагались символические метки, а программа, генерирующая машинный код, вычисляла фактическое расположение ячеек в оперативной памяти и поставляла его в код.
Программы, предназначенные для преобразования подобных мнемонических инструкций в исполняемый машинный код, стали называть ассемблерами, а языки, используемые для записи таких программ языками ассемблера, или, кратко, тоже ассемблерами.
Разумеется, появление ассемблеров явилось важным шагом на пути развития программирования. Во-первых, программы на ассемблере читать и понимать гораздо легче, чем разбираться с машинными кодами (однако не следует считать, что это легко – все познается в сравнении).
Во-вторых, вычисление смещений для ветвлений и относительной адресации – задача хоть и не сложная, но весьма громоздкая и подверженная
ошибкам. В-третьих, при добавлении дополнительных команд в середину программы не нужно заботиться о пересчете изменившихся адресов данных и команд, ассемблер их пересчитает при очередном запуске.
Однако применение ассемблера оставляет нерешенными ряд задач. Во-первых, программирование на языке ассемблера требует хорошего знания архитектуры машины, на которой программа будет выполняться. Это значительно сужает круг потенциальных разработчиков программного обеспечения. Например, для разработки программного обеспечения для решения экономических задач программист должен одинаково хорошо разбираться как в предметной области, так и в архитектуре компьютера; наладить совместную работу двух разных людей, каждый из которых является специалистом в одном из этих вопросов, значительно сложнее.
Во-вторых, как следствие, низкий уровень языка вынуждает программиста мыслить не категориями предметной области, а в терминах ячеек памяти, индексных и базовых регистров, указателя стека и т.п. В случае нетривиальной задачи довольно трудно мыслить одновременно на нескольких уровнях абстракции.
В-третьих, язык ассемблера вследствие жесткой привязки к архитектуре определенного компьютера делает программы непереносимыми: переход на другой тип компьютеров делает непригодными все ранее разработанные программы, поскольку новый компьютер имеет другие мнемоники и формат команд, другие методы адресации аргументов и т.п. Кроме того, переучивание программистов на новую систему команд также потребует определенного времени, что делает переход на другую архитектуру еще более трудным.
В качестве примера приведу небольшой отрывок ассемблерного кода, «Заметки о рекурсии-2. Механизмрекурсии»:
push esi
mov esi,dword ptr [esp+8]
pop eax
cmp esi,eax
jge Fact+10h
xor eax,eax
pop esi
Этот фрагмент предназначен для выполнения на процессоре архитектуры Intel 80x86 или совместимом.

0

3

FORTRAN
FORTRAN был первым успешно реализованным языком программирования высокого уровня. Разрабатывался он во времена жесточайшего дефицита оперативной памяти, который ставил под сомнение саму возможность практической реализации компилятора какого-либо из языков высокого уровня (ЯВУ). Это обстоятельство отложило свой отпечаток на облик языка: во главу угла ставилась высочайшая эффективность и компактность результирующего машинного кода, которые позволили языку постепенно завоевать популярность, несмотря на многочисленные нападки сторонников ассемблера.
Несмотря на отсутствие опыта (откуда же ему было взяться у разработчиков первого компилятора, когда даже теория компиляции еще не была разработана), эта задача была решена разработчиками блестяще: компилятор FORTRAN I для мэйнфреймов IBM удерживал рекорд по степени оптимизации кода в течение 20 лет! Хотя этому меньше удивляешься, узнав, что во главе разработки стоял гениальный Джон Бэкус, а в его команду входили Ш. Бест, Х. Геррик, П. Шеридан, Р. Натт, Р. Нельсон, И. Зиллер, Р. Голдберг, Л. Хейбт и Д. Сейр. Немалую роль сыграла и поддержка коллектива руководством
IBM, даже несмотря на то, что проект потребовал куда больше ресурсов, чем первоначально планировалось.
Выиграв кровопролитнейшую битву с ассемблером, новый язык получил заслуженное признание как в среде ученых, так и у промышленников и военных. В частности, трудно переоценить его роль в компьютерном обеспечении космической программы.
Разумеется, первая реализация была небезупречна, поэтому в дальнейшем как язык, так и его компиляторы претерпели долгое эволюционное развитие (которое, как я с удивлением обнаружил, продолжается и поныне). В 1958 г. увидел свет FORTRAN II, в который были добавлены средства раздельной компиляции модулей, а также возможность связи с ассемблерным кодом. В том же году появился FORTRAN III, который, впрочем, так и не был выпущен для общего пользования. В этой версии можно было включать фрагменты ассемблерного кода прямо в исходный текст программы. Эффективность кода возросла еще больше, однако это сильно ударило по переносимости, поэтому от новшества решили все же отказаться.
Наконец, в 1961 г. был выпущен FORTRAN IV, который представлял собой рафинированный вариант FORTRAN II, лишенный некоторых аномалий и машинно-зависимых особенностей. Именно эта версия получила наибольшее распространение среди ученых и инженеров и служила им верой и правдой более 30 лет, будучи реализованной практически на всех мэйнфреймах, мини-ЭВМ и персональных компьютерах, с которыми мне когда-либо доводилось иметь дело.
С мая 1962 г. началась работа по стандартизации языка, результатом которой стал FORTRAN 66 – первый в мире стандарт на ЯВУ. Язык заслуженно получил очередной титул «первый».
Основные черты языка: программа состоит из главной программы и набора подпрограмм, компилируемых независимо и компонуемых перед загрузкой. Каждая подпрограмма имеет собственную отдельную область памяти для хранения переменных и кода. Кроме того, можно выделять общие (COMMON) области памяти, которые содержат переменные, доступные из разных подпрограмм. Обмен данными осуществляется через блоки COMMON,
а также через формальные параметры подпрограмм, при этом передача параметров производится только по ссылке. Из типов данных имеются числовые (целочисленные и с плавающей точкой), а также логический. Из структур – скалярные переменные и статические массивы размерностью не более 3. Что характерно, имеется также встроенный тип для представления комплексных значений, для которого определен полный набор операций.
Поскольку основное назначение языка – математические вычисления, имеется богатый набор арифметических операций, математических функций, а также преобразований типов. Управляющие структуры весьма примитивны и представлены в основном условными и безусловными переходами по меткам.
Правила записи конструкций языка весьма строги: строка имеет не более 80 символов, из которых в первой позиции строки предусмотрен символ комментария (обычно C), позиции 2-6 отведены для меток, 7 – для символа продолжения строки (если предыдущая не уместилась в отведенные 80 символов), остальные служат для записи операторов. Хранение локальных переменных в специально выделенной области памяти весьма затрудняет использование рекурсии.
Небольшая программа на языке FORTRAN IV:
DIMENSION A(99)
10 READ(1,5) K
5 FORMAT (I2) IF (K.EQ.0) GO TO 30
REA
D (1,15) (A(I), I=1,K)
15 FORMAT (6F10.5)
RES=SUM(A,K) WRITE (2,25) RES
25 FORMAT (5HSUM = ,3X, F10.5)
GOTO 10
30 CONTINUE
END

0

4

FORTRAN 77
Несмотря на очевидный успех FORTRAN, по мере роста размера и сложности программ все очевиднее становилась его неуклюжесть благодаря примитивным управляющим структурам. Когда умами программистов овладели идеи структурного программирования и использование оператора GO TO стало признаком дурного тона, надолго застывший в своем развитии FORTRAN начал понемногу сдавать свои позиции. С другой стороны, огромные наработки в академической и промышленной среде нельзя было игнорировать. Поэтому спустя 11 лет старый добрый FORTRAN был основательно пересмотрен
и переработан с у четом современных (на то время) требований к языку программированию. Плодом этих усилий стал стандарт FORTRAN 77.
Прежде всего были учтены интересы давних сторонников языка: новый язык был в высокой степени совместим с предшественником, т.е. фактически любая корректная программа FORTRAN IV является корректной программой FORTRAN 77. Наряду с этим было добавлено немало новшеств, по большей части
в области управляющих структур.
Так, появилась долгожданная конструкция IF … THEN … ELSE … ENDIF. Улучшены были также циклы, например, появился цикл с предусловием (ранее цикл выполнялся минимум один раз, и зачастую приходилось добавлять условный оператор, чтобы обойти цикл при необходимости). Изменения коснулись и типов данных. Так, добавился символьный тип (ранее литеры хранились в целочисленных переменных, наобои средства работы с литерами были весьма рудиментарны). Помимо однородных массивов, появились структуры, подобные структурам C и записям Pascal.
На этом эволюция языка долгожителя не остановилась, и в 1990 г. увидел свет очередной стандарт, FORTRAN 90. Впрочем, он слишком опоздал со своим появлением, дав приличную фору по времени своим конкурентам, главным из которых явился, безусловно, C++. Несмотря на очевидные усовершенствования языка, FORTRAN 90 не получил такого ошеломляющего успеха, как его знаменитые предшественники, и удовольствовался весьма скромной нишей. Не прибавило ему популярности и появление следующего стандарта, FORTRAN 95. Новое поколение программистов ориентировано на C++, Java и C#, и старому доброму FORTRAN’у, увы, нечего им противопоставить.

0

5

COBOL
Как явственно следует из самого названия (Common Business Oriented Language), этот язык в первую очередь ориентирован на сферу приложений
для экономики и бизнеса. Первая его версия появилась в 1960 г., а последний вариант пересмотренного и дополненного стандарта – в 1972 г.
Специфика предметной области определила основные черты языка: для экономических расчетов характерны несложные алгоритмы при большом объеме ввода-вывода. Также для облегчения обучения целевой аудитории языку его синтаксис был максимально приближен к разговорному английскому. В результате практически каждый владеющий английским в состоянии прочитать и понять программу на COBOL’е без дополнительных комментариев, даже если раньше ему не доводилось иметь дело с этим языком: программа больше напоминает рассказ о выполняемой последовательности действий,
чем собственно программу.
Учитывая многообразие оборудования, сложившееся ко времени появления языка, при его разработке были предприняты меры, повышающие мобильность кода. Было определено обязательное ядро языка, которое должно быть реализовано на любой машине, включая самые маломощные. Кроме того, язык мог дополнительно включать в себя массу расширений; однако программист, использующий лишь конструкции, входящие в ядро, мог быть уверен, что его код будет работоспособен на любой стандартной реализации COBOL.
Программа на языке COBOL состоит из четырех разделов. Первый, раздел идентификации, позволяет задать имя программы и автора, а также включить некоторые дополнительные сведения о ней. Второй, раздел оборудования, описывает тип компьютера, на котором должна выполняться программа, а также отображение логических файлов ввода-вывода на физические.
Раздел данных, разумеется, содержит описания используемых структур данных, а раздел процедур – собственно выполняемый код. (Несмотря на название раздела, использование процедур в COBOL применяется редко, а в минимальной версии языка подпрограммы могут быть вообще не реализованы; функции в привычном нам виде вообще отсутствуют). Среди управляющих структур имеются вездесущий оператор GO TO, условный IF … THEN … ELSE в несколько урезанном виде и многоцелевая инструкция PERFORM, при помощи которой можно организовать цикл либо вызвать подпрограмму.
Как правило, все переменные глобальны и описываются в разделе данных. Структуры данных разнообразнее. Здесь имеются обычные однородные массивы, а также неоднородные, называемые записями. При этом элементом однородного массива может быть запись, и наоборот. Запись также определяет структуру внешних файлов, средства для работы с которыми весьма развиты, включая операции ввода-вывода для последовательных, индексно-последовательных и файлов прямого доступа, а также сортировки данных. Имеется также генератор отчетов, позволяющий получать достаточно сложные структуры отчетов. В завершение приведу небольшой фрагмент программы на COBOL:

DATA DIVISION.
FILE SECTION.
FD INP-DATA LABEL RECORD IS OMITTED.
01 ITEM-PRICE.
02 ITEM PICTURE X(30).
02 PRICE PICTURE 9999V99.
02 FILLER PICTURE X(44).

PROCEDURE DIVISION.
START.
OPEN INPUT INP-DATA AND OUTPUT RESULT-FILE.
READ-DATA.
READ INP-DATA AT END GO TO PRINT-LINE.
ADD PRICE TO TOT.
ADD 1 TO COUNT.
MOVE PRICE TO PRICE-OUT.
MOVE ITEM TO ITEM-OUT.
WRITE RESULT-LINE FROM ITEM-LINE.
GO TO READ-DATA.
PRINT-LINE.
MOVE TOT TO SUM-OUT

0

6

Algol 60
Этот язык, пожалуй, самый загадочный из всех упомянутых в данной статье. Он воплотил в себе все передовое, что было наработано теоретиками и практиками к моменту своего появления (конец 50-х годов), однако был встречен промышленностью и военными довольно прохладно и так и не получил должного признания. Однако несмотря на это, роль Algol 60 (в дальнейшем – Algol) в истории языков программирования огромна, потому что идеи, заложенные в этом зыке, получили дальнейшее развитие и породили целую плеяду так называемых «алголоподобных» языков, среди которых я бы в первую очередь выделил Algol 68 и Pascal. Эти языки получили значительное большее распространение (а уж историю Pascal иначе, как триумфом,
и не назовешь). Кроме того, эти языки в процессе своего развития в свою очередь стали основой для еще более развитых и мощных языков. Впрочем, о них поговорим в свое время, а сейчас вернемся к Algol’у. Своеобразие роли Algol’а в информатике заключается еще и в том, что этот язык стал алгоритмическим, в отличие от подавляющего большинства других языков, являющихся языками программирования. Эти понятия зачастую путают, но на самом деле это далеко не синонимы. Алгоритм можно реализовать практически на любом языке программирования, будь то FORTRAN, FORTH или APL. Особенность Algol’а заключается в том, что этот язык обладал непревзойденными (на время своего появления, конечно) выразительными средствами для строгого и изящного представления алгоритма (свойства, которые Дейкстра ценил превыше всего). В результате, не получив признания в промышленности
как язык программирования, Algol стал стандартом де-факто для публикации алгоритмов в научной среде. Так, например, на страницах Communications of the ACM долгие годы ему отдавалось предпочтение перед другими языками.
Лично мне Algol среди прочих языков программирования представлялся всегда в роли латыни среди естественных языков. Латынь ныне – мертвый язык, используется на практике в ограниченной среде лишь медиками, биологами и т.п. Однако от нее произошли многие современные языки романской группы, и классическое образование лингвиста не будет полноценным без тщательного изучения латыни. Жаль, что педагоги от информатики нынче почему-то пренебрегают им. Algol разрабатывался комитетом, специально созданным для разработки языка высокого уровня общего назначения, пригодного для научных вычислений (хотя в промышленности в то время царила эйфория, навеянная успехом FORTRAN’ а, в академической среде находились люди, способные заглянуть дальше и видящие, в какой тупик со временем неизбежно заведет FORTRAN).
Интересно, что впервые в истории язык был определен формально. По иронии судьбы Algol, которому было предназначено противопоставить четкость и элегантность конструкций хаотичности и сумбурности FORTRAN’а, был описан посредством модификации Нормальной Формы Бэкуса (создателя
FORTRAN’а). Нормальная Форма Бэкуса была доработана одним из членов комитета, Питером Науром, и в дальнейшем стала известна как Расширенная Форма Бэкуса-Наура (РБНФ). РБНФ оказалась настолько удобной формой описания синтаксиса формальных языков, что в дальнейшем практически все языки программирования стали описываться в этой нотации (еще один, косвенный вклад Algol’а в развитие информатики).
В частности, Дейкстра писал: «Четвертый проект, о котором следует упомянуть, – это ALGOL 60. В то время как до сих пор программисты на FORTRAN’e продолжают осознавать свой язык в рамках конкретной реализации, с которой они работают – отсюда и избыток восьмеричных или шестнадцатеричных
дампов, – в то время как определение языка LISP остается причудливой смесью описаний, что означает язык и как работает его механизм, знаменитый «Отчет об алгоритмическом языке ALGOL 60» – это продукт усилий по продвижению абстракции на один жизненно важный шаг дальше и по определению языка программирования способом, независимым от реализации. Кое-кто может возразить, что в этом отношении его авторы столь преуспели, что им удалось посеять серьезные сомнения, может ли он вообще быть реализован! «Отчет» великолепно демонстрирует мощь формального метода BNF, теперь справедливо известного как Backus-Naur-Form (Формализм Бэкуса-Наура, или Форма Бэкуса-Наура – прим. перев), и силу тщательно сформулированного английского языка, по крайней мере в изложении тех, кто владеет им столь же блестяще, как Питер Наур. Я думаю, справедливо будет заметить, что очень немногие документы, столь же короткие, как этот, оказали такое глубокое влияние на компьютерное сообщество. Легкость, с которой в последующие годы слова «ALGOL» и «ALGOL-подобный» использовались как незащищенные торговые марки, чтобы придать часть своей славы незрелым проектам, порой имеющим весьма слабое отношение к предмету, – это порой обескураживающий комплимент его основам. Сила BNF как определяющего механизма в ответе за то, что я расцениваю как одну из слабостей языка: переработанный и не слишком систематический синтаксис мог бы теперь быть втиснут всего в несколько страниц. Располагая столь мощным инструментом, каким является BNF, «Отчет об алгоритмическом языке ALGOL 60» должен был бы быть значительно короче». (Цитата из статьи «Смиренный программист» (EWD340)).
Как и в большинстве других языков программирования, программа на Algol’е состоит из главной программы и набора подпрограмм. При их построении используются блоки – наборы описаний и последовательности операторов, ограниченные «скобками» begin и end. Структуры данных, созданные внутри блока, локальны в его пределах и при выходе из блока уничтожаются. Таким образом можно управлять временем жизни данных и областью видимости
их идентификаторов.
Определение подпрограммы состоит из заголовка, в котором указываются имя подпрограммы и перечисляются имена и типы ее формальных параметров, и тела, которое представляет собой просто блок. Динамическое выделение памяти для переменных в блоке позволяет эффективно использовать рекурсию.
К особенностям языка можно отнести механизмы передачи параметров подпрограммам. Их два: хорошо известная передача по значению и довольно экзотическая передача по имени. В большинстве случаев она эквивалентна общеизвестной передаче по ссылке, однако между этими механизмами имеются довольно тонкие различия, которые в некоторых случаях могут привести к неожиданным сюрпризам.
Очень важно, что блоки могут образовывать вложенные структуры, т.е. внутри блока может быть вложен блок, в него – другой блок и т.д. Важной особенностью языка является также то, что блок является разновидностью оператора – составным оператором и может быть употреблен везде, где допустим обычный оператор. В сочетании с развитым набором структурных управляющих конструкций (условный оператор, цикл со счетчиком, циклы с пред- и постусловием) это позволяет строить хорошо структурированные программы, обходясь без оператора go to, столь нелюбимого сторонниками ясности и элегантности программ.
К сожалению, типы и структуры данных в языке гораздо менее разнообразны, чем управляющие конструкции. Пожалуй, это и определило дальнейшую судьбу языка, применявшегося в первую очередь для научных вычислений. Из типов имеются логический, целочисленный и вещественный, а из структур данных – лишь однородный массив. Правда, массивы являются динамическими, что позволяло эффективно управлять распределением памяти.
Пример программы на Algol’е:
begin
procedure SUM(V, N);
  value N;
  real array V;
  integer N;
  begin
    integer I;
    real TEMP;
    TEMP := 0;
    for I := 1 step
      1 until N do TEMP := TEMP+ V[i];
    SUM := TEMP
    end;
  integer K;
  START:
  inreal(1, K);
  if K > 0 then
  begin
    real array A[1:K];
    inarray(1, A);
    outreal(2,SUM(A, K));
    goto
START endend

0

7

а дельфи паскаль забыл что ли ?

0

8

а дельфи паскаль забыл что ли ?

До Delphi еще далеко было, а паскаль будет скоро))

0

9

Algol 68
В процессе использования Algol 60 выявлялись недочеты, допущенные при проектировании языка. В 1962 году под эгидой Международной федерации по обработке информации (International Federation for Information Processing, IFIP) был создан новый комитет, задачей которого являлись исправление и совершенствование Algol. В составе нового комитета оказалось немало ученых с мировым именем, в частности, Эдсгер Дейкстра, Никлаус Вирт и Тони Хоар.
Один из авторов разработки, Кеес Костер, впоследствии написал мемуары, в которых достаточно детально обрисовал как сам процесс, так и дух, царивший в то время в комитете. (Они были опубликованы среди прочих материалов 11 февраля 1993 года на конференции «25 лет Algol’у 68» Леннартом Беншопом).
Одной из очевидных слабостей предшествующей версии был признан слабо развитый ввод/вывод. Пренебрежение к этому моменту объяснялось академической направленностью языка: для ученых главный интерес представляет сам алгоритм, а в каком виде будут представлены выходные данные – дело второстепенное. Для промышленных  применений такой подход не годился, поэтому одной из приоритетных задач была объявлена разработка
механизма ввода/вывода.
Вторым важным моментом, который нельзя было сбрасывать со счетов, была сильная позиция FORTRAN’ а. Язык, проигрывающий FORTRAN’у по эффективности на этапе выполнения программы, не мог претендовать на успех. Главенствующую роль в разработке играл А. Ван Вейнгаарден, директор Математического центра Амстердама. Будучи по образованию и роду деятельности чистым математиком, порой он, пользуясь своим авторитетом, принимал решения, с которыми не соглашались программисты практики, что отложило свой отпечаток на получившийся в результате язык.
К сожалению, авторитарный стиль руководства ван Вейнгаардена нередко приводил к размолвкам в коллективе и даже стал причиной выхода Хоара и Вирта из команды. О том, как тяжела была эта потеря для команды, можете судить по такому факту: предложения Вирта, не принятые комитетом, легли в основу языка Algol W, который впоследствии перерос в Pascal. Время в итоге расставило все по своим местам – сравните нынешнюю популярность
Pascal’я и Algol’а 68. Или, что еще убедительнее, спросите программиста с опытом в несколько лет, что говорят ему фамилии Вирт и ван Вейнгаарден. Результат, думаю, скажет сам за себя. Хотя, безусловно, язык Algol 68 содержал немало рациональных зерен (например, механизмы расширения языка, а также средства для параллельных вычислений), он получил ограниченное применение. В Европе и, в частности, в России были коллективы энтузиастов языка, активно использовавших его в работе, и язык на основе Algol’а 68 стал некогда базовым для программирования отечественного компьютера  «Эльбрус», но мировой известности язык так никогда и не получил.

0

10

PL/1
В середине 60-х годов корпорацией IBM был организован комитет, целью которого было создание многоцелевого языка программирования. В это время на смену уникальным компьютерам, создававшимся в единичных экземплярах в стенах университетов и исследовательских лабораторий, стали приходить
промышленные компьютеры серийного изготовления. Цены на оборудование быстро падали, соответственно ширился круг задач, решаемых при помощи компьютеров.
Если раньше в связи с высокой ценой машинного времени эти задачи преимущественно носили характер расчетов для научных и военных целей, то теперь можно было позволить себе автоматизировать экономические расчеты, управление производством и т.п. Тем не менее в распоряжении программистов не было достаточно мощного языка, пригодного для решения подобных задач.
Новый язык должен был стать преемником FORTRAN’а, Algol’а и COBOL’а одновременно. Фактически он унаследовал все лучшее от своих педшественников. От FORTRAN’а ему достались раздельная компиляция подпрограмм, форматный ввод/вывод, блоки COMMON; от Algol’а – блочная структура и структурированные управляющие конструкции; от COBOL’а – неоднородные массивы и ввод/вывод, ориентированный на записи. Этот язык получил название PL/1.
Программа на PL/1 состоит из набора подпрограмм, структура которых аналогична подпрограммам Algol. Подпрограммы могут компилироваться
раздельно, что облегчает создание библиотек подпрограмм и повторное использование кода. Параметры передаются по ссылке. Допускается рекурсия при вызове подпрограмм. Предусмотрены также средства для параллельного выполнения подпрограмм (задач) и взаимодействия между ними.
Типы данных включают многочисленные простые типы, битовые цепочки, цепочки литер, указатели, метки. Допустимы также структуры данных, представляющие собой однородные и неоднородные массивы. При помощи таких структур программист может образовывать новые типы данных. Для преобразования типов друг в друга имеется большой набор встроенных примитивов.
Язык обладает богатым набором математических и логических операций над числовыми данными. Для обмена данными с внешними файлами также предусмотрен развитый механизм. Получившийся в результате этого проекта язык обладал большим набором средств, позволяющих применять
его практически для любых прикладных задач. Но эта всеядность имеет обратную сторону: язык получился настолько громоздок и сложен, что, во-первых, оказалось чрезвычайно трудно разработать компилятор, дающий эффективный код; во-вторых, изучить язык в полном объеме – также нелегкая задача. Разработчики пошли на компромисс: начинающий программист может оперировать неким подмножеством языка, достаточным для его задач. Хотя в языке имеется огромное количество всевозможных опций, для каждой из них имеется значение по умолчанию, которое по замыслу разработчиков должно устроить начинающего пользователя. Впрочем, подобные решения, неявно принимаемые машиной за пользователя, рано или поздно непременно становятся источником недоразумений, причину которых понять не столь просто.
Если вкратце подвести итог развития PL/1, то в нескольких словах его можно сформулировать так. Язык имел весьма скромные средства для расширения, поэтому разработчикам пришлось предусмотреть все необходимое и включить его в язык. В результате получился огромный неуклюжий монстр, не получивший распространения вне продуктов IBM (в нашей стране он довольно широко использовался, будучи унаследованным вместе с семейством IBM 360/370 в виде ЕС ЭВМ). Разумеется, эти свойства языка обусловили его крайне прохладный прием в академической среде. Вот, в частности, что писал Дейкстра в своей статье Смиренный программист (EWD340): «Наконец, хотя этот предмет не из приятных, я должен упомянуть PL/1, язык программирования,
документация которого обладает устрашающими размерами и сложностью. Использование PL/1 больше всего напоминает полет на самолете с 7000 кнопок, переключателей и рычагов в кабине. Я совершенно не представляю себе, как мы можем удерживать растущие программы в голове, когда из-за своей полнейшей вычурности язык программирования – наш основной инструмент, не так ли! – ускользает из-под контроля нашего интеллекта. И если мне понадобится описать влияние, которое PL/1 может оказывать на своих пользователей, ближайшее сравнение, которое приходит мне в голову, – это наркотик. Я помню лекцию в защиту PL/1, прочитанную на симпозиуме по языкам программирования высокого уровня человеком, который представился
одним из его преданных пользователей.
Но после похвал в адрес PL/1 в течение часа он умудрился попросить добавить к нему около пятидесяти новых «возможностей», не предполагая, что главный источник его проблем кроется в том, что в нем уже и так слишком уж много «возможностей». Выступающий продемонстрировал все неутешительные
признаки пагубной привычки, сводящейся к тому, что он впал в состояние умственного застоя и может теперь только просить еще, еще, еще… Если FORTRAN называют детским расстройством, то PL/1, с его тенденциями роста подобно опасной опухоли, может оказаться смертельной болезнью».
Пример программы на PL/1:
TEST: PROCEDURE OPTIONS (MAIN);
START:
GET LIST (K);
IF k > 0 THEN
BEGIN;
DECLARE A(K) DECIMAL FLOAT;
GET LIST (A);
PUT LIST (‘INPUT IS ‘, A, ‘SUM IS ‘, SUM(A));
GO TO START;
END;
SUM: PROCEDURE (V);
DECLARE V(*) DECIMAL FLOAT, TEMP DECIMAL FLOAT INITIAL (0);
DO I = 1 TO DIM(V,1);
TEMP = TEMP + V(I);
END;
RETURN (TEMP);
END SUM;
END TEST;

0

11

Pascal
Судьба языка Pascal во многом являет собой полную противоположность рассмотренным выше. Мы уже видели примеры языков программирования, которые проектировались с целью ни много ни мало оттеснить конкурентов, завоевать лидирующие позиции в промышленности, стать универсальным средством решения любых задач на компьютере… Большинству из них не суждено было реализовать своих притязаний, и ныне они почти забыты, возникая из небытия лишь для полноты исторических обзоров вроде данного.
Язык впервые увидел свет в 1972 году, хотя основные идеи, заложенные в него, сформировались значительно раньше, в середине 1960-х. Автор Pascal’я, профессор Цюрихского университета Никлаус Вирт, в начале своей работы был лишен подобных вселенских амбиций. Как он впоследствии писал в своих мемуарах, он обучал студентов программированию на языках FORTRAN и Algol, и оба эти языка казались ему неподходящими для целей обучения программированию. Поэтому он решил разработать новый язык, в большей степени пригодный для обучения. Однако получившийся в результате язык шагнул далеко за пределы учебных аудиторий. Он был реализован практически на всех компьютерах, от 8-разрядных на базе микропроцессоров Intel 8080 и Z80 до солидных мэйнфреймов IBM и CDC, а для популярнейших IBM PC-совместимых персональных компьютеров стал одним из основных средств разработки прикладных программ благодаря превосходным инструментальным системам фирмы Borland (ныне Inprise).
В немалой степени Pascal базируется на идеях Algol’а, позаимствовав у него основные структурные конструкции. Впрочем, это не слепое подражание предшественнику, а вполне самостоятельный язык, которому удалось избежать многих слабостей и ограничений Algol’ а. Можно сказать, что немалую лепту в появление языка на свет внесло упрямство ван Вейнгаардена, руководителя комитета по разработке Algol 68, благодаря которому Вирт был вынужден
покинуть комитет и самостоятельно реализовать свои идеи.
Структура программы на Pascal, как и сам язык в целом, весьма проста и логична. Программа состоит из заголовка, разделов меток, констант, типов, переменных и процедур, за которыми следует тело программы. Метки присутствуют в языке как дань оператору goto, отказаться от которого Вирт не решился (да и чего греха таить, попадаются иногда ситуации, когда без использования goto программа становится громоздкой и малопонятной).
Возможность использования констант позволяет создавать более читаемые и легкие для понимания программы. Должным образом подобранное имя константы может оказаться гораздо информативнее, чем ее значение, там и тут разбросанное в тексте программы, да и изменить это значение при необходимости не в пример легче.
Набор типов, доступных программисту, гораздо шире, чем в Algol’е. Помимо известных логического, целочисленного и вещественного типов, Pascal предоставляет символьный тип, а также принципиально новый тип – множество. Кроме того, имеются средства, позволяющие строить новые типы как ограниченные диапазоны целочисленного, а также перечисления. Имеются также структурированные типы – однородные (массивы) и неоднородные (записи), которые также образуют новые типы. При этом элементом массива или записи также может быть структурированный тип, что позволяет строить довольно изощренные структуры.
Принципиально новым по сравнению с предшественником является понятие указателя, что позволяет программисту работать не только со статическими переменными, но и при необходимости создавать их в «куче» во время выполнения программы. Создать средствами Pascal’я дерево, связный список или стек при помощи указателей можно гораздо эффективнее, нежели с использованием статических массивов. Процедуры и функции поддерживают передачу параметров как по значению, так и по ссылке, позволяя при необходимости использовать побочные эффекты. Они могут быть вложенными, что позволяет гибко управлять областью видимости каждой из них. Поскольку локальные переменные создаются в стеке, допустима рекурсия, как прямая, так и косвенная. В случае использования косвенной рекурсии может возникнуть противоречие, т.к. в языке строго действует правило: подпрограмма должна быть объявлена перед ее использованием. Разорвать этот круг можно посредством объявления подпрограммы с ключевым словом forward.
Набор операторов языка позволяет строить хорошо структурированные программы. Среди них есть условный оператор if … then … else …, операторы цикла со счетчиком for … to/downto … do …, а также циклы с предусловием while … do … и с постусловием repeat … until … Кроме того, как расширение условного оператора if добавлен оператор выбора case, позволяющий организовать переключение на одну из многочисленных альтернативных ветвей
программы. Имеется также оператор присоединения with, на мой взгляд, очень удачная находка, которой почему-то лишены более поздние языки вроде C++, Java и C#.
Конечно же, не лишен язык и некоторых слабостей. Одним из наиболее серьезных недочетов является то, что размер массива задает его тип. В соответствии со строгой типизацией это приводит к тому, что, например, процедура, сортирующая массив из 10 элементов, откажется сортировать массив из 100 элементов, поскольку формально они относятся к разным типам, даже если их элементы одного типа. Предусмотреть же разновидности сортировки для массивов разных размеров можно, но это загромождает программу и делает ее более подверженной ошибкам.
Тем не менее, сильных сторон у языка оказалось гораздо больше. На фоне языков FORTRAN, PL/I и Algol 60 он явился большим шагом вперед. Довольно быстро последовали реализации для различных платформ, поскольку язык был достаточно прост. Язык быстро завоевал прочные позиции в компьютерном мире, потеснив основных конкурентов, а его автор приобрел мировую известность.
В качестве иллюстрации приведу программу распечатки десятичного представления отрицательных степеней двойки (заимствовано из Вирт Н. Алгоритмы + структуры данных = программы: Пер. С англ. – М.: Мир, 1985):
program power(output);
const
n = 10;
type
digit = 0..9;
var
i, k, r: integer;
d: array [1..n] of digit;
begin
for k := 1 to n do
begin
write(‘.’);
r := 0;
for i := 1 to k – 1 do
begin
r := 10 * r + d[i];
d[i] := r div 2;
r := r – 2 * d[i];
write(chr(d[i] + ord(‘0’)))
end;
d[k] := 5;
writeln(‘5’)
end
end.

0

12

MODULA-2
Появление языка Pascal дало разработчикам программного обеспечения строгий и выразительный инструмент для создания ясных и хорошо структурированных программ, - тот самый инструмент, который был столь необходим в условиях известного «кризиса программного
обеспечения», становившегося все острее в то время. Однако неверным было бы считать, что все трудности информатики остались позади. Действительно, новый язык вполне адекватно поддерживал парадигму структурного программирования, которая позволяла справляться со сложными задачами путем декомпозиции их на более простые, легче решаемые. Декомпозиция является великолепным средством борьбы со сложностью, позволяя человеческому разуму с ограниченными возможностями охватывать как всю задачу в целом, так и каждую ее часть детально, переходя с одного уровня абстракции на другой. Однако у декомпозиции есть и другая сторона.
Разбив задачу на несколько относительно независимых, слабо связанных подзадач, мы получаем возможность привлечь к работе над проектом нескольких программистов. Если каждый из них получит ясную спецификацию своей части, в которой оговорено, какие данные поступают на вход и какие требуются на выходе, каждый из них сможет выполнять работу параллельно. Кроме того, каждая часть может в свою очередь быть подвержена декомпозиции, что позволяет произвести дальнейшее распараллеливание. Таким образом, можно обеспечить возможность согласованной коллективной работы над проектом при условии, что каждая часть строго соответствует спецификациям (что возможно в процессе тестирования). Разумеется, не следует думать, что структурное программирование возникло именно благодаря языку Pascal, скорее наоборот. Идеи структурного программирования витали в воздухе задолго до его появления. Да и проекты на FORTRAN и COBOL выполнялись не в одиночку; однако именно в Pascal’е идеи структурного программирования были воплощены Виртом в рафинированном виде.
Однако именно коллективная работа над проектом явилась наиболее слабой стороной Pascal’я. Язык, задуманный изначально как учебный, не содержал в себе никаких средств для разделения программы на независимые части – модули – с последующей сборкой модулей в единое целое. Для компиляции программы весь ее исходный текст должен быть собран в единое целое. Такой подход имеет ряд недостатков. Пожалуй, главный из них – огромная нагрузка на компилятор. Достаточно поменять одну строчку в процедуре, чтобы весь проект в тысячи или десятки тысяч строк пришлось перекомпилировать заново. Те, кому довелось работать с оборудованием 80-х годов выпуска, должны помнить, насколько это небыстрый процесс. Да и «склейка» большого файла из отдельных кусков тоже не слишком приятная задача.
Конечно же, различные реализации компиляторов по-разному пытались бороться с этой проблемой (впрочем, без особого успеха). Так, один из компиляторов для PDP-11 позаимствовал из языка C конструкцию #include, избавив программиста от сборки проекта в один исходный файл. Впрочем, эта полумера не избавляла от необходимости полной перекомпиляции при внесении малейшего изменения в программу. Другое расширение языка позволяло компилировать фрагменты программы отдельно, каждый фрагмент в свой объектный модуль. При этом «внешние» процедуры описывались одним лишь заголовком с ключевым словом external. Затем компоновщик собирал объектные модули воедино в загрузочный образ программы. Такой подход, получивший название независимой компиляции, позволил избежать полной перекомпиляции проекта, выигрывая немало времени.
Впрочем, независимая компиляция таит в себе большую опасность. Компилятор никоим образом не может проверить соответствие объявления процедуры и ее реализации, полагаясь лишь на внимательность программиста. Практика же показывает, что любая технология, полагающаяся на внимательность и ответственность человека, обречена на провал. Ошибки, связанные с неправильной передачей параметров между раздельно скомпилированными
процедурами, не так легко обнаружить, поскольку система контроля типов здесь бессильна.
Выход из создавшейся ситуации предложил тот же Вирт, разработав следующий язык программирования – MODULA-2. (Этому проекту предшествовал другой, экспериментальный язык MODULA, который, впрочем, не вышел за стены лаборатории Вирта и о котором подробно рассказывать я не вижу смысла).
Синтаксис MODULA-2 весьма напоминает Pascal, и понять программу на MODULA-2, зная Pascal, не составит никакого труда. Набор операторов практически не изменился, встроенные типы данных также не претерпели существенных изменений, равно как и основные структуры. Впрочем, разработчики получили небольшой подарок: поскольку многие высказывали претензии к операторным скобкам Pascal’я begin/end, весьма громоздким по сравнению
с {/}, столь привычным пишущим на C, многие операторы (операторы цикла, условные операторы и др.) начинаются неявной открывающей скобкой, делая многочисленные begin’ ы ненужными. Таким образом, многие операторы являются составными автоматически и требуют лишь явного закрытия посредством end. (Хотя такой подход может обескуражить знатоков Pascal, однако поклонники Visual Basic вряд ли будут этим удивлены).
Однако все это мелочи по сравнению с главной идеей: в языке появилось понятие модуля. Фактически модуль – это самостоятельно компилируемый фрагмент программы, состоящий из двух основных частей: интерфейса и реализации. Интерфейс – это некий контракт, который модуль обязуется соблюдать. В нем описываются сигнатуры процедур и функций, а также объекты, к которым можно обращаться извне (разумеется, слово «объекты» не следует понимать в смысле, привычном для ООП). Реализация – это закрытая часть модуля, содержащая его физическое воплощение в виде тел подпрограмм, локальных переменных и т.д.
В результате компиляции модуля образуются два файла: файл описания интерфейса и объектный файл. Для того, чтобы воспользоваться модулем, необходимо его импортировать. При импорте модуля используется описание его интерфейса и тем самым гарантируется столь же строгий контроль типов, как и в пределах локального модуля. При этом отслеживается соответствие версии модулей. Например, если модуль A импортирует модуль B и при этом в модуль B были внесены изменения, повлекшие изменение интерфейса, модуль A также потребует перекомпиляции. Если же изменения коснулись лишь реализации, а интерфейс остался неизменным, перекомпиляция A не потребуется. Таким образом, MODULA-2 не полагается на внимательность и аккуратность программиста, а подвергает согласованность интерфейсов строгому контролю при каждой компиляции.
Из других особенностей языка я бы отметил некоторые низкоуровневые средства, напоминающие C, для доступа к регистрам ввода/вывода и обработки прерываний, позволяющие использовать MODULA-2 для управления объектами в реальном времени, а также поддержку распараллеливания вычислений на уровне стандартной библиотеки.
Следует отметить, что по непонятным мне причинам язык не получил широкого распространения, несмотря на явные преимущества перед своим предшественником. Хотя Вирт доказал на деле гибкость и мощность нового языка, разработав на нем операционную систему Medos и все программное обеспечение для довольно интересной мини-ЭВМ Lilith, программисты  не спешили оставить полюбившийся им Pascal и перейти на MODULA-2.
В заключение – исходный текст программы для рисования кривой Серпински (заимствовано из Вирт Н. Программирование на языке Модула-2: Пер. с англ. – М.: Мир, 1987):
MODULE Serpinsky;
FROM Terminal IMPORT Read;
FROM LineDrawing IMPORT width, Height, Px, Py, clear, line;
CONST
SqrSize = 512;
VAR
i, h, x0, y0: CARDINAL;
ch: CHAR;
PROCEDURE A(k: CARDINAL);
BEGIN
IF k > 0 THEN
A(k-1);
line(7, h);
B(k-1);
line(0, 2*h);
D(k-1);
line(1, h);
A(k-1)
END
END A;
PROCEDURE B(k: CARDINAL);
BEGIN
IF k > 0 THEN
B(k-1);
line(5, h);
C(k-1);
line(6, 2*h);
A(k-1);
line(7, h);
B(k-1)
END
END B;
PROCEDURE C(k: CARDINAL);
BEGIN
IF k > 0 THEN
C(k-1);
line(3, h);
D(k-1);
line(4, 2*h);
B(k-1);
line(5, h);
C(k-1)
END
END C;
PROCEDURE D(k: CARDINAL);
BEGIN
IF k > 0 THEN
D(k-1);
line(1, h);
A(k-1);
line(2, 2*h);
C(k-1);
line(3, h);
D(k-1)
END
END A;
BEGIN
clear;
i := 0;
h := SqrSize DIV 4;
x0 := CARDINAL(width) DIV 2;
y0 := CARDINAL(height) DIV 2 + h;
REPEAT
i := i + 1;
x0 := x0 – h;
h := h DIV 2;
y0 := y0 + h;
Px := X0;
Py := Y0;
A(i);
line(7,h);
B(i);
line(5, h);
C(i);
line(3, h);
D(i);
line(1, h);
Read(ch)
UNTIL (i = 6) OR (ch = 33C);
clear
END Serpinsky.

0


Вы здесь » Студент "Информатик" » Библиотека » Экскурс в историю


Создать форум.