
4 Вопрос.
Функциональный определяется как заголовок процедуры и функции со списком формальных параметров, но без имени.После объявления функционального типа его можно использовать для описания формальных параметров — имен процедур и функций.тКроме того, необходимо написать те реальные процедуры или функции, имена которых будут передаваться как фактические параметры. Эти процедуры и функции должны компилироваться в режиме дальней адресации с ключом {$F+}.универсальная процедура печати значения для любых функций при х изменяющимся от А до Б с шагом h Type Fan=function (x:real):real; {P+}end; Function F1(x:real):real; Far;{компиляция в режиме дальнего вызова} Begin F1:=sinx*cosx;end; Function F2(x:real):real; Far;{компиляция в режиме дальнего вызова} Begin F1:=sqr(sqr(x))+sqr(x); end; {P-} Procedure TAB (F:fan; A,B,H:real);Var x:real; I,n:word; Begin n:=round((B-A)/H);x:=A; For i:=0 to n do begin writeln(x:12,F(x):14); x:=x+h; end; end; Begin tab(f1,0,1,0,1); tab(F2,5,7,0,1); end. 5 ВОПРОС.
В теле подпрограммы доступны все объекты, описанные в объемлющем блоке, в том числе и имя самой подпрограммы. Подпрограммы, вызывающие сами себя, называются рекурсивными. Пример: алгоритм вычисления факториала: N! = (N-1)!*N Fuction Fact(N: Word): LongInt; Begin If N = 1 then Fact:= 1 else Fact:= N * Fact(N-1); End; Необходимо только помнить, что каждый очередной рекурсивный вызов приводит к образованию новой копии локальных объектов подпрограммы и все эти копии, соответствующие цепочке активизированных и незавершенных рекурсивных вызовов существуют независимо друг от друга. Локальное распределение памяти подразумевает, что место для переменных и объектов выделяется на стеке программы. Стек представляет собой рабочую область памяти, резервируемую программой при ее загрузке. Любая память, необходимая программе для хранения локальных переменных, для вызовов функций и т. д. берется из стека. Она выделяется по мере необходимости и освобождается, когда надобность в ней отпадает; обычно этот процесс связан с выполнением тела функции или другого локального блока кода. При входе в функцию происходит выделение памяти для всех ее локальных переменных, а завершение ее работы приводит к автоматическому освобождению выделенной памяти. Причем дописывание информации в стек происходит при каждом рекуррентном вызове , поэтому нужно следить за глубиной рекурсии, иначе слишком длинная, или бесконечная рекурсия забьет все стековое пространство и программа не сможет выполняться дальше, произойдет ошибка времени исполнения. Максимальный объём стековой памяти в Турбо-Паскале — 1 сегмент (65520 байт). Можно устанавливать размер стека и контроль за переполнением стека — $M и $S (компилятор может включить в программу код, следящий за переполнением стека и выдающий вовремя сообщение о переполнении стека, вместо зависания программы, обычно этот ключ установлен по умолчанию). 6 ВОПРОС.
Синтаксические анализаторы. Элементы металингвистических формул. Формы Бэкуса-Наура Синтаксический анализатор (синтаксический разборщик) - это часть компилятора, которая отвечает за выявление и проверку синтаксических конструкций входного языка. В задачу синтаксического анализатора входит: • найти и выделить синтаксические конструкции в тексте исходной программы; • установить тип и проверить правильность каждой синтаксической конструкции; • представить синтаксические конструкции в виде, удобном для дальнейшей генерации текста результирующей программы. Цепочки языка могут содержать метасимволы, имеющие особое назначение. Метаязык. Предложенный Бэкусом и Науром использует следующие обозначения: Символ "::=" отделяет левую часть правила от правой9 читается: "определяется как") Нетерминалы (синтаксическая категория) обозначаются произвольной символьной строкой. Заключается в угловые скобки "< и >" Терминалы — это символы, используемые в описываемом языке, правило может определять порождение нескольких альтернативных цепочек, отделяемых друг от друга символом вертикальной черты "|" < простое-выражение >::= < целое без знака > (< простое-выражение > < знак > < простое выражение >) < целое- без- знака > ::= < цифра > < цифра > < целое-без-знака > < Знак операции > ::={+,-.*./} 7 ВОПРОС.
. Модуль(unit) в системе Турбо Паскаль-автономно компилируемая именованная программная еденица, не выполняющаяся самостоятельно. Для использования модуля в вызывающей программе необходимо указать его имя в uses-части. Отличия модуля unit от процедуры: • Модуль может включать более одной процедуры; • Модуль может включать не только процедуры. Поэтому модуль не вызывается как процедура, а подключается, объединяясь с вызывающей программой. Таким образом, модуль в системе турбо-паскаль — средство более мощное, чем механизм внешних процедур. Код модуля размещается в отдельном сегменте и за счет этого возможно уменьшение размера программ. Основным принципом модульного программирования является принцип "разделяй и властвуй". Модульное программирование — это организация программы как совокупности небольших независимых блоков, называемых модулями, структура и поведение которых подчиняются определенным правилам. Структура Заголовок, размер интерфейса, раздел реализации, раздел инициализации, Unit < имя_модуля >; имя должно совпадать с именем файла. interface < интерфейсная часть >;В этой части содержатся объявления всех глобальных объектов модуля (типов, констант, переменных и подпрограмм), которые должны быть доступны основной программе. При объявлении глобальных подпрограмм в интерфейсной части указывается только их заголовок. implementation < исполняемая часть >;и содержит описания подпрограмм, объявленных в интерфейсной части. В ней могут объявляться локальные для модуля объекты — вспомогательные типы, константы, переменные и блоки, а также метки. begin < инициирующая часть >; В инициирующей части размещаются исполняемые операторы, содержащие некоторый фрагмент программы. Эти операторы исполняются до передачи управления основной программе и обычно используются для подготовки ее работы В инициирующую часть можно включать вспомогательные операции, подготавливающие программу к работе, например, операции подготовки файлов assign,reset,rewrite. end . unit Compl; interface type complex=record re,im:real; end; procedure readc(var c:complex); procedure AddC (x, y: complex; var z: complex); procedure SubC (x, y: complex; var z: complex); ///implementation procedure readc; begin writeln(‘Введите действительные и мнимые части’); readln(Re,Im); end; Procedure ADDc;; begin z.re:= x.re + y.re; z.im:= x.im + y.im; end; {AddC} procedure SubC; begin z.re:= x.re — y.re; z.im:= x.im — y.im; end; {SubC} end . Модуль должен храниться в одноименном файле TPU,pas файле; Uses complexn; {подключение осуществляется директивой Uses} Var a,b,c: coplex; begin b.re:= 1; b.im:= 2; AddC(a, b, c); Writeln (‘ сложение :’, c.re: 5:1, c.im: 5:1, ‘i’); SubC (a, b, c); Writeln (‘ вычитание :’, c.re: 5:1, c.im: 5:1, ‘i’); begin Assign(F, TILE1.DAT) end. 9 ВОПРОС
Компиляция модулей. Схема поиска. TPU файла компилятором. Утилита TPU MOVER.EXE. три режима компиляции: COMPILE , MAKE , BUILD. Режимы отличаются способом связи компилируемого модуля или основной программы с другими модулями, объявленными в предложении USES . При компиляции модуля или основной программы в режиме COMPILE все, упоминаемые в предложении USES модули, должны быть предварительно откомпилированы, и результаты компиляции должны быть помещены в одноименные файлы с расширением TPU (от англ. Turbo Pascal Unit). Файл с расширением TPU создается автоматически при компиляции модуля Паскаля. В режиме MAKE компилятор проверяет наличие TPU —файлов для каждого объявленного модуля. Если какой-либо файл не найден, система ищет одноименный файл с расширением PAS , т.е. файл с исходным текстом модуля Паскаля. Если таковой файл найден, система приступает к его компиляции.В этом режиме система следит за возможными изменениями исходного текста любого используемого модуля. Программист избавляется от необходимости следить за соответствием TPU —файлов их исходному тексту, т.к. система делает это автоматически. В режиме BUILD существующие TPU —файлы игнорируются, система пытается отыскать и откомпилировать соответствующие PAS — файлы для каждого модуля Паскаля. -компилятор просматривает содержимое системного библиотечного файла модулей Turbo.tpl (Turbo Pascal Library); -если искомый модуль не найден в файле Turbo.tpl, то компилятор осуществляет поиск соответствующего TPU-файла в текущем каталоге; -если в текущем каталоге нужный файл не найден, то поиск продолжается в каталогах, заданных в альтернативе Options/Directories/Unit Directories для интегрированной среды; - если на предыдущих шагах файл не найден, то компилятор прекращает работу и выдает диагностическое сообщение об ошибке. Turbo.tpl. имеет специальную структуру и предназначен для компактного хранения и быстрого доступа к наиболее часто используемым модулям. Обычно в этом файле содержатся несколько системных модулей, однако с помощью специальной служебной программы Tpumover.exe можно произвольным образом конструировать файл Turbo.tpl, включая в него нужные модули и удаляя неиспользуемые. Перечень команд, поддерживаемых программой Tpumover.exe, можно получить, выполнив команду Tpumover.exe без параметров. 10 ВОПРОС.
Процедцры и функции модуля Crt Модуль Паскаля CRT. В нем сосредоточены процедуры и функции, обеспечивающие управление текстовым режимом работы экрана. С его помощью можно перемещать курсор в любую точку экрана, менять цвет выводимых символов и фона, создавать окна. GotoXY (x,y:byte); Процедура GotoXY переводит курсор в нужное место экрана или текущего окна.Функции WhereX и WhereY служат для определения текущих координат курсора; Процедура ClrScr очищает экран; Delay(n)Приостанавливает выполнение программы на n миллисекунд; Sound (f)Включает звуковой генератор (f-Гц); NoSound- Отключает звуковой генератор’ KeyPressed Проверка нажатия клавиши; ReadKey — Чтение символа с клавиатуры 11 ВОПРОС Процедуры и функции модуля STRINGS. Сформировать длинную динамическую строку, используя литерный ввод. Модуль Strings позволяет работать с ASCIIZ-строками (последний байт строки содержит символ с кодом 0). Он используется только в версии 7.0. Введение таких строк связано с необходимостью совместить программы, написанные в Turbo Pascal, с программами, использующими среду Windows, а также для установления соответствия с другими языками (например, Си, ассемблер и т. д.). Подпрограммы этого модуля позволяют манипулировать с такими строками, а также преобразовывать их в строки типа string, и наоборот. StrDispose — Удаление строки из динамической памяти StrCat Объединение двух строк;; StrComp Сравнение двух строк; StrEnd Получение указателя на конец строки ;StrLen Определение длины строки StrCopy Копирование строки в строку ; StrLCopy Копирование заданного числа символов ;StrECopy Копирование строки в строку с указанием конца новой строки; StrMove Копирование заданного числа символов StrLower Преобразование в строке прописных латинских букв в строчные StrUpper; StrNew Размещение строки в динамической области StrPas Преобразование ASCIIZ-строки в строку типа string StrPCopy; StrPos Поиск вхождения подстроки в строку; StrRScan Поиск последнего вхождения символа в строку 12 ВОПРОС Модуль Паскаля DOS . В модуле собраны процедуры и функции, открывающие доступ к средствам дисковой операционной системы MS — DOS . Процедуры управления вычислительным процессом Exec Intr Keep — Выполнение программы с параметрами из заданной командной строки Выполнение программного прерывания Прекращение выполнения программы и сохранение ее в памяти Функции управления вычислительным процессом UosExitCode — Получение кода выхода из выполняемого процесса, Процедуры работы с файлами FindFirst Поиск первого файла с заданными атрибутами в текущем или заданном каталоге работы с датой и временем GetDate GetFTime — Получение текущей даты, установленной в DOS, даты и времени последнего обновления файла Функции работы с файлами и диском DiskFree DiskSize Получение числа свободных байтов на диске Получение общего объема памяти диска Функции разнообразного назначения Dos Version Получение номера версии DOS 13 ВОПРОС.
Динамические структуры данных средства создания динамических структур данных, которые позволяют во время выполнения программы: -образовывать объекты; использование динамической памяти позволяет создавать структуры данных переменного размера. -выделять для них память; - если потребность в каких-то данных отпала до окончания программы, то занятую ими память можно освободить для другой информации - подключение динамической памяти позволяет увеличить объем обрабатываемых данных. Динамически распределяемый раздел памяти называется динамической памятью. Другое название динамической памяти — куча. Под кучей в случае Windows подразумевается вся виртуальная память вашего компьютера. Динамически распределяемую память следует использовать в случае если мы заранее не знаем сколько памяти нам понадобится (например, размер массива зависит от того, что введет пользователь во время работы программы) и при работе с большими объемами данных (например, массив из 1 000 000 int`ов не поместится на стеке). 14 ВОПРОС.
Работа с динамическими величинами связана с использованием еще одного типа данных — ссылочного типа. Величины, имеющие ссылочный тип, называют указателями. Указатель содержит адрес поля в динамической памяти, хранящего величину определенного типа. Указатели — это статические величины, поэтому они требуют описания. Адрес величины — это номер первого байта поля памяти, в котором располагается величина. Для обращения к ссылочной переменной используют запись " A^ ", что означает: "идти по адресу, хранящемуся в A". Память под указатели отводится на этапе компиляции. < указатель > := < ссылочное выражение >; В качестве ссылочного выражения можно использовать -указатель; -ссылочную функцию (т.е. функцию, значением которой является указатель); - Nil. это зарезервированная константа, обозначающая пустую ссылку, т.е. ссылку, которая ни на что не указывает. Константу Nil можно присваивать указателю с любым базовым типом. 1)Типизированные (пользовательский тип) указатели могут содержать адрес данных строго определенного типа. TYPE P=^< базовый тип > (любой тип паскаля) {помещается ^ перед индентификатором соответствующего типа} Plnt=^integer; Parr=^array[1..40] of integer; Var K:plnt; K-адрес целого числа 2) Указатель, не связанный с каким-либо конкретным типом данных, называется нетипизированным указателем. Для описания используется зарезервированное слово Pointer Имя-переменной: pointer; Var Q:pointer; - совместим со всеми пользовательскими типами SEG(P) вернет сегментную часть адреса, по которому располагается 4-байтный указатель Р, в то время как SEG(P^) - сегмент 6-байтного участка кучи, в котором хранится число 3.14. 15 ВОПРОС Динамические переменные — размещаются в памяти непосредственно в процессе работы программы. При динамическом размещении заранее неизвестны ни тип, ни количество размещаемых данных, к ним нельзя обращаться по именам, как к статическим переменным. Память под динамическую величину, связанную с указателем, выделяется в результате выполнения стандартной процедуры NEW(< указатель >); после выполнения этого оператора создана динамическая величина, имя которой имеет следующий вид: < имя динамической величины > := < указатель > NEW(P1); NEW(P2); NEW(Pm); После их выполненияP1^, P2^, Pm^ ; P1^ динамическая переменная, на которую ссылается указатель P1. Следует отчетливо понимать, что работа с динамическими данными замедляет выполнение программы, поскольку доступ к величине происходит в два шага: сначала ищется указатель, затем по нему — величина. Если динамическая величина теряет свой указатель, то она становится «мусором». В программировании под этим словом понимают информацию, которая занимает память, но уже не нужна. DISPOSE(< указатель >); Стандартная процедура, позволяющая освобождать память от данных, потребность в которых отпала. GetMem(P,Size) - резервирование памяти; FreeMem(P,Size) - освобождение памяти. Р — нетипизированный указатель, Size — размер в байтах требуемой или освобождаемой части кучи (до 65521 байт). Для работы с динамическими переменными в программе должны быть выполнены следующие действия: -Выделение памяти под динамическую переменную; -Инициализация указателя; -Освобождение памяти после использования динамической переменной. Альтернативой использованию функции Dispose является применение функций Mark и Release, которые совместно обеспечивают освобождение динамического участка памяти после его использования в программе. В действительности вызов функции Mark должен делаться до обращения к функции New, а вызов функции Release должен делаться после функции New, когда требуется перераспределить память. Функция Release освобождает все участки памяти, которые выделялись между вызовами функций Mark и Release. Динамическим считается массив, который способен в любой момент изменять свой размер. Массив указателей (МУ) - простейшая структура данных, в которой проявляется различие между физическим и логическим порядком следования элементов. Способ организации данных это массив, каждый элемент которого содержит указатель на переменную (объект). Sizeof — для определения размера необходимой памяти. Sizeof(q), где Q переменная или тип. memAvail — возвращает сумарный размер всех свободных областей динамической памяти. 53 Линейные списки Под списком мы будем понимать конечный упорядоченный набор объектов произвольных размера и природы. Связанные списки используются в двух основных случаях. если действительный размер списка неизвестен, то применяют связанный список. Связанный список позволяет быстро выполнять вставку и удаление элемента данных без реорганизации всего дискового файла. Однонаправленный линейный список — это список, который имеет указатель на начало списка, при этом каждый список имеет указатель на следующий список, а последний список принимает указатель NIL, что говорит о том, что он последний. модель списка при помощи определенной структуры данных, состоящей из динамических переменных. Каждый элемент списка представим записью, которая состоит из двух полей: -информационного поля или поля данных, которое в общем случае может содержать произвольное (фиксированное для данного типа элемента) количество полей разных типов; - ссылки на следующий элемент списка. Каждую такую пару будем называть звеном, а ссылки, содержащиеся в каждом из звеньев, будем использовать для соединения звеньев в цепочку. Такой способ представления упорядоченной последовательности элементов называется сцеплением. Каждая компонента списка определяется ключом. Обычно ключ — это либо число, либо строка символов. Ключ располагается в поле данных компоненты, он может занимать как отдельное поле записи, так и быть частью информационного поля записи. Над списками выполняются следующие операции: -начальное формирование списка (запись первой компоненты); -добавление компоненты в конец списка; -определение первого элемента в линейном списке; -чтение компоненты с заданным ключом; с заданным свойством; -вставка компоненты в заданное место списка (обычно до компоненты с заданным ключом или после неё); -исключение компоненты с заданным ключом из списка. —упорядочивание узлов линейного списка в определенном порядке. Для формирования списка и работы с ним необходимо иметь пять переменных типа указатель,первая из которых определяет начало списка pBegin, вторая — конец списка pEnd, остальные- вспомогательные, pCKey, pPreComp, pAux. Описание компоненты списка и переменных типа указатель дадим следующим образом: type PComp= ^Comp; Comp= record D:T; {Информационное поле} pNext:PComp {Ссылка на следующую компоненту} end; var pBegin, pEnd, pCKey, pPreComp, pAux: PComp; Однонаправленный кольцевой список — это список, который имеет указатель на начало списка, при этом каждый список имеет указатель на следующий список, а последний список имеет указатель на начало списка. Формирование списка. Просмотр списка Type T:^TElem; Q:R; TElem=record Q^.next:nil; Inf:< тип >;{ integer} Repeat Next:T; Q:=Q^.next; End; Until q=nil; Var R;Q:T; Q:=R; R:=nil; While Q< >nil do New(q); Q:=Q^.next; Q^.inf:=1; {формирование инф.ч} R:=Q; R- начало списка While < условие формирования списка > do Begin New(Q^.next); Q:=Q^.next;{формир. Инф.часть Q^.inf} End; 55. Другой специальный тип списка — очередь, где элементы вставляются с одного конца, а выборка — из другого конца. В программировании очереди применяются очень широко, например, при моделировании, буферизированном вводе-выводе или диспетчеризации задач в операционных системах. Для работы с очередью используются указатели на ее начало и конец, а также вспомогательный указатель. По отношению к очередям может использоваться специальная терминология, например, начало (front) и конец (rear) очереди. Объекты вставляются в конце очереди и проталкиваются по ней до тех пор, пока не достигнут начала очереди. 54 Стек — динамическая структура данных, представляющая из себя упорядоченный набор элементов, в которой добавление новых элементов и удаление существующих производится с одного конца, называемого вершиной стека. Элементы извлекаются из стека в порядке, обратном их добавлению в эту структуру, т.е. действует принцип «последний пришёл — первый ушёл». Детская пирамидка Выделим типовые операции над стеком и его элементами: -добавление элемента в стек; -удаление элемента из стека; -проверка, пуст ли стек; -просмотр элемента в вершине стека без удаления; -очистка стека. Размеров памяти стека можно управлять директивой $M (не превышает 64К) {$M < размер стека >,mind, MaxD} где < размер стека > от 1к до 664 к (по умолчанию 16 к) MinD —минимальный размер динамической памяти (носит ограничительный характер, устанавливает тот объем требуемой памяти при отсутствии которого программа вообще не может выполняться. Если mind=0, то запускается в любом случае). maxD- максимальный размер динамической памяти (носит рекомендательный характер. Занесение элемента в стек производится аналогично вставке нового элемента в начало списка. Процедура занесения элемента в стек должна содержать два параметра: первый задает вершину стека, в который нужно занести элемент, второй — заносимое значение элемента стека. Процедура формирования стека будет иметь следующий вид: Procedure FormStack; Var Stack : EXST; {Текущая переменная} Digit : integer; Procedure writeStack(Var u : EXST; Digit : integer); Var x : EXST; Begin new(x); {выделяем память под хранение нового элемента стека} x^.Data := Digit; {заполняем поле данных элемента} x^.Next := u; {новый элемент «связываем» со стеком} u := x; {созданный элемент определяем как вершину стека} End; Begin Stack := Nil; {инициализация стека} writeln('Введите элементы стека. Окончание ввода — 0'); read(Digit); while Digit < > 0 do begin writeStack(Stack, Digit); read(Digit); end; End; Извлечение элемента из стека В результате выполнения этой операции некоторой переменной i должно быть присвоено значение первого элемента стека, и значение указателя на начало списка должно быть перенесено на следующий элемент стека.Procedure readStack(Var u : EXST; Var i : integer); Var x : EXST; Begin i := u^.Data; {считываем значение поля данных в переменную} x := u; {запоминаем адрес вершины стека} u := u^.Next; {переносим вершину стека на следующий элемент} dispose(x); {освобождаем память, занятую уже ненужным элементом стека} End. 56 Двунаправленный список отличается двумя основными преимуществами. -список может просматриваться в обоих направлениях. Это не только упрощает сортировку списка, но также позволяет пользователям базы данных просматривать данные в обоих направлениях. -список при нарушении одной из связей может быть восстановлен по другой связи. Это свойство имеет смысл использовать при отказах оборудования, приводящих к нарушению списка. Построим модель двунаправленного списка. которая состоит из трех полей: 1) информационного поля или поля данных; 2) ссылки на следующий элемент списка; 3) ссылки на предыдущий элемент списка. Type PtrRec = ^Rec; Rec = record Element : TypeElement; {поле данных} pNext : PtrRec; {прямой указатель} pPrev : PtrRec; {