Москва 2001 г тайный язык информатики Чарльз Петцольд ббк 32. 973. 26–018



Pdf көрінісі
бет22/26
Дата07.04.2020
өлшемі3,29 Mb.
#61783
1   ...   18   19   20   21   22   23   24   25   26
Байланысты:
Petcold Kod-Taynyy-yazyk-informatiki.535358

Глава 24

Языки высокие и низкие

Программировать в машинных кодах — все равно что есть

зубочисткой. Подхватывать ею кусочки еды столь сложно, а

сами они столь малы, что обед растягивается в вечность. Бай-

тами машинных кодов обозначены настолько простые вычис-

лительные задачи — загрузка числа из памяти в процессор,

сложение его с другим числом, запись результата обратно в

память, — что практически невозможно представить себе, как

из таких крохотных кирпичиков складывается целое здание.

Еще в начале главы 22 мы вводили двоичные данные в па-

мять переключателями, но с тех пор нам удалось здорово про-

двинуться вперед. В той же главе я рассказал, как с помощью

простых программ задействовать клавиатуру для ввода дан-

ных (например, машинных кодов) и просматривать их на эк-

ране монитора. После этого работать на нашем воображаемом

компьютере стало удобнее, но все возможные усовершенство-

вания нами еще не исчерпаны.

Как вы помните, байтам машинных кодов сопоставлены

короткие мнемонические коды MOV, ADD, CALL, HLT, благо-

даря которым программа по крайней мере отдаленно напоми-

нает набор указаний на обычном английском языке. Часто за

мнемокодом следует аргумент, уточняющий действие коман-

ды. Например, в системе команд процессора 8080 команда с

кодом 46h помещает в регистр В байт из ячейки памяти, адрес

которой записан в паре регистров HL. С помощью мнемокода

это действие выражается нагляднее:



440

Глава двадцать четвертая

MOV B,[HL]

Конечно, составлять программу на языке ассемблера гораздо

проще, чем писать ее в машинных кодах. Увы, процессор ас-

семблера не понимает. Поэтому программу в мнемокодах при-

ходится писать на бумаге. Когда вам кажется, что она готова к

запуску, вы вручную преобразуете операторы ассемблера в

двоичные машинные коды и вводите их в память.

Но почему не автоматизировать эту задачу? Для этого впол-

не достаточно компьютера с процессором 8080, работающего

под управлением ОС CP/M.

Для начала создайте текстовый файл PROGRAM1.ASM и

введите в него программу на ассемблере (тип ASM как раз и

означает, что в файле содержится ассемблерная программа).

Для создания и редактирования файла можно применить тек-

стовый редактор из комплекта CP/M — программу ED.COM.

Слишком сложную задачу перед собой ставить не будем:

ORG 0100h

LXI DE,Text

MVI C,9


CALL 5

RET


Text: DB 'Hello!$'

END


Почти все операторы этой программы нам знакомы. Команда

ORG, с которой мы раньше не встречались, не входит в систе-

му команд процессора 8080. Она просто указывает, что следу-

ющая команда должна располагаться по адресу 0100h. Как вы

помните, начиная именно с этого адреса, CP/M загружает про-

граммы в память.

Следующая команда — LXI — загружает 16-битовое значе-

ние в пару регистров DE. Здесь адрес значения указан меткой

Text, расположенной в конце программы перед оператором DB

(Data Byte, байт данных). Аргументами оператора DB могут быть

несколько байтовых значений, разделенных запятыми, или (как

у нас) текстовая строка, заключенная в апострофы.

Команда MVI помещает в регистр С число 9. Это номер

функции CP/M для отображения на экране текстовой строки,

начинающейся по адресу, записанному в регистрах DE, и за-


441

Языки высокие и низкие

канчивающейся значком доллара $ (немного странно, что окон-

чание строки обозначается именно значком $, но так уж уст-

роена CP/M). Функцию вызывает оператор CALL 5. Наконец,

команда RET останавливает выполнение программы и пере-

дает управление системе (остановить программу можно и ина-

че). Оператор END отмечает конец файла с программой на ас-

семблере.

Итак, у нас есть текстовый файл, содержащий 7 строк. Те-

перь его нужно ассемблировать, т. е. преобразовать операторы

ассемблера в машинные коды. До сих пор мы делали это вруч-

ную. Но в CP/M входит специальная программа ASM.COM, ко-

торая выполнит это преобразование автоматически. Достаточ-

но ввести после приглашения системы команду:

ASM PROGRAM1.ASM

Программа ASM находит на диске файл PROGRAM1.ASM и

создает файл PROGRAM1.COM, в который помещает машин-

