Операторы языка си и управление их исполнением icon

Операторы языка си и управление их исполнением



НазваниеОператоры языка си и управление их исполнением
Дата конвертации16.09.2012
Размер255.18 Kb.
ТипПрограмма
1. /Troy/6.doc
2. /Troy/7.doc
3. /Troy/8.doc
4. /Troy/9.doc
Операторы языка си и управление их исполнением
Выражения и операции в языке си
Зачем нужны указатели?
Поля битов и побитовые операции

ГЛАВА 6

ОПЕРАТОРЫ ЯЗЫКА СИ И УПРАВЛЕНИЕ ИХ ИСПОЛНЕНИЕМ


В теории программирования доказано, что любая программа может быть за­кодирована с помощью комбинаций трех конструкций: последовательности опера­торов, выбора и итерации [Bohm и Jacopini]. Вы уже знакомы с несколькими различными операторами языка Си, которые реализуют эти конструкции. К ним относятся выражения, операторы if и while. В действительности этих операторов вполне достаточно, чтобы закодировать любую программу. Однако существуют и другие операторы» которые помогают облегчить программирование. Они будут представлены и продемонстрированы на примерах в настоящей главе.






В ч. 1 этой главы будет представлен синтаксис операторов, сопровождаемый не­которыми примерами. В ч. 2 с помощью вновь представленных операторов будет "подчищена" и расширена программа вычисления выражений.

ЧАСТЬ 1


В табл. 6.1 показаны различные операторы языка Си. Можно заметить, что не­которые из определений операторов сами содержат операторы. Они служат приме­рами рекурсивных определений.

Далее рассмотрим каждый оператор в отдельности.

6.1. ПУСТОЙ ОПЕРАТОР

Пустой оператор состоит из одного символа - точки с запятой. Для чего он нужен? Сам по себе он обычно не встречается в программе на языке Си. Пустой оператор используется как заполнитель в других более сложных операторах, например в опе­раторах for, if и while. Поэтому обсуждение пустого оператора будет включено в те разделы, которые посвящены этим и им подобным операторам.

6.2. ОПЕРАТОРЫ-ВЫРАЖЕНИЯ

Вы уже встречались с операторами-выражениями и пользовались ими. Опера­торы-выражения представляют собой просто выражения, за которыми следует точ­ка с запятой. Хотя многие операции (следовательно, и виды выражений) языка Си мы пока еще не рассматривали, в этой главе ограничимся только теми опе­рациями и выражениями, с которыми Вы уже знакомы. Глава 7 посвящена обсуж­дению остальных операций и выражений в языке Си.



6.3.
ОПЕРАТОРЫ BREAK И CONTINUE


Операторы break и continue подобно пустому оператору используются в составе других операторов, например switch, while и do-while. Как и в случае пустого опе­ратора, будем касаться их по мере обсуждения тех операторов, в состав которых они входят.

6.4. БЛОК ОПЕРАТОРОВ

Как показано на рис.4.4, блок (иногда называемый составным оператором) состоит из определений и объявлений данных, за которыми следует последователь­ность операторов. Блок заключается в фигурные скобки. Здесь стоит отметить, что в описаниях синтаксиса языка Си всюду, где указан "оператор", вместо него мож­но указывать блок операторов. Таким образом, если Вы пользуетесь такими опе­раторами, как for, if и т.д., блок можно использовать в любом месте, где в опре­делении синтаксиса указан нетерминальный оператор.

6.5. ОПЕРАТОР RETURN

Напомним, что Вам уже приходилось пользоваться оператором return. Следует обратить внимание на то, что этот оператор имеет следующие две основные формы: return; или return(выражение);

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

6.6. ОПЕРАТОР IF

Мы уже пользовались оператором if, и достаточно интенсивно. Его синтаксис имеет следующий вид:

if (выражение)

оператор_1

else

оператор_2

Вначале вычисляется заключенное в скобки выражение. Если его значение отлично от нуля ("истина"), то выполняется оператор_1. Если использовано слу­жебное слово else (иначе) и значение выражения равно нулю ("ложь"), то выпол­няется оператор, указанный после служебного слова else.

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

Как обычно, в качестве операторов оператор_1 и оператор_2 можно использо­вать блоки операторов.

Операторы if могут также быть вложенными, как это сделано в функции do_select программы управления портфелем акций (рис.6.1).



