Програмски преведувач или компајлер (од англиски: compiler) е сметачки програм (или множество програми) кои го преведуваат текстот напишан во т.н.
сметачки јазик (изворен јазик) во друг сметачки јазик- целниот јазик. Оригиналниот текст којшто му го даваме на сметачот да го преведе се нарекува изворен код, додека излезниот код се нарекува објектен код. Обично излезот е во форма со која можат да се обработуваат други програми, но може да биде и форма читлива за човекот-текстуална податотека.
Најзначајна причина поради која би сакале да го преведеме изворниот код е да создадеме т.н. извршна програма. Името ’компајлер’ првично се користело за преведување на кодови од вишите програмски јазици во нижи програмски јазици, на пример од асемблерски јазик во машински јазик. Додека програмот којшто преведува од нижи програмски јазици во виши се нарекува декомпајлер.
Обично компајлерот ги изведува следниве активности: лексичка анализа, предобработка, расчленување, семантичка анализа, оптимизација на кодот, создавање на код.
Софтверот за првите сметачи се пишувал во асемблерски јазик многу години. Вишите програмски јазици не беа измислени сè додека не се доби поволноста тие да се користат на различни видови CPU (Централна Обработувачка Единица). Многу ограничената меморија на раните сметачи исто така правела многу техничкипрограми за имплементацијата на компајлерот.
На крајот на 50-тите години, први беа предложени машински-независните јазици. Тогаш се направени неколку експериментални компајлери. Првиот компајлер е напишан од Грејс Хопер, во 1952, за А-0 програмскиот јазик. FORTRAN тимот предводен од Џон Бакус (John Backus) во IBM е најголемиот виновник за претставувањето на првиот комплетен компајлер , во 1957 г.
За многу апликации идејата за користење виши програмски јазици беше прифатлива. Огромната функционалност поддржана од новите програмски јазици и зголемената комплексност на сметачки архитектури направи компајлерите да станат се послоложени.
Раните компајлери беа пишувани во асембли јазик. Првиот само-одржувачки компајлер- спосебен да искомпајлира сопствен изворен код од виш програмски јазик- беше создаден од Lisp од Харт и Левин во MIT во 1962 г. Од 70-тите години вообичаена практика беше да се имплементира компајлер во јазикот кој го компајлира , иако и Pascal и C беа популарни избори за имплементација на јазикот.
Еден метод кој се користи за разликување на компајлерите е платформата на која се генерира кодот кој ја создава извршната програма.
Хостиран компајлер е оној компајлер чиј излез е наменет да работи на истиот тип на сметач и оперативен систем на којшто работи самиот тој. Додека пак излезот на вкрстениот компајлер (cross compiler) е дизајниран да работи на различни платформи. Вкрстените компајлери често се употребуваат за градење на софтвер за вгнездени системи коишто не се наменети за поддржување на околина за развивање на софтвер.
Излезот на компајлерот којшто произведува код за Виртуелна Машина (ВМ) може но не мора да биде извршена на друга платформа.
Многу луѓе прават поделба меѓу вишите програмски јазици на компајлирачки јазици и толкувачки јазици. Компајлерите и интерпретерите се имплементации на јазици, но самите тие не претставуваат јазици. Категоризирањето обично се рефлектира на најпознатите и најраширените имплементации на јазикот, на пример за BASIC се мисли дека е толкувачки јазик, додека за С компајлирачки, и покрај постоењето на BASIC компајлери и С интерпретери.
Но постојат и исклучоци, некои спецификации на јазици кажуваат дека во имплементацијата мора да се вклучи функционалноста на компајлерот (Common Lisp) додека други јазици имаат делови кои можат многу лесно да се приспособат на интерпретер, но прават пишувањето на компајлер да биде многу тешко, за пример, SNOBOL4.
Излезот на компајлирањето мора да влијае на хардверот на многу ниско ниво, на пример Field Programmable Gate Array (FPGA). Тие компајлери се наречени хардвер компајлери бидејќи програмите коишто тие ги компајлираат делотворно ја контролираат финалната конфигурација на хардверот и како истата работи.
Пристапот кон создавање на еден компајлер зависи од комплексноста на обработката кое треба да се направи, искуството на лицето кое го дизајнира, и на достапноста на ресурсите.
Компајлер за релативно едноставен јазик напишан од некое лице може да биде многу едноставен софтвер. Но кога изворниот код е голем и комплексен и е потребен квалитетен излез тогаш дизајнот на компајлерот може да се подели во неколку фази или поминувања. Да се раздели работата во фази се мисли дека развојот може подели на мали делови и да се додели на различни лица да ги изработат. Исто така многу е полесно да се замени само еден дел со некоја негова подобрена верзија.
Поделбата на компајлирањето како процес беше предложено од Production Quality Compiler-Compiler Project на Carneige Mellon Универзитетот. Овој проект ги внесе термините “преден крај”,” среден крај”(кој ретко се користи) и “заден крај”.
Скоро сите помали компајлери имаат најмалку две фази. Но, овие фази обично се разгледуваат какодел од ” предниот” или “задниот крај”. Местото каде овие “краеви” се сретнуваат секогаш било отворено за дебата. “Предниот крај” генерално работи за синтаксичка и семантичка анализа, заедно со преведувањето во понизок јазик од изворниот код.
“Средниот крај” обично е наменет за оптимизација на друг вид на код различен од изворниот или машинскиот. “Задниот крај” го зема излезот на средниот крај, и потоа може да направи уште анализи, трансформации и оптимизации кои ќе ги направи за соодветниот сметач. Потоа генерира код за соодветниот процесор и оперативен систем.
Пристапот со разделување на компајлирањето во фази преден/среден/заден крај прави возможно комбинирањето на фазата на предниот крај за различни јазици со фазата-заден крај за различни CPU. Практичен пример за тоа GNU Compiler Collection и Amsterdam Compiler Kit.
Во фазата Преден крај се анализира изворниот код за да сеизгради интерна репрезентација на програмата, наречена Интермедиална Репрезрнтација или ИР . Исто така се работи со табелата на симболи којашто е податочна структура која секој симбол од изворниот код му ја придава информацијата како локација и тип. Тоа се прави во неколку фази, меѓу кои ги вклучува и следниве:
Терминот “Заден крај” често се поистоветува генератор на код поради делумната функционалност на генерирање на асемблерски код. Некои литератури ја користат “Средната фаза” за да ги означат фазите на анализа и оптимизација.
Главните процеси се:
Оптимизација- интермедиалната репрезентација на јазикот е трансформирана во некој функционален еквивалент но во побрзи (помали) форми.
Генерирање на код- трансформираниот јазик се преведува во излезен јазик, обично во соодветниот машински. Ова вклучува одлуки за ресурсите и меморијата, како што се која од променливите да се стави во некој од регистрите , потоа планирањето на меморија и селекцијата и распоредот на соодветните машински инструкции заедно со дадените адреси.
Постоењето на интерпроцедуралната анализа и оптимизација е вообичаена за компајлерите од IBM, SGI, Intel, Microsoft и Sun Microsystem.
Следнава програма презентира многу прост компајлер напишан во C. Овој компајлер компајлира изрази дефинирани со infix нотација во postfix нотација. Овој компајлер користи рекурзивна стратегија, која се препознава по тоа што секоја функција кореспондира со нетерминален симбол во јазичната граматика.
#include#include #include
#define MODE_POSTFIX 0 #define MODE_ASSEMBLY 1
char lookahead; int pos; int compile_mode; char expression[20+1];
void error() { printf("Syntax error!\n"); }
void match( char t ) { if( lookahead == t ) { pos++; lookahead = expression[pos]; } else error(); }
void digit() { switch( lookahead ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if( compile_mode == MODE_POSTFIX ) printf("%c", lookahead); else printf("\tPUSH %c\n", lookahead); match( lookahead ); break; default: error(); break; } }
void term() { digit(); while(1) { switch( lookahead ) { case '*': match('*'); digit(); printf( "%s", compile_mode == MODE_POSTFIX ? "*" : "\tPOP B\n\tPOP A\n\tMUL A, B\n\tPUSH A\n"); break; case '/': match('/'); digit();
printf( "%s", compile_mode == MODE_POSTFIX ? "/" : "\tPOP B\n\tPOP A\n\tDIV A, B\n\tPUSH A\n"); break; default: return; } } }
void expr() { term(); while(1) { switch( lookahead ) { case '+': match('+'); term(); printf( "%s", compile_mode == MODE_POSTFIX ? "+" : "\tPOP B\n\tPOP A\n\tADD A, B\n\tPUSH A\n"); break; case '-': match('-'); term();
printf( "%s", compile_mode == MODE_POSTFIX ? "-" : "\tPOP B\n\tPOP A\n\tSUB A, B\n\tPUSH A\n"); break; default: return; } } }
int main ( int argc, char** argv ) { printf("Please enter an infix-notated expression with single digits:\n\n\t"); scanf("%20s", expression); printf("\nCompiling to postfix-notated expression:\n\n\t"); compile_mode = MODE_POSTFIX; pos = 0; lookahead = *expression; expr(); printf("\n\nCompiling to assembly-notated machine code:\n\n"); compile_mode = MODE_ASSEMBLY; pos = 0; lookahead = *expression; expr();
return 0; }
Можен излез на програмата
Please enter an infix-notated expression with single digits:
3-4*2+2
Compiling to postfix-notated expression:
342*-2+
Compiling to assembly-notated machine code:
PUSH 3 PUSH 4 PUSH 2 POP B POP A MUL A, B PUSH A POP B POP A SUB A, B PUSH A PUSH 2 POP B POP A ADD A, B PUSH A
This article uses material from the Wikipedia Македонски article Програмски преведувач, which is released under the Creative Commons Attribution-ShareAlike 3.0 license ("CC BY-SA 3.0"); additional terms may apply (view authors). Содржината е достапна под CC BY-SA 4.0 освен ако не е поинаку наведено. Images, videos and audio are available under their respective licenses.
®Wikipedia is a registered trademark of the Wiki Foundation, Inc. Wiki Македонски (DUHOCTRUNGQUOC.VN) is an independent company and has no affiliation with Wiki Foundation.