ные коды, соответствующие операторам ассемблера (честно

говоря, я пропустил один этап процесса ассемблирования, но

для понимания сути происходящего он не важен). После это-

го программу PROGRAM1 можно запускать из командной

строки CP/M. Она отобразит на экране строку «Hello!» и за-

кончит работу.

Файл PROGRAM1.COM содержит следующие 16 байтов:

11 09 01 0E 09 CD 05 00 C9 48 65 6C 6C 6F 21 24

Первые 3 байта — это команда LXI, следующие 2 — команда

MVI. 3 байта занимает команда CALL 5, и 1 — команда RET.

Последние 7 байт — это ASCII-коды букв Hello, восклицатель-

ного знака и знака $.

Работа программы-ассемблера, например, ASM.COM, сво-

дится к чтению файла с программой на языке ассемблера (про-

граммисты часто называют его файлом с исходным кодом) и

созданию  исполняемого  (executable) файла, содержащего ма-

шинные коды. По сути своей, ассемблеры — очень простые

программы, поскольку в основе их работы лежит взаимно од-

нозначное соответствие между мнемоническими и машинны-

ми кодами. Ассемблер считывает из файла строку, разделяет

ее на мнемокод команды и аргументы, а затем находит в спис-

ке машинный код, соответствующий такому сочетанию коман-


442

Глава двадцать четвертая

ды и аргументов (в списке должны быть все возможные соче-

тания). В результате сравнения появляется последовательность

машинных кодов, в точности соответствующая последователь-

ности команд.

Заметьте: вместо метки Text в код подставлен ее адрес 0109h.

Именно там окажется текстовая строка после того, как про-

грамма будет загружена в память, начиная с адреса 0100h.

Обычно программисту, пишущему программы на ассембле-

ре, не приходится беспокоиться из-за подстановки конкрет-

ных адресов — это делает ассемблер.

Программисту, написавшему первую программу-ассемб-

лер, конечно, пришлось переводить ее в машинные коды вруч-

ную. Следующую, улучшенную версию ассемблера для того

же компьютера, уже можно ассемблировать автоматически с

помощью первого ассемблера. Новый ассемблер приходится

разрабатывать каждый раз при появлении нового процессора.

Но заниматься этим можно на компьютере со старым процес-

сором и старым ассемблером.

Конечно, программы-ассемблеры избавляют программи-

ста от самой неблагодарной части работы — ручного перево-

да операторов в машинные коды. И все же язык ассемблера

отягощен двумя крупными недостатками. О первом из них вы,

вероятно, уже догадались: программирование на языке ассем-

блера — задача весьма кропотливая. Непосредственно управ-

ляя действием микропроцессора, приходится беспокоиться о

бесчисленных мелочах.

Второй недостаток в том, что программа на ассемблере не

является переносимой (portable). Например, программу, напи-

санную на языке ассемблера для процессора Intel 8080, нельзя

запустить на компьютере с процессором Motorola 6800. Пред-

варительно ее придется переписать на ассемблере для этого

процессора. Это, конечно, будет несложно, поскольку основ-

ные организационные и алгоритмические проблемы вы реши-

ли, создавая исходную программу, но работы все же хватит.

В главе 23 я писал о том, что в современные микропроцес-

соры встроены команды для работы с числами с плавающей

точкой. Они, конечно, облегчают программисту жизнь, но не

особо. Хотелось бы совершенно забыть о командах процессо-

ра для выполнения элементарных арифметических операций,



443

Языки высокие и низкие

используя для математических выражений проверенную ве-

ками алгебраическую форму записи, например:

´ Sin(2 ´ PI + B) / C



где A, B и C — произвольные числа, а PI равно 3,14159.

Так в чем проблема? Если это выражение записано в тек-

стовом файле, мы вольны создать программу на языке ассем-

блера, которая будет читать строки из этого файла и преобра-

зовывать их в машинные коды.

Если бы вам нужно было вычислить это выражение лишь

однажды, вы обошлись бы калькулятором. На создание про-

граммы вас, вероятно, подвигла необходимость вычислять его

многократно, с различными значениями коэффициентов A, B

и C. Значит, кроме этого выражения вам понадобятся и дру-

гие, для вычисления коэффициентов.

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



ня (high-level). Язык ассемблера считается языком низкого уров-

ня (low-level), поскольку он напрямую взаимодействует с обо-

рудованием компьютера. На практике языками высокого уров-

ня называют любые языки, кроме ассемблера, но это не значит,

что все они равнозначны. Уровень одних языков выше уровня

других языков. А знаете, что такое язык программирования

высочайшего уровня? Это когда президент компании набирает

на клавиатуре или, еще лучше, положив ноги на стол, диктует