Каждому из операторов if (кроме последнего) соответствует свое служебное сло­во else, поэтому показанный на рис.6.1 исходный код воспринимается вполне однозначно. Рассмотрим, однако, следующий пример:



Какому именно из операторов if соответствует первое служебное слово else? Чтобы ответ на этот вопрос не вызывал затруднений, слово else должно набираться на одном уровне с тем оператором if, которому оно соответствует. Язык Си следует обычному правилу, согласно которому служебное слово else связывается с пос­ледним оператором if, с которым еще не было связано else. Иной порядок может быть установлен с помощью фигурных скобок.

6.7. ОПЕРАТОР WHILE

Оператор while (пока) также уже знаком Вам. Его синтаксис следующий: while (выражение) оператор

Выполнение оператора while начинается с вычисления выражения. Если его значение отлично от нуля ("истина"), то выполняется оператор, указанный вслед за выражением, и весь этот процесс повторяется заново. Повторное выполнение оператора осуществляется в течение всего времени, пока выражение имеет нену­левое значение. Это выражение называется условием цикла. Конечно, одним из результатов выполнения оператора, составляющего тело цикла, должно быть изме­нение условия цикла; в противном случае оператор while будет выполняться бес­конечно.

Обычно тело цикла представляет собой блок операторов. Это позволяет обес­печить циклическое выполнение группы операторов. Однако иногда может пона­добиться, чтобы ни один оператор не выполнялся. Предположим, к примеру, что при работе с программой вычисления выражений было ошибочно введено следую­щее выражение:

(5X9)+(3*2)

Входящий в него символ X не принадлежит к числу допустимых элементов выра­жения. Было бы бессмысленно продолжать разбор и выполнение выражения после того, как этот символ был обнаружен, поскольку никакими средствами нельзя ус­тановить, что же на самом деле хотел ввести пользователь. Одним из путей игнорирования оставшейся части выражения являются повторные вызовы функции scanner с помощью оператора while до тех пор, пока не будет обнаружен конец выражения. Эту идею можно реализовать следующим образом:

/-------Пустой оператор

while (scanner() != END);

В этом операторе вся работа осуществляется за счет выполнения условия цикла. Не требуется никаких других операторов. Однако для удовлетворения синтаксическим правилам должна быть указана завершающая точка с запятой. Она порождает пустой оператор. Другие примеры пустых операторов будут приведены при обсуждении оператора for.

Еще одним специальным примером использования оператора while служит пред­намеренное создание "бесконечного" цикла. Следующий цикл while эквивалентен предыдущему примеру:

while(l) {

if (scanner() = = END) break;

}

Условие цикла всегда отлично от нуля, поэтому цикл может исполняться неог­раниченное число раз. В действительности он бы исполнялся бесконечно, если бы не наличие в его теле оператора break. Оператор break вызывает завершение самого внутреннего включающего его оператора while, do-while, for или switch. В нашем примере оператор break будет исполнен, если возвращаемое функцией scanner зна­чение станет равным END. Как только это произойдет, управление будет передано оператору программы, находящемуся непосредственно за концом оператора while.

Можно дать и другой способ решения поставленной здесь задачи: игнорировать ошибочный элемент и попытаться продолжить разбор выражения. Попробуем в случае выражения (5Х9)+(3*2) просто пропустить символ X. Если разбор выра­жения выполнялся с помощью оператора while, то при обнаружении ошибочного элемента следует пропустить оставшиеся операторы цикла, не завершая его вы­полнение (как это делает оператор break), что может быть сделано с помощью оператора if следующим образом:

