Базовый FORTRAN (Formula translation).
Типы.
Integer (целый), real (вещественный), logical (логический), complex (комплексный), double precision (вещественный с двойной точностью)
Описание переменных.
Integer A, B, C
Real K, M1
DATA А/15/, К/3.14/, M1/2.72/ - задание начальных значений
Массивы.
Нижняя граница по умолчанию 1.
Вариант 1
Integer A(10,20)
Logical T, V(50)
Вариант 2
Integer A
Dimension A(10,20)
Логические операторы сравнения.
.GT. > .NE. ¹
.GE. ³ .LE. £
.EQ. = .LT. <
Логические связки.
.AND. .OR. .NOT.
Операторы.
Присвоения
I=5
Условного ветвления
Оператор «альтернативы». Не было ветвления «иначе», управление передавалось следующему оператору.
Синтаксис оператора
IF(<логич.выражение>) <оператор>
Пример реализации конструкции IF (<условие>) <операторы 1> ELSE <операторы 2>.
IF (<условие>) GOTO 100
<операторы 1>
GOTO 200
100 <операторы 2>
200 CONTINUE - продолжить
Оператор «выбора»
Синтаксис оператора.
GOTO (<метка 1>, <метка 2>,…..<метка n>), <переменная>
Переход осуществлялся по алгоритму: переход на метку по порядку совпадающем со значением переменной (переменная =1 – переход на метку 1 и т.д.)
Цикл («с границами»).
DO <метка> <счетчик>=<нач. граница>, <предел>, <шаг>
<тело цикла>
<метка> оследний оператор цикла - часто CONTINUE (пустой оператор)
Основы языка программирования Ассемблер.
Ассемблер — низкоуровневый машинно-ориентированный язык программирования. Реализация языка зависит от типа процессора и определяется архитектурой вычислительной системы. Ассемблер позволяет напрямую работать с аппаратурой компьютера. Программа на языке ассемблера включает в себя набор команд, которые после трансляции преобразуются в машинные команды.
Реализация большинства операций в языке Ассемблер основана на непосредственном использовании регистров процессора. Микропроцессорная память процессора Intel 8088 включает 14 двухбайтовых запоминающих регистров. По назначению они делятся на 4 группы.
· Универсальные регистры AX, BX, CX, DX. Каждый из универсальных регистров может использоваться для временного хранения любых данных. Разрешается работать как с регистром целиком, так и отдельно с каждой его половиной. Для обращения к старшим байтам используются регистры AH, BH, CH, DH, для обращения к младшим байтам — регистры AL, BL, CL, DL.
· Сегментные регистры CS, DS, SS, ES используются для хранения начальных адресов полей памяти (сегментов), отведенных в программах для команд (CS), данных (DS), стека (SS), данных при межсегментных пересылках (ES).
· Регистры смещений IP, SP, BP, SI, DI служат для хранения относительных адресов ячеек памяти внутри сегментов, т.е. смещений относительно начала сегментов.
· Регистр флагов FL содержит 9 одноразрядных флагов, управляющих прохождением программы в компьютере. Например, ZF — флаг нуля, устанавливаемый в 1, если результат операции равен нулю; SF — флаг знака, устанавливаемый в 1, если после арифметической операции получен отрицательный результат; OF — флаг переполнения, устанавливаемый в 1 при арифметическом переполнении; IF — флаг прерываний, разрешающий (значение 1) или запрещающий (значение 0) прерывания.
Ассемблерная программа может включать в себя следующие основные элементы: константы, команды, директивы и модификаторы. Константы языка ассемблер подразделяются на два типа: целые числа и строки. Целые числа могут быть представлены в двоичном, десятичном и шестнадцатеричном виде. Строки заключаются в одинарные или двойные кавычки.
Команды или операторы имеют следующий формат:
[<Метка>[:]] <Код оператора> [<Операнды>] [;<Комментарий>]
Основные типы команд.
· Выполнения арифметических операций. Например, команда ADD <приемник>, <источник> осуществляет сложение двоичных чисел, а именно содержимое источника складывается с содержимым приемника, при этом операнды должны иметь одинаковый формат. Команда MUL <источник> предназначена для перемножения чисел без учета знака. В этом случае операнд представляет собой 8- или 16-битовый множитель, множимое хранится соответственно в регистре AL или AX, а произведение будет сохранено в регистре AX или AX и DX. Команда CMP <приемник>, <источник> выполняет сравнение двоичных чисел.
· Выполнения логических операций. Например, команды OR <приемник>, <источник> и AND <приемник>, <источник> — выполняют соответственно поразрядную дизъюнкцию и конъюнкцию битов операндов.
· Пересылки данных. Например, MOV <приемник>, <источник> — пересылает в зависимости от формата операндов один байт или одно слово между регистрами или между регистром и памятью, т.е. заносит непосредственное значение в регистр или память.
· Передачи управления. Команда безусловного перехода: JMP <операнд> — выполняет передачу управления по заданному адресу. В качестве операнда указывается прямой или косвенный адрес. Команды условной передачи управления, называемые также иногда триггерами, имеют вид: J<условие> <метка>. Например, JG — переход, если больше, т.е., если флаги ZF=0 и SF=OF; JL — переход, если меньше, т.е., если флаг SF¹OF; JE/JZ — переход, если равно/нуль, т.е., если флаг ZF=1; JS — переход, если знак отрицательный, т.е., если флаг SF=1. К этой группе относятся также следующие команды: LOOP — управления циклом, CALL — вызова процедуры, RET — возврата из процедуры.
· Прерывания работы программы. Прерывание — это приостановка выполнения программы процессором с целью выполнения другой программы (программы обработки прерывания), после завершения которой, как правило, продолжается выполнение прерванной программы с момента её прерывания. Основной представителем этой группы является команда INT <номер прерывания>, прерывающая выполнение программы и передающая управление подпрограмме обработки, заданной номером прерывания.
· Управления процессором. Например, ST* и CL* — установки и сброса флагов, HLT — останова, WAIT — ожидания, NOP — холостого хода.
· Обработки строк символов. Например, MOVS — пересылки, CMPS — сравнения, LODS — загрузки, SCAS — сканирования.
Директивы или псевдооператоры ассемблера представляют собой инструкции транслятору. В отличие от команд, являющихся инструкциями машине, директивы обрабатываются только в ходе трансляции программы в машинный код, а не в ходе её выполнения на компьютере. Директивы имеют следующий формат:
[<Идентификатор>] <Код псевдооператора> [<Операнды>] [;<Комментарий>]
Для идентификации переменных и полей данных используются директивы определения данных. Они позволяют объявить переменную, задав её имя, присвоить ячейкам памяти начальные значения или зарезервировать область памяти для последующего сохранения в ней некоторых значений. Имеют следующий формат:
[<имя>] D<формат> <выражение>[, <выражение>][,…]
где имя — набор символов, начинающийся с буквы, используемый для ссылки на переменную или поле данных. Формат может иметь следующие значения: B — байт, W — слово (2 байта), D — двойное слово (4 байта), Q — 8 байтов, T — 10 байтов. Выражение показывает, какое количество элементов памяти необходимо выделить и какие данные там будут содержаться.
Также в программе используются директивы определения сегментов:
<имя сегмента> segment
<содержимое сегмента>
<имя сегмента> ends
В программе можно использовать 4 сегмента (по числу сегментных регистров) и для каждого из них в сегменте кода следует указывать соответствующий регистр сегмента директивой ASSUME. Например:
COMMANDS segment
assume CS:COMMANDS, DS:DATA, SS:STACK
…
COMMANDS ends
После директивы ASSUME необходимо загрузить адрес начала сегмента данных в регистр DS. Инициализация сегментных регистров CS и SS выполняется автоматически.
Модификаторы используются в командах и директивах ассемблера для выполнения некоторых операций над операндами, обрабатываемых в ходе трансляции программы.
Ниже приведен пример ассемблерной программы с комментариями, предназначенной для вычисления суммы целых чисел от 1 до N (здесь и далее знак Þ означает продолжение строки программы на следующей строке индекса).
TITLE sum1n.asm - программа вычисляет сумму целых чисел от 1 Þ до N (N < 1000)
STACK segment ; Начало сегмента стека
dw 64 dup(?)
STACK ends ; Конец сегмента стека
DATA segment ; Начало сегмента данных
ZeroCode = 48 ; ASCII-код цифры 0
; Задаем строки с сообщениями, используемые в ходе работы Þ программы
; Символ "$" в конце строк - требование DOS
TitleMsg db "Программа вычисляет сумму целых чисел от 1 до N Þ (N < 1000)", 13, 10, "$"
InputMsg db "Введите число N: ", "$"
ResultMsg db 13, 10, "Сумма равна ", "$"
; Объявляем необходимые переменные
M10 dw 10 ; Множитель 10
N dw ? ; Введенное число N в двоичном формате
P10 dw 1 ; Степень 10
StrN db 4, 5 dup(0) ; Число N в формате строки Þ
(первый байт - максимальное число вводимых символов)
StrSum db 6 dup(0), "$" ; Сумма в формате строки
Sum dd 0 ; Вычисляемая сумма
DATA ends ; Конец сегмента данных
CODE segment ; Начало сегмента кода
assume CS:CODE, DS:DATA, SS:STACK ; Связываем сегментные Þ регистры с сегментами
main proc far ; Объявляем главную программную процедуру Þ (требование DOS)
; Записываем адрес префикса программного сегмента в стек Þ (требование DOS)
push ds
sub ax, ax
push ax
mov ax, DATA ; Пересылаем адрес сегмента данных в регистр AX
mov ds, ax ; Устанавливаем регистр DS на сегмент данных
; Выводим сообщение о назначении программы
mov AH, 09h ; Определяем в качестве обработчика прерывания Þ DOS-функцию вывода строки на экран
mov DX, offset TitleMsg ; Задаем смещение к началу строки
int 21h ; Выводим строку
; Выводим сообщение с запросом на ввод числа N
mov AH, 09h
mov DX, offset InputMsg
int 21h
; Запрашиваем число и сохраняем его в переменной StrN
mov AH, 0Ah ; Определяем в качестве обработчика прерывания Þ DOS-функцию ввода строки символов
mov DX, offset StrN ; Задаем смещение к началу строки
int 21h ; Запрашиваем строку
; Теперь в переменной StrN хранятся следующие значения Þ (байты перечисляются слева направо):
; 1-й байт - максимальное число вводимых символов Þ (для данного примера - 4)
; 2-й байт - действительное число введенных символов
; последующие байты - ASCII-коды введенных символов, Þ последний из которых всегда - 13 (код клавиши Enter)
; Переводим введенное число в двоичный формат
; (в данный момент число представлено двоичными кодами цифр, Þ т.е. ASCII-кодами введенных символов)
mov P10, 1 ; Заносим 1 в степень 10
mov DI, 0 ; Обнуляем регистр, в котором будем сохранять Þ результат
mov SI, offset StrN + 1 ; Заносим в регистр SI адрес Þ ячейки, в которой хранится количество цифр числа Þ
(хранится во втором байте переменной StrN)
mov BL, [SI] ; Заносим в младший байт регистра BX Þ количество цифр числа
mov BH, 0 ; Обнуляем старший байт регистра BX
mov SI, offset StrN + 2 ; Заносим в регистр SI адрес Þ ячейки первой цифры введенного числа
LS2B: mov AL, [SI + BX - 1] ; Заносим в младший байт Þ регистра AX ASCII-код текущей цифры числа (цифры перебираем справа налево)
sub AL, ZeroCode ; Вычитаем из кода цифры код цифры 0 для Þ получения соответствующего числа
mov AH, 0 ; Обнуляем старший байт регистра AX
mul P10 ; Умножаем значение регистра AX на число 10 в Þ степени, соответствующей позиции текущей цифры
add DI, AX ; Добавляем полученное произведение к конечному Þ результату
mov AX, P10 ; Сохраняем степень 10 в регистре AX
mul M10 ; Увеличиваем степень 10 на порядок (содержимое Þ регистра AX умножаем на 10)
mov P10, AX ; Сохраняем новое значение степени в Þ соответствующей переменной
dec BX ; Определяем номер следующей цифры
jnz LS2B ; Переходим к обработке следующей цифры, если Þ перебраны еще не все цифры числа
; Теперь в регистре DI находится введенное число в двоичном Þ формате
; Запоминаем его в переменной N
mov N, DI
; Вычисляем сумму от 1 до N
mov AX, 0 ; Обнуляем регистр AX
LSM: inc AX ; Увеличиваем содержимое регистра AX на 1, Þ определяя очередное слагаемое
add word ptr Sum[2], AX ; Добавляем содержимое регистра AX Þ к младшему слову суммы
adc word ptr Sum[0], 0 ; Добавляем 0 к старшему слову Þ суммы с учетом переноса от предыдущего сложения Þ
(учитываем перенос, если он был)
cmp AX, N ; Если содержимое регистра AX меньше числа N,
JB LSM ; переходим к следующему слагаемому
; Переводим полученную сумму в форму строки
mov SI, offset StrSum + length StrSum - 1 ; Заносим в Þ регистр SI адрес ячейки для хранения последней цифры числа
mov DX, word ptr Sum[0] ; Заносим в регистры DX:AX число, Þ которое будем переводить в строку
mov AX, word ptr Sum[2]
LB2S: div M10 ; Делим число, находящееся в регистрах DX:AX Þ на 10
add DL, ZeroCode ; Добавляем к остатку от деления код Þ цифры 0 для получения ASCII-кода цифры
mov [SI], DL ; Сохраняем найденную цифру в соответствующей Þ позиции строки с результирующим числом
dec SI ; "Переходим" к предыдущей цифре числа
mov DX, 0 ; Обнуляем регистр DX
cmp AX, 0 ; Если частное отлично от нуля (определены не Þ все цифры числа),
jne LB2S ; то переходим к вычислению очередной цифры числа
; Выводим сообщение, предшествующее выводу результата
mov AH, 09h
mov DX, offset ResultMsg
int 21h
; Выводим полученное число
mov AH, 09h
mov DX, offset StrSum
int 21h
ret ; Выходим из основной процедуры
main endp ; Конец основной процедуры
CODE ends ; Конец сегмента кода
END MAIN ; Конец программы (требование DOS)