секретарше: «Рассчитать прибыли и убытки за этот год, напи-

сать годовой отчет, распечатать 1 000 экземпляров и разослать

акционерам»! Конечно, настоящие языки программирования,

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

Человеческие языки формируются в течение сотен и ты-

сяч лет взаимопроникновения, случайных изменений и заим-

ствований. Даже в основу искусственных языков вроде эспе-

ранто положены реальные языки со всей их многовековой ис-

торией. Другое дело — языки программирования. Их созда-

ние всегда было продуманным и целенаправленным. Созда-

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

ление об общении человека и машины. В 1993 г. было подсчи-

тано, что с 1950-х годов разработано более 1 000 языков про-

граммирования.

Конечно,  изобретение  языка (т. е. разработка  синтаксиса

— правил построения выражений) — только полдела. Нужно


444

Глава двадцать четвертая

также написать компилятор (compiler), т. е.  программу, пре-

образующую операторы языка в машинные коды. Подобно

ассемблеру, компилятор символ за символом считывает файл

с исходной программой, разделяя его на слова, операторы и

числа. Написать компилятор, разумеется, гораздо сложнее, чем

ассемблер. Оператор ассемблера переводится в единственный

машинный код, тогда как оператор языка высокого уровня, как

правило, превращается во множество машинных команд. Раз-

работке компиляторов посвящена обширная литература.

У языков программирования высокого уровня есть свои

плюсы и минусы. Главное преимущество языка высокого уров-

ня в том, что он обычно намного превосходит ассемблер в лег-

кости изучения и использования. Программа на языке высо-

кого уровня короче и понятнее ассемблерной. Языки высоко-

го уровня в основном переносимы, т. е. одинаково хорошо

работают на компьютерах с разными процессорами. Это зна-

чит, что, создавая программу, не нужно вникать в тонкости

архитектуры компьютера, на котором она будет работать. Ко-

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

компилятор. Созданный им исполняемый файл также будет

годиться только для этого процессора.

С другой стороны, программа на ассемблере практически

всегда эффективнее аналогичной программы на языке высо-

кого уровня. Это значит, что исполняемый файл, созданный

компилятором языка высокого уровня, занимает больше мес-

та и работает медленнее, чем функционально идентичная про-

грамма на ассемблере. Нужно отметить, что в последние годы

это правило уже не выполняется с прежней неизменностью.

Микропроцессоры стали более сложными, а создатели компи-

ляторов достигли больших успехов в оптимизации генериру-

емых кодов.

Язык высокого уровня облегчает использование процессо-

ра, но не делает его мощнее. Любые действия, которые процес-

сор в состоянии выполнить, могут быть запрограммированы

на языке ассемблера. Это значит, что программа на языке высо-

кого уровня не наделяет процессор никакими новыми возмож-

ностями. Более того, чтобы сделать программу переносимой,

от некоторых специфических возможностей данного процес-

сора в ней приходится отказываться.



445

Языки высокие и низкие

Приведу пример. Во многих процессорах есть команды для

выполнения побитового сдвига содержимого аккумулятора

влево или вправо. Аналогичных команд практически ни в од-

ном языке высокого уровня нет. Чтобы осуществить эту опе-

рацию, вам придется заменить ее делением или умножением на

2 (впрочем, во многих современных компиляторах для умно-

жения или деления на степень двойки используются именно

команды побитового сдвига). Нет во многих языках высокого

уровня и команд для выполнения с битами булевых операций.

Большинство прикладных программ для первых домаш-

них компьютеров писалось на ассемблере. В наши дни его прак-

тически не используют, разве что для решения каких-либо

специфических задач. Чем изощреннее архитектура процес-

соров, тем сложнее писать для них ассемблерные программы.

Одновременно все совершеннее становятся и компиляторы.

Немаловажную роль в снижении популярности ассемблера

сыграло и увеличение объема доступной оперативной и дис-

ковой памяти. Программистам более не нужно создавать коды,

которые обходились бы минимальным количеством памяти и

целиком умещались на одной дискете.

Проектировщики многих первых компьютеров пытались

формулировать задания для них с помощью алгебраической

записи, но создать действительно работающий компилятор

удалось только в 1952 г. Его написала для компьютера UNIVAC

Грейс Мюррей Хоппер (1906–1992), работавшая тогда в ком-

пании Remington Rand. Грейс Хоппер связала свою жизнь с

вычислительной техникой еще в 1944 г., но даже разменяв де-

вятый десяток, продолжала работать в компьютерной индуст-

рии, отвечая за связи с общественностью в корпорации Digital

Equipment.

Старейшим языком высокого уровня, не утратившим сво-