while (...) {

/* Обрабатывать только допустимые элементы, игнорируя остальные */

if (scanner() != ER

{

/* Разобрать выражение */

В языке Си предусмотрен оператор, который позволяет пропускать оставшуюся часть цикла и начинать новую итерацию. Он имеет подходящее название: continue (продолжить). Следующий пример обеспечивает те же действия, что и преды­дущий:

while (...)

if (scanner() = = ER) continue; /* Разобрать выражение */

}

Если возвращаемое функцией scanner значение равно ER, то будет исполнен оператор continue. В результате оставшиеся операторы цикла (представленные многоточием) будут на этой итерации пропущены и управление будет передано в конец цикла. В данном примере за выполнением оператора continue последует вычисление условия цикла, и цикл будет продолжен, если значение условия отлично от нуля.

По своему действию операторы break и continue эквивалентны операторам пере­хода с ограниченным диапазоном передачи управления. Действие операторов break и continue в том случае, когда они используются в составе оператора while, отра­жено на следующей диаграмме:



6.8. ОПЕРАТОР SWITCH

Вернемся к показанному на рис. 6.1 исходному коду:

if (choice = = '1')

buy(); else if (choice = = '2')

sell(); else if (choice = = '3')

current(); else if (choice = = '4')

gain_loss(); else if (choice ,= = '5')

rem_stock();

Этот код трудно читать и еще труднее сопровождать. В подобной ситуации, когда требуется передавать управление одному из нескольких операторов в зависимости от значения выражения, может быть использован оператор switch (переключить). Его синтаксис следующий: switch (выражение)

{

case константное_выражение_1:

оператор;

.

.

.

сазе константное_выражение_2:

оператор;

case константное_выражение_n:

оператор;

default :

оператор;

}

Выполнение оператора switch начинается с вычисления заключенного в скобки вы­ражения, которое должно давать целый результат. Затем просматриваются друг за другом префиксы case (случай), указанные после служебного слова case константные выражения вычисляются и результаты сравниваются с результатом вычисления вы­ражения, указанного после служебного слова switch. Если эти результаты совпали, то управление передается оператору, следующему за служебным словом case. Если ни одного совпадения не произошло, и при этом указано (необязательное) служебное слово default (по умолчанию), та управление передается оператору, следующему за служебным словом default. Если ни одного совпадения не произошло, а служебное слово default отсутствует, то ни один из операторов блока не выполняется.

После передачи управления в блок исполнение указанных в нем операторов про­должается до конца блока, если только последовательность выполнения операторов не будет изменена операторами break или goto. Это означает, что будут выпол­няться все операторы, указанные под низлежащими служебными словами case, если только последовательность исполнения операторов не будет явным образом изменена.

Заметьте, что выражение, указанное вслед за служебным словом case, должно быть константным (т.е. после префикса case не допускается использование пере­менных). Кроме того, порядок значений этих выражений несуществен (т.е. не тре­буется порядка ни по возрастанию, ни по убыванию этих значений).

На рис.6.2 показан исходный код, который можно получить из кода, приведен­ного на рис.6.1, если применить оператор switch.

switch (choice)

{

case '1':

buy();

break; case '2':

sell();

break; case '3':

current();

break; case '4':

gain_loss();

break; case '5':

rem_stock();

break; default:

printf("Ошибочный выбор\n");

}

Рис.6.2


Обратите внимание на использование оператора break. Префиксы case и default не изменяют порядка исполнения операторов в блоке оператора switch. Чтобы вы­полнялись только те операторы, которые соответствуют выбранной альтернативе, необходимо использовать оператор break, который досрочно завершит выполнение оператора switch (если это необходимо). В результате выполнения оператора break управление будет передано оператору, находящемуся вслед за закрывающей фигурной скобкой блока оператора switch:



Если бы оператора break не было, то управление передавалось бы от одной аль­тернативы к следующей низлежащей. Иногда это желательно. Например, в программе вычисления выражений функция scanner должна выполнять разбор чисел с плавающей точкой.



Однако числа с плавающей точкой могут начинаться как с цифры, так и с десятичной точки. Определяя, какое из условий имеет место, мож­но связать два служебных слова case с одной и той же группой операторов (пример показан на рис.б.З).

Прежде чем обсудить код, содержащийся в блоке оператора switch, за­метим, что одной и той же группе операторов присвоены два префикса case. Если значение выражения в операторе switch равно DОТ или NUMBER, то будет исполняться один и тот же код. Обработка вариантов DOT и NUMBER одинакова. Обратите внимание на то, что оператор break тем не менее используется, поскольку необходимо отделить код обработки вариантов DOT и NUMBER от кода обработки остальных вариантов (default).

Посмотрим на код, приведенный на рис.6.3. Назначением этого фрагмента программы является преобразование строки цифр, в которую может также входить де­сятичная точка, в число с плавающей точкой. Попробуем проследить ход его выпол­нения. Переменная value будет содержать числовое значение разбираемой строки. Объект divisor будет содержать масштабирующий коэффициент (показатель степени при 10) дробной части числа. Но каково назначение следующего оператора?

value = value*10 + (ch - '0');

После извлечения очередной цифры (содержащейся в переменной ch) текущее зна­чение числа (содержащееся в переменной value) умножается на 10 для того, чтобы освободилось место для этой цифры. Затем к результату умножения прибавляется очередная цифра. Но зачем надо вычитать '0' из значения переменной ch? Напомним, что ch содержит ASCII-код извлеченной цифры, т.е. значение в диапазоне от 48 (код '0') до 57 (код '9'). Вычитая '0' (т.е. 48), сдвигаем эти значения из диапазона 48-57 в диапазон 0-9 и тем самым получаем числовое значение для цифры, представленной ASCII-кодом.

Для примера "разберем" число 98.6 (символом ^ отмечен текущий обрабатыва­емый символ):



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

value = value/divisor;

после выполнения которого в переменной value образуется значение 98.6. В ч. 2 этот фрагмент вставим в программу вычисления выражений.

6.9. ОПЕРАТОР DO-WHILE

Оператор do-while нередко называют просто оператором do. Его синтаксис сле­дующий:

do оператор while (выражение);

Примечание: точка с запятой обязательна /

Оператор do-while исполняет оператор, следующий за служебным словом do, до тех. пор, пока значение выражения не станет равным нулю, Оператор do-while похож на оператор while, но в отличие от последнего в нем условие цикла (вы­ражение) вычисляется и проверяется после очередного исполнения оператора. Это означает, что следующий за служебным словом do оператор будет в отличие от цикла while выполнен не менее одного раза.

Для изменения хода исполнения операторов, составляющих тело цикла do-while, можно воспользоваться операторами break и continue. Действие этих операторов на ход исполнения цикла показано на следующей диаграмме:



Как и в случае оператора while, действие операторов break и continue эквива­лентно действию операторов перехода с ограниченным диапазоном передачи уп­равления.

6.10. ОПЕРАТОР FOR

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

8ыражение._1; . /* Инициализировать условие цикла */

while (выражение_2) /* Проверить условие цикла */

{

выражение_3; /* изменить условие цикла */

}

Например, следующий цикл копирует содержимое символьного массива name в массив co_name:

i=0; /* Инициализации */

while name[i] != '\0') /* Условие цикла, */

{

со_name[ i ] = name[i];

i=i+1; /* Модификация условия */

} со_name[i] = '\0';

Этот пример настолько типичен, что и язык Си был включен оператор for, который один реализует все три операции: инициализацию счетчика цикла, проверку его зна­чения и его модификацию. Синтаксис оператора for следующий:



Выражение_1 вычисляется один, и только один раз перед проверкой условия цикла. Выражение_2 задает условие продолжения цикла. Если его значение отлично от нуля ("истина"), то будет выполнен оператор, составляющий тело цикла. После этого будет вычислено выражение _3, указанное в операторе for. Хотя оно может иметь произвольный характер, обычно его используют для модификации условия про­должения цикла. Затем снова вычисляется условие продолжения цикла и весь процесс повторяется заново. Оператор выполняется, пока значение условия цикла остается отличным от нуля. (Обратите внимание, что выражение_2 и выражение_3 вычисляются на каждом проходе цикла, в то время как выражение_1 вычисляется только перед его началом.)

Приведем пример оператора for, эквивалентного предыдущему примеру с опе­ратором while и предназначенного для копирования содержимого массива name в массив co_name:

for (i = 0; name[i] != '\0'; i = i + 1)

co_name[i] = name[i]; co_name[i] = '\0';

Оператор for удобен и легче для восприятия, чем оператор while. Это обусловлено тем, что все три выражения, связанные с организацией цикла (инициализация, проверка и модификация) собраны вместе. При этом не приходится просматривать исходный код в поисках выражений, обеспечивающих инициализацию и модификацию, как пришлось бы при применении оператора while.

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

for ( ; ;) оператор /* Исполняется бесконечно */

эквивалентен оператору while(1). А в операторе for( ; scanner() != END; )

опущены выражения инициализации и модификации.

Как и в случае операторов while и do-while, последовательность передачи уп­равления в операторе for может быть изменена с помощью операторов break и continue. Действие этих операторов показано на следующей диаграмме:



— >

6.11. ОПЕРАТОР GOTO И МЕТКИ ОПЕРАТОРОВ

Операторы break и continue описывались как операторы перехода с ограничен­ным диапазоном передачи управления. В дополнение к ним язык Си предоставляет программисту и нашумевший оператор перехода goto.

Оператор goto обеспечивает передачу управления любому оператору функции. Оператор, которому предполагается передать управление, должен быть снабжен меткой. Эта метка указывается в операторе goto. В синтаксисе оператора goto goto идентификатор

идентификатор является именем метки. Синтаксис метки имеет вид идентификатор:

Строго говоря, при написании программ применение оператора goto не является необходимым. Как уже упоминалось в начале этой главы, любая программа может быть написана с помощью применения трех конструкций: последовательности опе­раторов, выбора и итерации. Однако можно найти ситуации, когда оператор goto удобен [Knuth], и поэтому он был включен в состав языка Си.

Обычно оператор goto служит для передачи управления в конец функции в слу­чае обнаружения ошибки, особенно если ошибка может возникать во многих ме­стах программы. Тем самым может быть исключено применение флагов. Расс­мотрим следующий пример:

Структурированное использование оператора goto

buy ()

{

if (get_trans() = = FAILURE) goto error;

if (update_current() = = FAILURE) goto error; if (update_ytd() = = FAILURE) goto error;

return(SUCCESS); error:

/* коды для обработки ошибок */

return(FAILURE);

}

Заметьте, что этот код мог бы быть написан без оператора goto, например, за счет применения вложенных операторов if и флага состояния. Однако, как будет показано далее, ограниченное применение оператора goto иногда может упростить исходный код.

Другим примером применения оператора goto может служить выход из глубоко вложенных циклов. Поскольку оператор break выводит управление только из са­мого внутреннего цикла, то для выхода наружу из вложенных циклов может быть использован оператор goto. В следующем примере оператор goto должен выпол­няться в случае возникновения ошибочной ситуации, при которой необходим вы­ход сразу из обоих операторов while: while (выражение)

while (выражение) {

if (/* ошибка */) goto loop_end;

} } loop_end:

