Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

spz / spz

.pdf
Скачиваний:
33
Добавлен:
23.02.2016
Размер:
5.16 Mб
Скачать

6

У свою чергу, набір команд останнього виду включає стандартні команди і команди, створені користувачами системи.

Для того щоб виконуваний файл, розроблений користувачем ОС Unix, можна було запускати як команду shell, досить визначити в одному з вихідних файлів функцію з ім'ям main. Якщо ужити як ім'я команди ім'я такого виконуваного файлу, командний інтерпретатор створить новий процес і запустить у ньому зазначену виконувану програму, починаючи з виклику функції main.

Процеси

Процес в ОС Unix розуміється в класичному змісті цього терміна, тобто як програма, виконувана у власному віртуальному адресному просторі. Коли користувач входить у систему, автоматично створюється процес, у якому виконується програма командного інтерпретатора. Якщо командному інтерпретатору зустрічається команда, що відповідає виконуваному файлу, то він створює новий процес і запускає в ньому відповідну програму, починаючи з функції main. Ця запущена програма, у свою чергу, може створити процес і запустити в ньому іншу програму (вона теж повинна містити функцію main) і т.д.

Функціонування системи Unix . Виконання процесів

Тепер розглянемо найбільш характерні моменти функціонування цієї системи.

Процес може виконуватися в одному з двох станів, а саме користувальницькому і системному. У користувальницькому стані процес виконує користувальницьку програму і має доступ до користувальницького сегмента даних.

У системному стані процес виконує програми ядра і має доступ до системного сегмента даних.

Коли користувальницькому процесу потрібно виконати системну функцію, він створює системний виклик. Фактично відбувається виклик ядра системи як підпрограми. З моменту появи системного виклику процес вважається системним. Таким чином, користувальницький і системний процеси є двома фазами того самого процесу, але вони ніколи не перетинаються між собою.

Кожна фаза користується своїм власної стеком. Стек задачі містить аргументи, локальні змінні й іншу інформацію.

7

У Unix-системах використовується поділ часу, тобто кожному процесу виділяється квант часу. Або процес завершується сам до закінчення відведеного йому кванта часу, або він відкладається після закінчення кванта. Механізм диспетчеризації характеризується досить справедливим розподілом процесорного часу між усіма процесами. Користувальницьким процесам приписуються пріоритети в залежності від кількості одержуваного ними процесорного часу. Процесам, що одержали велику кількість процесорного часу, призначають більш низькі пріоритети, у той час як процесам, що одержали лише невелику кількість процесорного часу — навпаки, підвищують пріоритет. Такий метод диспетчеризації забезпечує гарний час реакції для всіх користувачів системи.

Будь-яке введення/виведення у Unix-системах трактується як введення з деякого файлу і виведення у деякий файл. Клавіатура й екран термінала теж інтерпретуються як файли (перший можна тільки читати, а в другий можна тільки писати).

Linux

Linux -Unix-подібна операційна система для персональних комп'ютерів і робочих станцій.

Як відомо, Linux — це вільно розповсюджувана версія Unix, що спочатку була розроблена Лінусом Торвальдсом в університеті Хельсінкі (Фінляндія). Усі компоненти системи, включаючи вихідні тексти, поширюються з ліцензією на вільне копіювання й установку для необмеженого числа користувачів.

Linux був створений за допомогою багатьох Unix-програмістів і ентузіастів з Інтернету. До даного проекту добровільно підключилися ті, хто має досить навичок і здібностей розвивати систему. Більшість програм Linux розроблено в рамках проекту в Кембріджі, Массачусетс. Але в нього внесли вклад також програмісти усього світу.

Спочатку Linux створювалася як «саморобна» Unix-подібна реалізація для ПК типу IВМ РС із процесором I80386. Однак Linux став настільки популярний і його нині підтримує таке велике число компаній, що в даний час є реалізація цієї ОС практично для всіх типів процесорів і комп'ютерів на їхній основі. На базі ОС Linux створюються й вбудовані системи, і суперкомп'ютери. Система підтримує більшість сучасних інтерфейсів і технологій.

Linux підтримує більшість властивостей, які притаманні іншим реалізаціям Unix, плюс ряд тих, яких більше ніде немає.

8

Linux — це повноцінна багатозадачна багатокористувальницька операційна система. Це означає, що одночасно багато користувачів можуть працювати на одній машині, одночасно виконуючи багато програм.