ей актуальности и сегодня, является ФОРТРАН (FORTRAN),

хотя от исходной версии в нем мало что сохранилось. Кстати,

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

прописными буквами, так как они являются сокращениями.

Например, название ФОРТРАНа составлено из словосочета-

ния «FORmula TRANslation» (трансляция формул). ФОРТРАН

разработан в IBM в середине 1950-х для компьютеров серии

704 и долгое время интенсивно использовался в научном и

инженерном программировании. Он особенно удобен для ма-


446

Глава двадцать четвертая

тематических расчетов благодаря обширнейшей поддержке

операций с плавающей точкой, включая возможность работы

с комплексными числами.

У каждого языка масса сторонников и противников. Спо-

ры их зачастую протекают весьма эмоционально. Стараясь

сохранить нейтралитет, я решил использовать в качестве при-

мера язык, который сейчас уже почти никто не применяет, —

АЛГОЛ (ALGOL). Его имя — тоже сокращение, составленное

из «ALGOrithmic Language» (алгоритмический язык). Иссле-

довать природу языков высокого уровня на примере АЛГОЛа

удобно еще и потому, что он во многих отношениях — пря-

мой предок многих распространенных языков, появившихся

за последние 40 лет. Даже в наши дни иногда приходится слы-

шать о «языках программирования типа АЛГОЛа».

Первую версию — АЛГОЛ 58 — разработал в 1957–58 гг.

международный комитет программистов. Два года спустя был

выпущен усовершенствованный вариант — АЛГОЛ 60. В кон-

це концов дело дошло и до АЛГОЛа 68, но в этой главе я расска-

жу о версии языка, описанной в документе «Переработанное

описание алгоритмического языка АЛГОЛ 60», работа над ко-

торым была закончена в 1962, а выход в свет состоялся в 1963 г.

Давайте напишем на АЛГОЛе небольшую программу. Бу-

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

ALGOL.COM, работающий в CP/M или, скажем, MS-DOS. За-

пишем эту программу в файл FIRST.ALG (обратите внимание

на тип файла).

Программа на АЛГОЛе заключается между ключевыми сло-

вами (keywords) begin и end. Для начала выведем на экран одну

строку текста:

begin

print ('This is my fist ALGOL program!');



ende

Для запуска компилятора нужно набрать в командной строке:

ALGOL FIRST.ALG

В ответ компилятор сообщит о нераспознанном ключевом сло-

ве в третьей строке программы:

Line 3: Unrecognized keyword 'ende'.



447

Языки высокие и низкие

В вопросах правописания компилятор даст фору самому при-

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

я неправильно ввел ключевое слово end. Компилятор не за-

медлил сообщить мне о синтаксической ошибке. Там, где сто-

ит слово ende, компилятор ожидал увидеть известное ему клю-

чевое слово АЛГОЛа.

Исправляем ошибку и запускаем компилятор снова. На

диске появляется исполняемый файл — FIRST.COM в CP/M

или FIRST.EXE в MS-DOS. Вообще-то чаще для преобразова-

ния файла с исходной программой в исполняемый файл нуж-

но выполнить не одно, а два действия, но я для простоты об

этом умолчу. Так или иначе, для запуска созданного исполня-

емого файла в командную строку нужно ввести его имя:

FIRST

На экране появятся слова:



This is my fist ALGOL program!

Знатоки английского укоризненно качают головами. В этой

фразе тоже есть ошибка: в слове «first» (первый) пропущена

буква r. Однако на нее компилятор никак не прореагировал,

да это и понятно. В задачу программы входит вывод на экран

заданной текстовой строки, и компилятор, конечно, не анали-

зирует ее содержимое.

Вы, наверное, уже догадались, что оператор  print  осуще-

ствляет вывод на экран некоей информации, в данном случае

— текстовой строки. В этом смысле показанная выше програм-

ма на языке АЛГОЛ эквивалентна программе на языке ассемб-

лера, приведенной в начале главы. Оператор  print  в офици-

альную спецификацию языка АЛГОЛ не входит, но мы будем

считать, что у нашего компилятора есть соответствующая



встроенная функция (built-in function). Большинство опера-

торов АЛГОЛа (не считая begin и end) должны заканчиваться

точкой с запятой. Вставлять отступ перед оператором print не

обязательно, но вообще отступы часто используют, чтобы

прояснить структуру программы.

Теперь напишем программу для умножения двух чисел. В

любом языке программирования имеется понятие переменной

(variable). Переменная обозначается буквой или сочетанием

букв, например, коротким словом. Хотя для хранения чисел


448

Глава двадцать четвертая

по-прежнему используются ячейки памяти, переменные по-