/* Остальной код */

Хотя в отдельных случаях применение оператора goto достаточно безопасно, в этой книге его использовать не будем.

часть 2

В этой части сосредоточимся на программе вычисления выражений. Сделаем в ней добавления, обеспечивающие получение действующего варианта программы, Программа управления портфелем акций будет развиваться в последующих главах.

6.12. ПРОГРАММА ВЫЧИСЛЕНИЯ ВЫРАЖЕНИЙ

Основные изменения в этой версии программы вычисления выражений коснутся модулей SCAN.C, EXECUTE.C и EVAL.C. К функции scanner, находящейся в мо­дуле SCAN.C, будет добавлен код для разбора числа (см. рис.6.3). Модуль EXECUTE.C будет расширен таким образом, чтобы имелась возможность выпол­нять четыре действия, задаваемые в таблице переходов. Наконец, функция eval, находящаяся в модуле EVAL, будет расширена так, чтобы действительно выпол­нялись операции сложения, вычитания, умножения и деления. При изучении этих функций помните, что в качестве операндов выполняемой программой операции используются два верхних значения стека результатов. Результат ее выполнения возвращается обратно в стек результатов.

Приведем новый исходный код программы вычисления выражений:

/* Содержание файла CALC.H */

/*

* Определить возвращаемые значения общих функций. */

