Строительный блокнот Развитие полупроводниковой электроники при отсутствии грамматики такой перевод просто оказался бы невозможным. Во-вторых, правила грамматики позволяют проверять составленные программы и выявлять ошибки. Такой контроль служит средством повышения иадежноств функционирования микропроцессорного комплекта. Как и в обычных разговорных языках, слова в языках программирования подразделяются на части речи. Роль существительного в языках программирования выполняют идентификаторы. Грамматически идентификатор - это буква нли любая последовательность букв и цифр, начинающаяся с буквы. Сущность его состоит в следующем. Любой алгоритм или, что то же самое, любая программа выполняется над словами, которые хранятся в ячейках памяти. Адрес ячейки памяти представляет собой нмя слова и в то же время является единственным признаком, позволяющим отличить одно слово от другого. Для человека-программиста непосредственное использование адресов связано с большими трудностями. Сложные программы могут иметь дело с огромным количеством - в несколько тысяч или даже несколько десятков тысяч - слов. Ясно, что запомнить адреса такого количества слов трудно. Но это еще не все. В процессе выполнения программы слова могут перемещаться) из одной ячейки памяти в другую, н это тоже нужно запомнить. Как все это охватить? Поступают так. Каждому слову раз и навсегда* ставится в соответствие идентификатор. Идентификатор служит постоянным именем данного слова от начала до конца выполнения программы. Специальная программа, называемая транслятором, каждому идентификатору ставит в соответствие определенный адрес ячейки памяти. Составляется таблица таких соответствий. Эта же программа следит за тем, чтобы при перемещениях слов нз одних ячеек памяти в другие в таблицу соответствий вносились необходимые коррективы. Использование идентификаторов возникло значительно раньше, чем была написана первая программа. Переменная в математике, обозначаемая одной илн несколькими буквами, может служить наиболее типичным примером идентификатора. К существительным следует отнести и метки. Метки - это имя команды илн в более общем случае имя оператора. Грамматически метка - это, так же как идентификатор, последовательность букв и цифр, правда в отличие от него метка может начинаться с цифры или вообще состоять из одной цифры, Л1етка записывается перед командой (оператором) и в подавляющем большинстве языков отделяется от нее двоеточием. Метки нужны для осуществлени переходов по программе. Уже на этом уровне мы можем проследить роль грамматических правил. Формально метка неотличима от идентификатора - и то, и другое может представлять собой, к примеру, одну букву. Ясно, что при переводе совершенно необходимо различать метки н идентификаторы. Это в делается с использованием грамматических правил. В частности, если за некоторой последовательностью букв и цифр имеется двоеточие, а затем мнемонический код команды, то такая последовательность представляет собой метку. В языках ассемблера имеются два вида слов, выполняющих функции глагола. К первому виду относятся команды. Вообще язык ассемблера - это язык команд. Каждая команда в языке ассемблера в свою очередь состоит нз мнемонического кода операции и идентификатора (идентификаторов). Последние и служат основным отличием команды в языке ассемблера от команды в машинном языке. Например, если команда пересылки слова из ячейки памяти в регистр результата выглядела так: LDA ADR, то та же команда на языке ассемблера будет выглядеть как М: LDA FUN 1. Здесь М - метка, а FUN 1 ~~ ©то идентификатор, представляющий собой имя слова, хранящегося в запоминающей ячейке с адресом ADR. Адрес слова может измениться, но идентификатор по-прежнему будет оставаться именем этого же самого слова. Это достигается внесением необходимых корректив в таблицу соответствий. Ко второму виду слов, в обычном разговорном языке выполняющих функ-яин глаголов, относятся макрооператоры. Их часто называют макрокомандами шли макроопределениями. Чтобы понять роль макрооператоров, заметим, что в перечне команд, рассмотренном в предыдущем разделе, нет ни одной команды, предусматривающей выполнение арифметической операции над двумя словами, хранящимися в памяти. Предположим, в некоторой программе, записанной на языке ассемблера, встречается такая команда: М: ADD XI, Х2, что означает сложить числа XI и Х2, после чего идентификатору XI присвоить значение полученной суммы. Присвоить значение идентификатору - это значит поместить соответствующее значение в ячейку памяти, которая в данный момент поставлена в соответствие ©тому идентификатору. Тот факт, что значение суммы присваивается именно первому из двух идентификаторов, представляет собой одно нз грамматических правил. Обращаясь к материалу предыдущего параграфа, мы видим, что рассмотренной команде отвечает следующая последовательность действий. Во-первых, число XI должно быть изв.течено из памяти н помещено в регистр результата. Во-вторых, число Х2 должно быть извлечено из памяти и помещено в один из свободных РОН. Выбор РОН выполняется автоматически, для чего необходимо составить и постоянно корректировать таблицу занятых и свободных РОН, Затем можно выполнить машинную команду ADD R, где на месте символа R подставляется имя выбранного РОН. Наконец, в заключение должна быть выполнена операция пересылки содержимого регистра результатов в ячейку памяти, поставленную в соответствие идентификатору XI. Иными словами, одна команда на языке ассемблера вводит в действие целую последовательность команд машинного языка или, иначе говоря, подпрограмму. Такие команды и получили название макрокоманд. Примером более сложной макрокоманды может служить, например, команда умножения. Роль прилагательных в языке ассемблера играют описания. Описываются, во-первых, сами переменные (идентификаторы). Делается это в основном для облегчения контроля программ и выявления ошибок. Например, если некоторое слово представляет собой набор логических значений (такие слова называют также булевы.ми), то над ним бессмысленно выполнять арифметическую операцию. Если некоторый идентификатор, скажем RIX, описан как относящийся к классу булевых, то встретившаяся в программе конструкция типа М: ADD X RIX будет при переводе распознана как ошибочная. Кроме того, описанию иодвергаются отдельные области памяти, так называемые поля. Программа яа языке ассемблера состоит из двух частей, В первой части собраны все описания, а во второй - содержится сама программа, т. е, последовательность команд н макрокоманды. В языках самого высокого уровня также используются идентификаторы и метки. Однако во всем остальном они существенно отличаются от машинных языков и языков ассемблера. Каждый язык самого высокого уровня гораздо ближе к обычному разговорному языку, чем к машинному. Основными грам- матнческимн конструкциями языка высокого уровня являются выражения, операторы, описания и блоки. Выражение эквивалентно некоторой последовательности (сколь угодно длинной) команд, ие содержащей, однако, команд ввода-вывода, управления и специальных. Записываются выражения в форме, очень близкой к той, что принята в математике. Выражение - это последовательность идентификаторов, связанных между собой символами, обозначающими операции. В состав выражения обычно входят также один или несколько идентификаторов, которым присваиваются результаты всех выполненных операций. Операторы определяют структуру последовательности действий. Наиболее типичными для всех языков самого высокого уровня являются оператор цикла н условный оператор. Оператор цикла предусматривает повторение заданное число раз некоторой последовательности действий. При этом число повторений может задаваться с самого начала и просто вписываться в состав оператора или повторение должно производиться до тех пор, пока не окажется удовлетворенным некоторое условие, например пока некоторое число не окажется меньше заданного значения. Условный оператор осуществляет переходы по программе. В отличие от команд условного перехода в состав условного оператора может входить несколько условий и соответственно несколько меток, по которым осуществляются переходы. Описания в языках самого высокого уровня применяются не только к отдельным переменным (идентификаторам), но н к большим группам переменных - массивам. Таким образом, опнсаиня определяют структуру данных, что очень важно для размещения нх в памяти. Наконец, блок - это некоторый законченный в смысловом отношении фрагмент программы, который может рассматриваться как единое целое по отношению к более Сложной программе. Блок обладает большой степенью автономии, что позволяет компоновать различные программы нз одних и тех же блоков. В настоящее время существует несколько сотен различных языков самого высокого уровня, и каждый нз них обладает специфическими особенностями. Для микропроцессорных спстем был разработан язык PL/M, представляющий собой сокращенную версию широко распространенного языка Pi/!; PL - начальные буквы английских слов programming language , что значит язык программирования. Кроме того, для программирования микропроцессорных систем широко используется язык Бейсик, приобретший в последние годы большую популярность благодаря своей простоте. Мы вынуждены заметить, однако, что если машинный язык микропроцессорных систем обладает какой-то спецификой, то при составлении программ на языках самого высокого уровня совершенно безразлично, для какой именно конкретной системы пишется программа. В этом несомненное преимущество языков программирования, но в то же время в этом кроются определенные трудности, поскольку, программируя на языках самого высокого уровня, мы теряем возможность учесть некоторые особенности конкретных систем, что под-час делает программу малоэффективной. Назвав эту главу Команды н языки , мы пока ни слова не сказали о самом процессе программирования. Что же можно сказать по этому поводу? Существует много стандартных приемов, описанных в большом количестве ру-
|