Linux добре сумісний з стандартами для Unix. Така сумісність враховувалася при його створенні. Більшість вільна розповсюджуваних по мережі Інтернет програм для Unix може бути відкомпільована для Linux практично без особливих змін. Крім того, усі вихідні тексти для Linux, включаючи ядро, драйвери пристроїв, бібліотеки, користувальницькі програми й інструментальні засоби поширюються вільно.

Linux підтримує різні типи файлових систем для збереження даних. Деякі файлові системи, такі як файлова система ехt2fs, були створені спеціально для Linux. Підтримуються також інші типи файлових систем, наприклад Мinix-1 і Хеnix. Реалізована також система керування файлами на основі FАТ, що дозволяє безпосередньо звертатися до файлів, що знаходяться в розділах з цією файловою системою. Підтримується і файлова система ISO 9660 СD-RОМ для роботи з дисками СD-RОМ. Є системи керування файлами і на томах із НРFS і NTFS, щоправда, вони працюють тільки на читання файлів. Створено варіанти системи керування файлами і для доступу до

FАТ32.

Linux забезпечує повний набір протоколів стека ТСР/IР для мережної роботи.

Ядро Linux підтримує завантаження тільки потрібних сторінок. Тобто з диска в пам'ять завантажуються ті сегменти програми, що дійсно використовуються. Можливе використання однієї сторінки, фізично один раз завантаженої в пам'ять, декількома виконуваними програмами, тобто реєнтерабельность коду збереглася.

Ядро також підтримує універсальний пул пул (роо1 — це сукупність однорідних, об'єктів, що динамічно розподіляються, наприклад, блоків пам'яті однакової довжини) пам'яті для користувальницьких програм і дискового кеша. При цьому для кешування може використовуватися уся вільна пам'ять, і навпаки, кеш зменшується при роботі великих програм.

Цей механізм агресивного кешeирования дозволяє збільшити продуктивність системи.

Виконувані програми використовують бібліотеки, що динамічно зв'язуються, тобто виконувані програми можуть спільно використовувати бібліотечну програму, представлену одним фізичним файлом на диску. Це дозволяє виконуваним файлам займати менше місця на диску, особливо тим, що багаторазово використовують бібліотечні функції. Є також статичні бібліотеки для тих, хто бажає користатися налагодженням на рівні об'єктних

9

чи кодів мати «повні» виконувані програми, що не мають потребу в поділюваних бібліотеках. У Linux поділювані бібліотеки динамічно зв'язуються під час виконання, дозволяючи програмісту заміняти бібліотечні модулі своїми власними.

1

Загальна схема роботи компіляторів

1.Визначення транслятора, компілятора, інтерпретатора.

2.Відмінність компілятора від транслятора.

3.Різниця між інтерпретаторами і трансляторами.

4.Етапи трансляції.

5.Загальна схема роботи транслятора.

6.Поняття проходу.

7.Багатопрохідні і однопрохідні компілятори.

Визначення транслятора, компілятора, інтерпретатора

Транслятор – це програма, що переводить вхідну програму на вихідній (вхідній) мові в еквівалентну їй вихідну програму на результуючій (вихідній) мові.

1.Транслятор є програмою — звичайно він входить до складу системного програмного забезпечення обчислювальної системи. Тобто транслятор — це частина програмного забезпечення (ПО), він являє собою набір машинних команд і даних і виконується комп'ютером, як і всі інші програми в рамках операційної системи (ОС). Усі складові частини транслятора являють собою фрагменти або модулі програми зі своїми вхідними і вихідними даними.

2.Вихідними даними для роботи транслятора служить текст вхідної програми — деяка послідовність речень вхідної мови програмування.

Звичайно це символьний файл, але цей файл повинний містити текст програми, що задовольняє синтаксичним і семантичним1 вимогам вхідної

мови. Крім того, цей файл несе в собі деякий зміст, обумовлений семантикою вхідної мови.

3.Вихідними даними транслятора є текст результуючої програми. Результуюча програма будується за синтаксичними правилами, заданим у вихідній мові транслятора, а її зміст визначається семантикою вихідної

мови. Важливою вимогою у визначенні транслятора є еквівалентність

1 Синтаксис мови — це набір правил, що визначає припустимі конструкції мови. Синтаксис визначає «форму мови» — задає набір ланцюжків символів, що належать мові. Найчастіше синтаксис мови можна задати у виді строгого набору правил, але цілком це твердження справедливе тільки для чисто формальних мов.