#define TRACE /* Включает в программу отладочный код */

#define SUCCESS 1 #define FAILURE 0 #define DONE 0

/*

* Ниже приводятся определения кодов элементов выражения и классов

* символов, используемых функцией scanner.

* Эти значения используются как индексы в таблице переходов. */

«define END 0 /* Конец выражения */

#define EMPTY 0 /* Пустой стек */

#define LPAREN 1 /* ( */

#define RPAREN 6 /* ) */

#define MULT 4 /* * */

«define PLUS 2 /* + */

«define MINUS 3 /* - */

«define DOT 8 /* . (десятичная точка) */

«define DIVIDE 5 /* / */

«define NUMBER 7 /* Числовая константа */

«define WHITE 9 /* Пробельные элементы */

#define ER 20 /* Остальные (нежелательные) символы */

/* Содержание модуля CALC.C */

/*

* Этот файл содержит функцию main программы вычисления выражений. */

#include "CALC.H"

/* Объявить внешние функции */

extern exs_init(), ops_init(); /* STACK.С */

extern int getexpr(); . /* SCAN.C */

extern int execute(); /* EXECUTE.C */ /**

* Это основная управляющая функция программы вычисления

* выражений. **/

main()

{

exs_init(); ops_init(); /* Инициализировать стеки */

getexpr();

execute()

}

/* Содержание модуля EXECUTE.С */

/* * Этот файл содержит Функцию execute программы вычисления выражений.

#include "CALC.H"

extern int scanner().; /* SCAN.С */