зволяют обращаться к ним без явного указания адреса, что

делает программу понятнее. Нам понадобятся переменные a,



b и c — для двух сомножителей и для произведения:

begin


real a, b, c;

a := 535.43;

b := 289.771;

c := a 


´ b;

print (‘Произведение ', a, ' и ', b, ' равно ', c);

end

Оператор  real   используется для описания переменных, т. е.



для введения их имен и указания типа. В данном случае, пере-

менные a,  b и  c предназначены для хранения вещественных

чисел, т. е. чисел с плавающей точкой (для описания целых

переменных в АЛГОЛе служит оператор integer). Практически

во всех языках имена переменных могут включать цифры, но

начинаться должны обязательно с буквы. Применение пробе-

лов и специальных символов, как правило, не допускается. Во

многих компиляторах ограничена и длина имени. Я в приме-

рах будут использовать имена переменных, состоящие из од-

ной буквы.

Если наш компилятор АЛГОЛа поддерживает стандарт IEEE

для хранения чисел с плавающей точкой, для любой из трех

переменных понадобится 4 байта с простой точностью и 8 байт

— с удвоенной.

Следующие три выражения являются операторами присва-

ивания (assignment). В АЛГОЛе их легко распознать по двоето-

чию и знаку равенства (в других языках используется только

знак равенства). В левой части оператора присваивания стоит

имя переменной, в правой — выражение. Переменной при-

сваивается значение, полученное в результате вычисления

выражения. В первых двух операторах присваиваются конк-

ретные численные значения. В третьем операторе в перемен-

ную c записывается произведение переменных a и b.



449

Языки высокие и низкие

В современных языках символ 

´ не используется, так как

его нет в кодировках ASCII и EBCDIC. Вместо него применя-

ется символ 

*

. Деление в АЛГОЛе обозначается косой чертой



(/),  

¸  обозначает деление нацело, а символ ­, также не входя-

щий в кодировку ASCII, — возведение в степень.

Для отображения переменных и констант служит опера-

тор print. Отдельные элементы списка вывода разделяются за-

пятыми. Отображение на экране текста — не великая заслуга,

но если вы захотите вывести на экран значение числовой пе-

ременной с плавающей точкой, оно будет автоматически пре-

образовано в ASCII:

Произведение 535.43 и 289.771 равно 155152.08653

Выведя эту строку, программа завершает работу и передает

управление ОС.

Чтобы найти произведение двух других чисел, вам придется

отредактировать программу, перекомпилировать ее и запус-

тить вновь. Чтобы не возиться с перекомпиляцией, вызовите

встроенную функцию read:

begin

real a, b, c;



print ('Введите первое число: ');

read (a);

print ('Введите второе число: ');

read (b);

c := a 

´ b;


print ('Произведение ', a, ' и ', b, ' равно ', c);

end


Оператор read считывает введенные с клавиатуры ASCII-сим-

волы и преобразует их в числа с плавающей точкой.

Очень важной структурным понятием в языках высокого

уровня является цикл (loop), позволяющий многократно вы-

полнить один и тот же фрагмент кода. Допустим, вы хотите

написать программу, вычисляющую кубы чисел 3, 5, 7 и 9.

Выглядеть она будет примерно так:


450

Глава двадцать четвертая

begin


real a, b;

for a := 3, 5, 7, 9 do

begin

b := a 


´ a ´ a;

print (‘Куб числа ', a, ' равен ', b);

end

end


В операторе for переменной a присваивается значение 3, а за-

тем выполняется оператор, следующий за ключевым словом



do. Если таких операторов несколько (как у нас), их нужно раз-

местить между ключевыми словами  begin  и  end. Операторы

между двумя этими словами называются блоком (block). Те же

операторы выполняются для значений переменной a 5, 7 и 9.

У оператора for есть и другой вариант. Следующая програм-

ма вычисляет кубы всех нечетных чисел от 3 до 99:

begin

real a, b;



for a := 3 step 2 until 99 do

begin


b := a 

´ a ´ a;


print ('Куб числа ', a, ' равен ', b);

end


end

В операторе for переменной a присваивается значение 3, а затем

выполняется блок операторов, идущий за ключевым словом do.

При следующем выполнении цикла значение переменной a уве-

личивается на значение, указанное после ключевого слова step,

т. е. на 2. Блок операторов выполняется с переменной a, равной

5. Затем значение переменной a увеличится еще на 2. Выполне-

ние цикла завершится, когда значение a станет больше 99.

Синтаксические правила языков программирования обыч-

но не допускают никаких исключений. В АЛГОЛе 60, например,

за ключевым словом for может идти только имя переменной.

Другой важный элемент языка программирования — услов-

ные структуры, позволяющие организовать выполнение опе-


451

Языки высокие и низкие

ратора или блока операторов только при соблюдении опреде-

ленного условия. В приведенном ниже примере используется

встроенная функция АЛГОЛа sqrt, вычисляющая квадратный

корень. С отрицательными числами она не работает, что учи-

тывается в программе.

begin

real a, b;



print ('Введите число: ');

read (a);

if a < 0 then

print('Извините, введено отрицательное число.');

else

begin


b := sqrt(a);

print (‘Квадратный корень из ', a, ' равен ', b);

end

end


Символ < соответствует математическому знаку «меньше».

Если пользователь ввел отрицательное число, выполняется

первый оператор  print  в структуре  if. Если введенное число

больше 0 или равно ему, выполняется блок, содержащий вто-

рой оператор print.

До сих пор все переменные в этой главе использовались для

хранения одиночных значений. Но в одной переменной их мож-

но хранить и несколько. Такая переменная называется массивом

(array). В программе на АЛГОЛе массив описывается так:

real array a[1:100];

Здесь переменную a предполагается использовать для хране-

ния 100 чисел с плавающей точкой, называемых элементами

массива. Для обращения к первому элементу массива исполь-

зуется обозначение a[1], ко второму — a[2], к последнему —



a[100]. Число в скобках называется индексом (index).

В следующей программе вычисляются квадратные корни

всех чисел от 1 до 100. Результаты вычислений сохраняются в

массиве, а затем выводятся на печать.



452

Глава двадцать четвертая

begin


real array a[1:100];

integer i;

for i := 1 step 1 until 100 do

a[i] := sqrt(i);

for i := 1 step 1 until 100 do

print ('Квадратный корень из ', i, ' равен ', a[i]);

end

Помимо массива, в программе описана целая переменная



i. В первом цикле каждому элементу массива присваивается

значение квадратного корня из его индекса. Во втором цикле

значения элементов массива выводятся на печать.

В дополнение к типам real и integer в АЛГОЛе имеется так-

же тип Boolean. Переменные этого типа могут принимать лишь

два значения: true и false. Массив булевых переменных помо-

жет нам написать последнюю в этой главе программу, кото-

рая составляет список простых чисел с помощью алгоритма,

известного как решето Эратосфена. Эратосфен (около 276–196

до н. э.) был библиотекарем в знаменитой Александрийской

библиотеке и более всего прославился вычислением длины

окружности Земли.

Простыми называют целые числа, которые без остатка де-

лятся только на себя и на 1. Самое маленькое простое число —

2. Оно же — единственное четное простое число. Далее идут 3,

5, 7, 11, 13, 17 и т. д.

В методе Эратосфена рассматривается ряд целых чисел,

начинающийся с двойки. Сначала из списка вычеркиваются

все числа, кратные наименьшему простому числу (2), т. е. все

четные числа, кроме самой двойки. Следующее по порядку

простое число — 3. Вычеркиваем из списка все числа, кратные

ему. За тройкой идет 4, но это число уже вычеркнуто, так как

оно четно. 5 — опять простое число, и мы вычеркиваем из спис-

ка все числа, которые без остатка делятся на 5. По мере того

как мы будем продвигаться вперед, невычеркнутыми будут ос-

таваться только простые числа.



453

Языки высокие и низкие

В программе на АЛГОЛе для определения всех простых

чисел, меньших 10 000, используется булев массив, индекс ко-

торого принимает значения от 2 до 10 000.

begin

Boolean array a[2:10000];



integer i, j;

for i := 2 step 1 until 10000 do

a[i] := true;

for i := 2 step 1 until 100 do

if a[i] then

for j := 2 step 1 until 10000  

¸  i do

a[j  


´  j] := false;

for i := 2 step 1 until 10000 do

if a[i] then

print (i);

end

В первом цикле всем элементам булева массива присваивает-



ся значение true, т. е. изначально программа полагает, что про-

стыми являются все числа. Во втором цикле переменная i про-

бегает значения от 2 до 100 (квадратный корень из 10 000). Если

значение i — простое число (это значит, что a[i] равно true), во

вложенном цикле всем элементам массива с номерами, крат-

ными i, присваиваются значения false (эти числа простыми не

являются). В последнем цикле на печать выводятся номера всех

элементов массива, равных true, т. е. все простые числа.

Иногда приходится слышать споры о том, является про-

граммирование наукой или искусством. С одной стороны, вы

вспоминаете о приятеле, получившем степень магистра ком-

пьютерных наук, с другой стороны, на полке у вас стоит зна-

менитая книга Дональда Кнута (Donald Knuth) «Искусство

программирования». Физик Ричард Фейнман писал так: «Я бы

сказал, что программирование сродни машиностроению —

всего-то нужно заставить что-то сделать что-то».

Попросите 100 человек написать программу для печати

простых чисел, и вы получите 100 разных решений. Даже те,


454

Глава двадцать четвертая

что воспользуются для решения решетом Эратосфена, напи-

шут программу иначе, чем я. Если бы программирование было

наукой, вряд ли у одной задачи было бы так много правиль-

ных решений, а неверные решения были бы более очевидны.

Зачастую программирование связано с творческими озарени-

ями и интуитивными решениями, и это сближает его с искус-

ством. И все-таки процесс проектирования и создания про-

граммы не отличается существенно, скажем, от строительства

моста.


Первыми программистами были в основном ученые и ин-

женеры, которые умели формулировать свои задачи на язы-

ке математики, положенном в основу ФОРТРАНа и АЛГОЛа.

Однако на протяжении всей истории языков программирова-

ния неоднократно предпринимались попытки разработать

язык, который могли бы использовать и люди, не столь близ-

ко знакомые с математикой.

Одним из первых языков, специально предназначенных для

бизнеса, был КОБОЛ (COBOL), созданный в конце 1950-х ко-

митетом из представителей промышленности и Министерства

обороны США. КОБОЛ широко применяется и по сей день.

Его название расшифровывается как «COmmon Business

Oriented Language» (язык, ориентированный на общие коммер-

ческие задачи). Одно из основных требований, предъявляв-

шихся к КОБОЛу, заключалось в том, чтобы менеджеры, сами

не занимавшиеся программированием, могли хотя бы читать

программы и убеждаться, что они делают именно то, что дол-

жны делать (чего на практике, конечно, не бывает).

В КОБОЛе имеются обширные возможности по чтению

записей (records) и созданию отчетов (reports). Записью в про-

граммировании называется собрание взаимосвязанных сведе-

ний. Например, страховая компания может вести базу данных

с информацией о проданных полисах. Отдельные элементы

этой базы и есть записи, в которых хранятся имя клиента, дата

его рождения и другие сведения. Поначалу для хранения ин-

формации в программах на КОБОЛе использовали 80-столб-

цовые перфокарты IBM. Для максимальной экономии места в

номере года на картах зачастую указывались только две пос-

ледние цифры, что позже отчасти обусловило знаменитую

«проблему 2000 года».


455

Языки высокие и низкие

В середине 1960-х в IBM разработали для компьютеров

System/360 язык PL/I (Programming Language I, язык програм-

мирования №1). Предполагалось, что в PL/I будут объедине-

ны модульная структура программ на АЛГОЛе, обширный

математический аппарат ФОРТРАНа и средства КОБОЛа для

работы с записями. Но уровня популярности ФОРТРАНа или

КОБОЛа этот язык так и не достиг.

Компиляторы ФОРТРАНа, АЛГОЛа, КОБОЛа и PL/I созда-

вались и для домашних компьютеров, но ни один из них не

оказал на эти машины такого влияния, как БЕЙСИК.

Язык БЕЙСИК (BASIC, Beginner’s All-purpose Symbolic

Instruction Code, универсальный символьный программный

код для начинающих) разработан в 1964 г. Джоном Кемени

(John Kemeny) и Томасом Курцем (Thomas Kurtz) из Дартмут-

ского университета. Большинство студентов в Дартмуте не

были ни математиками, ни инженерами, поэтому их не сто-

ило заставлять возиться с перфокартами или сложными язы-

ками программирования. Вместо этого студент, сидя перед

терминалом, набирал простую программу прямо на экране.

Если строка начиналась с номера, она считалась строкой про-

граммы на БЕЙСИКе. Строка без номера считалась командой

для системы. Например, командой SAVE пользователь сохра-

нял программу на диске, командой LIST — выводил ее на эк-

ран, а RUN — компилировал и запускал. Самое первое печат-

ное руководство по БЕЙСИКу начиналось с такой программы:

10 LET X = (7 + 8) / 3

20 PRINT X

30 END

В отличие от АЛГОЛа в БЕЙСИКе программист не должен был



указывать тип переменной. Большинство переменных по

умолчанию считались вещественными.

Во многих последующих реализациях БЕЙСИКа исполь-

зовались не компиляторы, а интерпретаторы (interpreters). Я

уже говорил, что компилятор считывает файл с исходной про-

граммой целиком, а затем создает исполняемый файл. Интер-

претатор считывает программу оператор за оператором и сра-

зу выполняет их. При этом исполняемый файл не создается.

Разрабатывать интерпретаторы проще, чем компиляторы, но

работает интерпретируемая программа, как правило, медлен-



456

Глава двадцать четвертая

нее скомпилированной. На домашних компьютерах дебют

БЕЙСИКа состоялся в 1975 г., когда два приятеля Билл Гейтс

(Bill Gates) (род. 1955) и Пол Аллен (Paul Allen) (род. 1953) на-

писали интерпретатор БЕЙСИКа для компьютера «Альтаир

8800». Этот интерпретатор стал первым продуктом основан-

ной ими корпорации Microsoft.

Язык программирования Паскаль (Pascal) унаследовал

структуру АЛГОЛа и средства КОБОЛа для работы с запися-

ми. Он разработан в конце 1960-х швейцарским профессором

информатики Николасом Виртом (Niklaus Wirth). Среди про-

граммистов компьютеров IBM PC Паскаль был очень популя-

рен, правда, только в одной специфической реализации —

Turbo Pascal фирмы Borland. Эта программа, написанная Ан-

дерсом Хейлсбергом (Anders Hejlsberg) из Дании (род. 1960),

поступила в продажу в 1983 г. Она представляла собой интег-



рированную среду разработки  (Integrated Development

Environment, IDE) — текстовый редактор и компилятор были

объединены в единую программу, что существенно облегчало

разработку кодов. На больших компьютерах интегрированные

среды использовались задолго до этого, но с Turbo Pascal на-

чалось их пришествие на персональные компьютеры.

На Паскале частично основан язык программирования Ада,

разработанный для Минобороны США. Он назван в честь Ав-

густы Ады Байрон, которую я упоминал в главе 18, рассказы-

вая об Аналитической Машине Бэббиджа.

И наконец — С (Си). Этот чрезвычайно популярный язык

был создан в 1969–1973 гг. в основном усилиями Денниса Рит-

чи (Dennis Ritchie) из Bell Telephone Laboratories. Часто спра-

шивают, откуда взялось название С. Ответ прост: его предше-

ственником был язык В, который в свою очередь был упро-

щенным вариантом BCPL (Basic CPL), основанного на CPL

(Combined Programming Language, комбинированный язык

программирования).

Помните, я говорил в главе 22 о переносимости ОС UNIX?

В те времена ОС, как правило, писались на языке ассемблера

для конкретного процессора. В 1973 г. UNIX была написана

(точнее, переписана) на С, и с тех пор язык и система идут по

жизни рука об руку.

Одно из основных качеств программы на С — краткость.

Например, для указания границ блоков используются не клю-


457

Языки высокие и низкие

чевые слова, как в АЛГОЛе или Паскале, а фигурные скобки:

{ и }. Или другой пример. В программах часто возникает необ-

ходимость прибавить к переменной некое число и записать

результат в ту же переменную:

i = i + 5;

В С этот оператор можно сократить:

i += 5;


Если значение переменной нужно увеличить на 1, оператор

становится еще короче:

i++;

На 16-разрядном или 32-разрядном микропроцессоре этот



оператор превращается в единственную машинную команду.

Чуть раньше я говорил, что в большинстве языков высо-

кого уровня нет операций побитового сдвига или булевых опе-

раций над битами. Язык С — исключение из этого правила.

Кроме того, важной особенностью С является поддержка ука-

зателей (pointers), т. е. фактически работы непосредственно с

адресами в памяти. Из-за этой близости к командам процес-

сора С иногда называют языком ассемблера высокого уровня.

Все языки типа АЛГОЛа, т. е. большинство распространен-

ных языков, предназначены для компьютеров с архитектурой

Неймана. Вырваться из пут неймановской модели при разра-

ботке языка нелегко, но еще сложнее убедить других людей

им пользоваться. Один из таких «не-неймановских» языков —

LISP (LIst Processing, обработка списков), созданный в конце

1950-х Джоном Маккарти (John MacCarthy) — используется

при работах в области искусственного интеллекта. Не менее

экзотичен, чем LISP, хотя и не похож на него, APL (A Prog-

ramming Language), созданный также в конце 1950-х Кеннетом

Айверсоном (Kenneth Iverson).

Так или иначе, пока в программировании доминируют язы-

ки типа АЛГОЛа, хотя в последние годы в них внесено несколь-

ко важных усовершенствований, результатом которых стало

появление  объектно-ориентированных  (object-oriented) язы-

ков. Эти языки очень удобны при работе в графических опе-

рационных системах, о которых речь пойдет в следующей (пос-

ледней) главе книги.




Достарыңызбен бөлісу:
1   ...   18   19   20   21   22   23   24   25   26




©www.engime.org 2024
әкімшілігінің қараңыз

    Басты бет