Семантика мови — це розділ мови, що визначає значення речень мови. Семантика визначає «зміст мови»

— задає значення для всіх припустимих ланцюжків мови. Семантика для більшості мов визначається неформальними методами (відносини між знаками і тим, що вони позначають, вивчаються семіотикою). Чисто формальні мови позбавлені якого-небудь змісту.

2

вхідної і вихідної програм. Еквівалентність двох програм означає збіг їхнього змісту з погляду семантики вхідної мови (для вихідної програми) і семантики вихідної мови (для результуючої програми). Без виконання цієї вимоги сам транслятор утрачає всякий практичний зміст.

Отже, щоб створити транслятор, необхідно насамперед вибрати вхідну і вихідну мови. З погляду перетворення речень вхідної мови в еквівалентні їм речення вихідної мови транслятор виступає як перекладач. Наприклад, трансляція програми з мови С на мову ассемблера по суті нічим не відрізняється від перекладу, скажемо, з російської мови на англійську, з тією тільки різницею, що складність мов трохи інша. Тому і саме слово «транслятор» означає «перекладач».

Результатом роботи транслятора буде результуюча програма, але тільки в тому випадку, якщо текст вихідної програми є правильним — не містить помилок з погляду синтаксису і семантики вхідної мови. Якщо вихідна програма неправильна (містить хоча б одну помилку), то результатом роботи транслятора буде повідомлення про помилку (як правило, з додатковими поясненнями і вказівкою місця помилки у вихідній програмі).

Визначення компілятора. Відмінність компілятора від транслятора

Крім поняття «транслятор» широко вживається також близьке йому за змістом поняття «компілятор».

Компілятор — це транслятор, що здійснює переклад вихідної програми в еквівалентну їй об'єктну програму мовою машинних команд або мовою ассемблера.

Таким чином, компілятор відрізняється від транслятора лише тим, що його результуюча програма завжди повинна бути написана мовою машинних кодів чи мовою ассемблера. Результуюча програма транслятора, у загальному випадку, може бути написана на будь-якій мові — можливий транслятор програм з мови Pascal на мову С. Відповідно, усякий компілятор є транслятором, але не навпаки — не всякий транслятор буде компілятором.

Наприклад, згаданий вище транслятор з мови Раscal на С компілятором бути не буде.

Саме слово «компілятор» походить від англійського терміна “compiler” («укладач», «компоновщик»). Термін зобов'язаний своєму походженню здатності компіляторів складати об'єктні програми на основі вихідних програм.

3