extern float value; /* Число, извлеченное функцией

scanner */

extern int exs_push(); /* STACK. С */

extern float exs_pop(); /* STACK.С */

extern int ops_top(}; /* STACK.С */

extern int ops_push{); /* STACK.С */

extern int ops_pop(); /* STACK.С */

/* Текущий элемент */

Конец ( + - /. ) */

/* Определить таблицу переходов */



/**

* Эта функция выполняет разбор и вычисление выражения.

**/ execute()

}

int token; /* Текущий элемент */

int action = 1; /* Из таблицы переходов */

token = scanner(); /* Извлечь первый элемент */

while,(action i= DONE)

{

if (token = = NUMBER) /* Поместить число в стек результатов */

{

exs_push(value);

token = scanner();

} else

{

/* Определить индекс в таблице переходов, используя текущий элемент и верхнюю операцию из стека операций */ action = trans_table[ops_top()][token];

#ifdef TRACE

printf("Действие = %d\n".action);

#endif

switch (action)

{

case 0: /* конец выражения */

/* изобразить результат */

printf ("%f\n" ,exs_pop( 5);

break; case 1:

ops_push(token); token = scanner(); break; case 2:

eval(); /* выполнить верхнюю операцию */ ops_push(token); token = scanner(); break; case 3:

ops_pop(); /* извлечь операцию из стека * token = scanner(); break; case 4:

eval(); /* выполнить верхнюю операцию */ break; case 10:

printf("Ошибка в выражении\n"); action = 0; break; } } } #ifdef TRACE

printf("Выполнение эавершено\n"); #endif

return; } /* Содержание модуля SCAN.С */

/*

* Этот файл содержит функции scanner и getexpr программы вычисления

* выражений. */

#include "CALC.H"

#define MAX_LINE 81

static char line[MAX_LINE]; /* Содержит текущее выражение */

static int position; /* Индекс массива line */

float value; /* Число, извлеченное функцией scanner */

/*

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

* символу выражения определенного класса, соответствующего типу

* элемента, в состав которого входит этот символ. Каждому эле-

* менту приписан числовой код в диапазоне от 0 до 20 (20 озна-

* чает наличие в элементе недопустимого символа). Этот массив

* рассчитан на подмножество смежных символов от пробела до цифры

* 9. */

static char token_codes[26] =

{ WHITE,ER,ER,ER.ER,ER,ER,ER, /* Пробел,! ,",#,$,%,&,'*/

LPAREN.RPAREN,MULT,PLUS, /* (,),*,+ */

ER,MINUS,DOT,DIVIDE, /* , ,-,.,/*/

NUMBER,NUMBER,NUMBER,NUMBER, /* 0,1,2,3 */

NUMBER,NUMBER,NUMBER,NUMBER, /* 4,5,6,7 */

NUMBER,NUMBER /* 8,9 */ };

/**

Эта функция отвечает за поиск очередного элемента выражения. Элементами могут быть операции

* +,-,* или /

или операнд (в данной версии мы ограничимся одной цифрой). **/

int scanner()

{

char ch; /* Текущий символ выражения */

int token; /* Текущий элемент выражения */

int index; /* Индекс массива token_codes */

float divisor; /* Масштабный коэффициент для дробной части числа */

ch = line[position];

if (ch = = '\0') return(END); /* Конец выражения */

if (ch < ' ') return(ER); /* Недопустимый символ: < пробел */

if (ch > '9') return(ER); /* или > 9 */

/* Использовать символ как индекс в массиве.

* Вначале масштабировать его так, чтобы пробелу

* соответствовал нулевой индекс.

*/

index = ch - ' '; token = token_codes[index]; switch (token) {

case DOT:

token = NUMBER;

case NUMBER: /* Разобрать число */ value = 0; divisor = 1;

while (token_codes[ch - ' '] = = NUMBER) {

value = value*10 + (ch - '0');

position = position + 1;

ch = line[position];

}

if (ch = = '.')

{

position = position + 1;

ch = line[position];

while (token_codes[ch - ' '] = = NUMBER)

{

divisor = divisor*10; value = value*10 + (ch - '0'); position = position + 1; ch = line[position];

}

}

value = value/divisor; break;

default:

position = position + 1; break; .

}

#ifdef TRACE

printf("Элемент = %d\n".token);

#end if

return(token);

}

/**

Эта функция выдает пользователю приглашение к вводу выражения

и считывает вводимое выражение.

**/

getexpr()

{

int ch; /* Текущий введенный символ */

extern getline(); /* GETLINE.C */

printf("* ");

getline(line,MAX_LINE);

position =0; /* Установить значение внешнего индекса

на начало строки */

return;

}

/* Содержание модуля GETLINE.C */

/*

* Этот файл содержит функцию getline.

*/ #include "stdio.h" /* Может понадобиться функция getchar */

/**

* Эта функция считывает строку данных с клавиатуры и запоминает

* ее в заданном массиве символов. Она возвращает число считанных

* символов. **/

getline(array, size)

char array[]; /* Массив символов соответствующей длины */

int size;

{

register int i; /* Позиция а массиве */

int с; /* Введенный символ */

i=0;

с = getchar();

/* Игнорировать ведущие символы перехода на новую строку */

while (с = ='\n'} с = getchar();

/* Считывать символы, пока не будет обнаружен возврат каретки *

while (с := '\n')

{

/# "Не переполнять массив -- оставить место для нулевого

байта */

if (i < (size - 1))

{

array[i] = с; i=i+1;

}

с = getchar();

}

array[i] = '\0'; return(i);

}

/* Содержание модуля EVAL.C */

/*

* Этот файл содержит функцию eval, программы вычисления

* выражений. */

#include "CALC.H"

extern float exs_pop{); /* STACK. С */

extern int ops_рор(), exs_push(); /* STACK.С */

/**

* Эта функция выполняет заданную oпeрацию над двумя числами,

* которые снимаются с верха стека операндов. **/

eval() {

int operator;

float left, right, result;

/* Извлечь операцию и операнды из стеков */

operator = орs_рор();

right - ехs_рор{); left = exs_pop() ;

switch (operator)

{•

case PLUS;

result - left + right;

exs_push(result);

break; сазе MINUS:

result - left - right;

exs_push(result); break; case MULT:

result = left*right; exs_push(result); break; case DIVIDE:

if (right != 0.0) /* Проверить делитель на нуль */ {

result = left/right; exs_push(result) ; } else {

printf("Ошибка: деление на нуль\n"); }

break; } #ifdef TRACE

printf("eval: op - %d, left = %f, right = %f, result = %f\n",

operator,left,right,result); #end if

return; }

/* Содержание модуля STACK.С */ /*

Этот файл содержит функции для работы со стеком программы

* вычисления выражений.

*/ #include "CALC.H"

/**

* Этот файл содержит группу функций для выполнения операций над

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

* значений (т.е. операндов) и другой для хранения операций,

* которые снимаются с верха стека операндов.

* В состав этой группы входят следующие функции:

* Стек результатов Стек операций Назначение

* exs_init ops_init инициализация стека

* exs_push ops_push поместить в стек

* ехs_рор орs_рор извлечь из стека

* exs_top ops_top посмотреть содержимое

* вершины стека **/

'* Определить стеки и индексы стеков */

#define MAX_STACK 20 /* Максимальный размер стека */

'*

* Стеки содержат на один элемент больше максимального размера

* для удобства проверки пустоты и переполнения.

*/ static float ex_stack[MAX_STACK+l]; /* Стек результатов (содержит

числа) */ static int op_stack[MAX_STACK+l]; /* Стек операций (содержит

символы) */ static int ex_index, op_index;

/**

* Инициализировать стек результатов и указатель стека (индекс). **/