Результуюча програма компілятора називається «об'єктною програмою» чи «об'єктним кодом». Файл, у який вона записана, звичайно називається «об'єктним файлом». Навіть у тому випадку, коли результуюча програма породжується мовою машинних команд, між об'єктною програмою (об'єктним файлом) і програмою, що виконується, ( файлом, що виконується,) є істотна різниця. Породжена компілятором програма не може безпосередньо виконуватися на комп'ютері, тому що вона не прив'язана до конкретної області пам'яті, де повинні розташовуватися її код і дані .

Компілятори, безумовно, найпоширеніший вид трансляторів (багато хто вважають їхній узагалі єдиним видом трансляторів, хоча це не так). Вони мають саме широке практичне застосування, яким зобов'язані широкому поширенню всіляких мов програмування. Далі завжди будемо говорити про компілятори, припускаючи, що результуюча програма написана мовою машинних кодів або мові ассемблера.

Транслятори і компілятори, як і всі інші програми, розробляє людина або група розроблювачів. У принципі вони могли б створювати його безпосередньо мовою машинних команд, однак обсяг коду і даних сучасних компіляторів такий, що їх створення мовою машинних команд практично неможливо в розумний термін при розумних трудозатратах. Тому практично всі сучасні компілятори також створюються за допомогою компіляторів (звичайно в цій ролі виступають попередні версії компіляторів тієї ж фірми-виробника). І в цій якості компілятор є уже вихідною (выходящей) програмою для іншого компілятора, що нічим не краще і не гірше всіх інших породжуваних вихідних (выходящих) програм.

Визначення інтерпретатора. Різниця між інтерпретаторами і трансляторами

Крім схожих між собою понять «транслятор» і «компілятор» існує принципиально відмінне від них поняття інтерпретатора.

Інтерпретатор — це програма, що сприймає вхідну програму вихідною мовою і виконує її.

На відміну від трансляторів інтерпретатори не породжують результуючу програму (і взагалі якого-небудь результуючого коду) — і в цьому принципова різниця між ними.

Інтерпретатор, так само як і транслятор, аналізує текст вихідної програми. Однак він не породжує результуючої програми, а відразу ж виконує вихідну відповідно до її змісту, заданим семантикою вхідної мови. Таким чином, результатом роботи інтерпретатора буде результат, заданий змістом початкової програми, у тому випадку, якщо ця програма

4

правильна, або повідомлення про помилку, якщо початкова програма невірна.

Щоб виконати вихідну програму, інтерпретатор так чи інакше повинний перетворити її в мову машинних кодів, оскільки інакше виконання програм на комп'ютері неможливо. Він і робить це, однак отримані машинні коди є недоступними — їх не бачить користувач інтерпретатора. Ці машинні коди породжуються інтерпретатором, виповнюються і знищуються в міру потреби — так, як того вимагає конкретна реалізація інтерпретатора. Користувач же бачить результат виконання цих кодів — то результат виконання початкової програми.

Варто особливо згадати, що зараз у сучасних системах програмування стали з'являтися компілятори, у яких результуюча програма створюється не мовою машинних команд і не мовою ассемблера, а на деякій проміжній мові. Сама по собі ця проміжна мова не може безпосередньо виконуватися на комп'ютері, а вимагає спеціального проміжного інтерпретатора для виконання написаних на ньому програм. Хоча в даному випадку термін «транслятор» був би, напевно, більш правильним, у літературі вживається поняття «компілятор», оскільки проміжна мова є мовою дуже низького рівня, будучи родинною машинним командам і мовам ассемблера.

У першому поколінні компілятори писалися безпосередньо на машинних командах, але потом, з появою компіляторів, від цієї практики відійшли. Навіть самі відповідальні частини компіляторів створюються, як мінімум, із застосуванням мови ассемблера — а він теж обробляється компілятором.

Призначення трансляторів, компіляторів і інтерпретаторів. Приклади реалізації

Перші програми, що створювалися ще для ЕОМ першого покоління, писалися безпосередньо мовою машинних кодів. Це була пекельна робота.

З тих пір весь розвиток програмного забезпечення комп'ютерів нерозривно зв'язано з виникненням і розвитком компіляторів.

Першими компіляторами були компілятори з мов ассемблера або, як вони називалися, мнемокодів. Мнемокоди перетворили мову машинних команд у більш-менш доступну розумінню фахівця мову мнемонічних (переважно англомовних) позначень цих команд. Створювати програми стало значно, простіше, але виконувати сам мнемокод (мова ассемблера) жоден комп'ютер нездатний, відповідно, виникла необхідність у створенні компіляторів. Ці компілятори елементарно прості, але вони продовжують відігравати істотну роль у системах програмування донині.

Наступним етапом стало створення мов високого рівня. Мови високого рівня (до них відноситься більшість мов програмування) являють собою деяку проміжну ланку між чисто формальними мовами і мовами природного спілкування людей. Від перших їм дісталася формалізація синтаксичних структуру пропозицій мови, від других — значна частина

5

словникового запасу, семантика основних конструкцій і виразів (з елементами математичних операцій, що прийшли з алгебри).

Поява мов високого рівня істотно спростило процес програмування, хоча і не звело його до «рівня домогосподарки». Спочатку таких мов були одиниці, потім десятки, зараз, напевно, їх нараховується більш сотні. Процесу цьому не видно кінця. Проте як і раніше переважають комп'ютери традиційної, «неймановской»2, архітектури, що вміють розуміти тільки машинні команди, тому питання про створення компіляторів продовжує бути актуальним.

Як тільки виникла масова потреба в створенні компіляторів, стала розвиватися і спеціалізована теорія. Згодом вона знайшла практичне застосування у безлічі створених компіляторів. Компілятори створювалися і продовжують створюватися не тільки для нових, але і для давно відомих мов. Багато виробників від відомих, солідних фірм до мало кому знайомих колективів авторів випускають на ринок нові і більш нові зразки компіляторів.

Нині компілятори є невід'ємною частиною будь-якої обчислювальної системи. Без їхнього існування програмування будь-якої прикладної задачі було б утруднене, а те і просто неможливо. Та й програмування спеціалізованих системних задач, як правило, ведеться якщо не мовою високого рівня (у цій ролі в даний час найчастіше застосовується мова С), то мовою ассемблера, отже, застосовується відповідний компілятор.

Програмування безпосередньо на мовах машинних кодів відбувається винятково рідко і тільки для рішення дуже вузьких питань.

Компілятори, звичайно трохи простіші в реалізації, чим інтерпретатори. По ефективності вони також перевершують їх — очевидно, що відкомпільований код буде виконуватись завжди швидше, ніж відбувається інтерпретація аналогічної вихідної (исходной) програми. Крім того, не кожна мова програмування допускає побудову простого інтерпретатора. Однак інтерпретатори мають одну істотну перевагу — відкомпільований код завжди прив'язаний до архітектури обчислювальної системи, на яку він орієнтований, а вихідна (исходная) програма — тільки до семантики мови програмування, що набагато легше піддається стандартизації. Цей аспект спочатку не брали до уваги.

Першими компіляторами були компілятори з мнемокодів. Їхні нащадки — сучасні компілятори з мов ассемблера — існують практично для усіх відомих обчислювальних систем. Вони гранично жорстко

2 Неймановская архітектура. Джон фон Нейман, математик угорського походження, запропонував архітектуру з об'єднаною пам'яттю програм і даних. З тих пір це просте рішення широко застосовується в більшості комп'ютерів. Машина фон Неймана була створена в Принстонскому інституті новітніх досліджень у 1951 році. Вона містить три основних функціональних блоки – пам'ять, АЛУ і блок введення/виведення. Для виконання кожної операції АЛУ звертається по однієї і тій же лінії зв'язку спочатку до пам'яті програм, а потім до пам'яті даних. Пристрій уведення/виведення керує потоком зовнішніх даних. Мікроконтролери, в основному, мають архітектуру фон Неймана.

6

орієнтовані на архітектуру. Потім з'явилися компілятори з таких мов, як Fortran, Algol-68. Вони були орієнтовані на великі ЕОМ з пакетною обробкою задач. З перерахованих вище тільки Fortran продовжує використовуватися донині, оскільки має величезну кількість бібліотек різного призначення. Багато мов, народившись, так і не одержали широкого поширення — АDА, Моdula, Simula відомі лише вузькому колу фахівців. У той же час на ринку програмних систем домінують компілятори мов, яким не прочили світлого майбутнього. У першу чергу, зараз це С и С++. Перша з них народилася разом з операційними системами типу Unix, разом з нею завоювала своє «місце під сонцем», а потім перейшла під ОС інших типів. Друга втілила у собі приклад реалізації ідей об’ектно-орінтованого програмування. Ще можна згадати досить розповсюджений Раscal, що зненацька для багатьох вийшов за рамки чисто навчальної мови для університетського середовища.

Історія інтерпретаторів не настільки багата. Спочатку їм не віддавали істотного значення, оскільки майже по всіх параметрах вони уступають компіляторам. З відомих мов, що припускали інтерпретацію, можна згадати хіба що Ваsic.

Зараз ситуація змінилася, оскільки питання про переміщуваність програм і їх апаратно-платформної незалежності здобуває усе більшу актуальність з розвитком мережі Інтернет. Найвідоміший зараз приклад — це мова JаVа (сама по собі він сполучає компіляцію й інтерпретацію). Зрештою, мова НТМ, на якому ґрунтується протокол НТТР, що дав поштовх настільки бурхливому розвитку Всесвітньої мережі, — це теж интерпретуєма мова.

Вобласті появи нових інтерпретаторів усіх ще чекають сюрпризи, і з'явилися уже перші з них — наприклад, мова С# («сі-діез», але назва скрізь йде як «Си шарп»), яка анонсується фірмою Мicrosoft.

Етапи трансляції. Загальна схема роботи транслятора

На мал. 13.1 представлена загальна схема роботи компілятора. З неї видно, що в цілому процес компіляції складається з двох основних етапів

— синтезу й аналізу.

На етапі аналізу виконується розпізнавання тексту вихідної програми, створення і заповнення таблиць ідентифікаторів. Результатом його роботи служить деяке внутрішнє представлення програми, зрозуміле компілятору.

На етапі синтезу на підставі внутрішнього представлення програми й інформації, що міститься в таблиці (таблицях) ідентифікаторів,

Соседние файлы в папке spz