exs_init() {

ex_index = 0;

ex_stack[0] = EMPTY; /* Присвоить значение EMPTY ("пуст") */ return; 1

/**

* Поместить "значение" в стек результатов. Если все нормально,

* возвратить SUCCESS, если стек полон, возвратить FAILURE. **/

int exs_push(value)

float value;

{

int result = SUCCESS;

if (ex_index < MAX_STACK) {

ex_index = ex_index + 1;

ex_stack[ex_index] = value; } else { '

result - FAILURE; }

return(result); } •/**

Извлечь значение, помещенное в стек последним. Возвратить

* это значение. Если стек пуст, то возвратить EMPTY. **/

float exs_pop() {

float result;

result = ex_stack[ex_index]; if (ex_index > 0) ex_index = ex_index - 1; return(result); }

/**

Возвратить содержимое вершины стека (не изменяя значение

* указателя стека). **/

float exs_top() {

return(ex_stack[ex_index]); } /**

* Инициализировать стек операций и указатель стека (индекс). **/

ops_init() {

op_index = 0;

op_stack[0] = EMPTY; /* Присвоить EMPTY ("пуст") */

return; } /**

Поместить "операцию" в стек операций. Если все нормально,

* возвратить SUCCESS, если стек полон, возвратить EMPTY. **/

int ops_push(operator)

int operator;

{

int result = SUCCESS;

if (op_index < MAX_STACK)

{

op_index = op_index + 1; op_stack[op_index] = operator;

} else

{

result = FAILURE;

return(result);

}

/**

* Извлечь значение, помещенное в стек последним. Возвратить

* это значение. Если стек пуст, то возвратить EMPTY. **/

int ops_pop()

{

int result;

result = op_stack[op_index];

if (op_index > 0) op_index = op_index - 1; return(result);

}

/**

* Возвратить содержимое вершины стека (не изменяя значение

* указателя стека).

**/

int ops_top()

{

return(op_stack[op_index]);

}

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

ЛИТЕРАТУРА

Bohm, С., G. Jacopini, "Flow Diagrams, Turing Machines, and Languages with Only Two Formation Rules", Communications of the ACM, Vol. 9, No. 5 (May 1969), pp. 366-371.

Knuth, D., "Structured Programming with go to Statements", in Classics in Software Engineering. New York:Yourdon Press, 1979: pp. 259-321.



Похожие:

Операторы языка си и управление их исполнением iconАлфавит языка программирования Pascal. Константы и переменные. Величины. Типы величин. Операторы ввода и вывода данных
Алфавит языка программирования, представляет собой набор латинских букв, арабских цифр, знаков арифметических операций, специальные...
Операторы языка си и управление их исполнением iconКонспект урока по информатике учителя Оганьян Э. А. Тема урока : Основные операторы языка Бейсик Тип урока: урок обобщение План урока
Каждый из них должен написать, что появится на экране при выполнении данных задач
Операторы языка си и управление их исполнением iconШкольное методическое объединение учителей русского языка и литературы Методическая тема: «Управление познавательной и творческой деятельностью учащихся на уроке и во внеклассной работе» Руководитель шмо: Ткалич Татьяна Владимировна Сведения об учителях
Методическая тема: «Управление познавательной и творческой деятельностью учащихся на уроке и во внеклассной работе»
Операторы языка си и управление их исполнением iconО преподавании немецкого языка в моу «сош г. Бирюча» Красногвардейского района в 2008-2009 учебном году
Учитель русского языка и литературы, немецкого языка по специальности «Филология»
Операторы языка си и управление их исполнением iconМанипуляция в рекламе
Оксфордский словарь английского языка трактует манипуляцию как акт влияния на людей или управления ими с ловкостью, особенно с пренебрежительным...
Операторы языка си и управление их исполнением iconДокументы
1. /Perl. Операторы и приоритеты.txt
Операторы языка си и управление их исполнением iconДепартамент образования города москвы северо-восточное окружное управление образования государственное образовательное учреждение средняя общеобразовательная школа с углублённым изучением английского языка №0000
Комиссия, назначенная приказом директора школы от августа 2007 года в составе
Операторы языка си и управление их исполнением iconСтр из главное управление национальной полиции центральное управление судебной полиции межрегиональное управление судебной полиции бордо отряд байонна
Передавая нижеследующее дело3, согласно Вашим указаниям, я имею честь представить отчет, о результатах проведенного расследования...
Операторы языка си и управление их исполнением iconДекарт, Лейбниц, Вы? Или на порядок лучше Эсперанто
Изучение языка требует затрат времени и работы памяти. Ускорить и облегчить изучение позволяет структура (внутренние логические закономерности)...
Операторы языка си и управление их исполнением icon«Современные проблемы лингвистики и методики преподавания русского языка в вузе и школе» (Выпуск 2)
Новое научно-методическое издание призвано объединить усилия многих ученых-лингвистов и преподавателей русского языка, в сфере интересов...
Операторы языка си и управление их исполнением iconСправочник "Региональные операторы Государственного банка данных о детях, оставшихся без попечения родителей, Российской Федерации" (данные на 15. 08. 2006)

Разместите кнопку на своём сайте:
Документы


База данных защищена авторским правом ©podelise.ru 2000-2014
При копировании материала обязательно указание активной ссылки открытой для индексации.
обратиться к администрации
Документы

Разработка сайта — Веб студия Адаманов