Upravljanje tokom

U računarstvu, **upravljanje tokom** predstavlja redosled po kome se naredbe, uputstva ili pozivi funkcija proveravaju ili izvršavaju. Eksplicitnim naglaskom na kontrolu toka se razlikuju imperativni programski jezici od deklarativnih programskih jezika.

U okviru imperativnog programskog jezika, naredba upravljanja tokom svojim izvršavanjem daje odgovor na pitanje kojim putem (ako postoje 2 ili više) treba nastaviti izvršavanje. Kod ne-striktnih programskih jezika, funkcijama i jezičkim konstrukcijama se dolazi do istog rezultata, ali se to ne zove nužno upravljanje tokom.

Vrste naredbi kontrole tokom koje podržavaju različiti jezici se razlikuju, ali se mogu podeliti po njihovom efektu:
* nastavak na drugoj naredbi(bezuslovno grananje ili skok),
* izvršavanje bloka naredbi samo ako je ispunjen određeni uslov (izbor, odnosno uslovna grana),
* izvršavanje sklopa naredbi nijednom ili više puta, dok se ne ispuni određeni uslov (npr. petlja - isto gao i uslovna grana),
* izvršavanje udaljenog kompleta naredbi, nakon kojeg se uglavnom tok upravljanja vraća (potprogrami, koprogrami i kontinuacije),
* zaustavljanje programa, sprečavajući dalji rad (bezuslovni zastoj).

Skup naredbi je zato generalno strukturiran kao blok, koji pored grupisanja definiše i leksički obim.

Prekidi i signali su mehanizmi niskog nivoa koji menjaju tok upravljanja na sličan način kao i potprogrami, ali se pre javljaju kao odgovor na neke eksterne stimuluse (koji mogu da se dese asinhrono), nego na „in-lajn* naredbe upravljanja tokom.

Na nivou [[Mašinski jezik|mašine]] ili [[Asembler|asemblerskog jezika]], instrukcije upravljanja tokom rade tako što menjaju [[IP (procesor)|programski registar]]. Za neke [[procesor]]e jedina uputstva za upravljanje tokom su uslovne ili bezuslovne naredbe za [[Grana (računarstvo)|grananje]] (skokovi).

== Primitive ==

=== Labele ===

Labela prestavlja ime ili broj eksplicitno dodeljen fiksnoj poziciji unutar izvornog koda, koji može biti pozvan naredbom upravljanja toka koja se nalazi na nekom drugom mestu unutar izvornog koda. Labela, osim što obeležava poziciju unutar izvornog koda, nema drugih funkcija.

Brojevi redova su zamena za labelu sa imenom (koji se koriste u nekim programskim jezicima kao što su [[Fortran]] i [[Bejsik]]), to su [[celi brojevi]] postavljeni na početak svakog reda teksta unutar izvornog koda. Programski jezici u kojima se ovo koristi često postavljaju uslov da broj svakog novog reda mora biti veći od broja iz prethodnog reda, ali ne mora nužno biti prvi uzastopni. Na primer, u Bejsiku:<syntaxhighlight lang="qbasic">
10 LET X = 3
20 PRINT X
</syntaxhighlight>U drugim jezicima kao što su C i Ada, labela je identifikator koji se obično pojavljuje na početku reda, praćen kolonom. Na primer, u programskom jeziku C:<syntaxhighlight lang="c">
Success: printf("The operation was successful.\n");
</syntaxhighlight>Programski jezik [[Algol 60]] je dozvoljavao kako cele brojeve tako i identifikatore kao labele (oba zakačena za kolonu sa određenom naredbom), ali samo nekoliko u slučaju da je neka druga varijanta Algola dozvoljavala cele brojeve.

=== Goto ===
*'goto **naredba (reč nastala spajanjem engleskih reči gou i tu) je najjednostavnija forma bezuslovnog prenosa upravljanja.

Iako [[ključna reč]] može biti sastavljena i od velikih i od malih slova u zavisnosti od programskog jezika, obično se zapisuje kao:
    **goto** ''label''
Cilj goutu naredbe je da izazove izvršavanje naredbe koja je data određenom labelom (ili sledi odmah nakon nje).

Goutu naredbe se [[Smatra se štetnim|smatraju štetnim]] od strane mnogih stručnjaka iz oblasti računarstva, među kojima je i [[Edsger Dajkstra]].

=== Potprogrami ===


Terminologija reči potprogram dosta varira; alternativni nazivi su rutine, procedure, funkcije (pogotovo ako vraćaju rezultate) ili metode (posebno ako pripadaju [[Klasa (računarstvo)|klasama]] ili [[Klasa tipa|klasama tipa]]).

Tokom pedesetih godina dvadesetog veka, memorije računara su bile veoma male u poređenju sa današnjim standardima, pa su potprogrami pre svega korišćene radi smanjivanja veličine programa; deo koda je bio jednom napisan a onda korišćen mnogo puta iz različitih delova programa.

U današnje vreme, potprogrami se češće koriste sa stvaranje programa koji ima obimniju strukturu, npr. izdvajanjem određenog algoritma ili sakrivanjem određene metode prsistupa podacima, potprogrami su jedan tip modularnosti koji pomaže da se skrati posao.

== Minimalno strukturirano upravljanje tokom ==
U maju 1966., Bom i Jakopini su objavili članak u časopisu ''Komunikacije ACM-a'' u kojem tvrde da bilo koji program sa **goutu**jem može da se preobrazi u program bez goutua koristeći samo izbor (IF THEN ELSE) i petlje (WHILE uslov DO xxx), moguće sa dupliranim kodom i/ili dodavanjem Bulovih varijabli (tačno/netačno). Kasnije su autori dokazali da izbor može biti zamenjen petljama (i još više Bulovih promenljivih).

Činjenica da je takav minimalizam moguć, ne znači i da je poželjan; uostalom, računarima je teoretski potrebna samo jedna mašinska instrukcija (oduzmi jedan broj od drugog i granaj ako je rezultat negativan), ali praktični računari imaju više desetina ili više stotina mašinskih instrukcija.

Bomov i Jakopinijev članak je pokazao da svi programi mogu biti bez goutu-a. Ostala istraživanja su pokazala da su kontrolne strukture sa po jednim ulazom i izlazom bile mnogo lakše za razumevanje nego bilo koja druga forma, najviše zbog toga što su mogle da se koriste svuda kao naredbe, bez remećenja upravljanja tokom. Drugim rečima, bile su ''kompozabilne. ''(Kasnija unapređenja, kao što su [[ne-striktni programski jezici]] - ili ranija, kompozabilne softverske transakcije - su pratile ovaj pravac mišljenja, što je činilo komponente programa još više kompozabilnim.)

Neki akademici su puristički pristupili rezultatima Boma i Jakopinija i započeli raspravu o tome da su čak i <code>break</code> i <code>return</code> naredbe koje se nalaze u petljama loše u praksi pošto uopšte nisu potrebne u navedenom dokazu, stoga su se zalagali da sve petlje treba da imaju samo jedan izlaz. Ovakav puristički pristup je osnova programskog jezika Paskal (dizajniranog 1968-1969), koji je do sredine devedesetih godina dvadesetog veka bio preferiran jezik za programere početnike na fakultetima. Direktna primena Bom-Jakopini teoreme može dovesti do pojave dodatnih lokalnih promenljivih u strukturiranom grafikonu, i takođe dovesti do [[ponavljanja u kodu]]. Potonji problem se naziva [[petlja i po]] u ovom kontekstu. Paskal je zahvaćen sa oba navedena problema i sudeći po empirijskim istraživanjima [[Erik S. Roberts|Erika S. Robertsa]], studenti su imali poteškoća sa formulacijom tačnih rešenja za nekolicinu prostih problema, uključujući pisanje funkcije koja traži element u nizu. U istraživanju Henrija Šapira iz 1980. navedenog od strane Robertsa, stoji podatak da koristeći samo kontrolne strukture koje nudi Paskal, samo 20% subjekata je dalo tačan odgovor, dok nijedan subjekat nije napisao pogrešan kod za rešenje problema ako mu je bilo dozvoljeno da napiše return naredbu u telu petlje.

== Kontrolne strukture u praksi ==
Većina programskih jezika koji sadrže kontrolne strukture poseduju i inicijalnu ključnu reč koja kazuje koji tip kontrolne strukture je sadržan. Jezici se tada dele na one čije kontrolne strukture imaju odnosno nemaju finalnu ključnu reč.

* Bez finalne ključne reči: [[Algol|Algol 60]], [[C (programski jezik)|C]], [[C++]], [[Haskel (programski jezik)|Haskel]], [[Java (programski jezik)|Java]], [[Paskal (programski jezik)|Paskal]], [[Perl (programski jezik)|Perl]], [[PHP]], [[PL/I]], [[Pajton]], [[PauerŠel]]. Ovakvim jezicima je potreban neki način grupisanja izjava:
** Algol 60 i Paskal : <code>begin</code> ... <code>end</code>
** C, C++, Java, Perl, PHP i PauerŠel: vitičaste zagrade <code>{</code> ... <code>}</code>
** PL/1: <code>DO</code> ... <code>END</code>
** Pajton: koristi nivo uvlačenja (vidi pravilo [[sa-strane]])
** Haskel: mogu se koristiti i metod uvlačenja i vitičaste zagrade, uz slobodu da se mešaju
* Finalne ključne reči: [[Ada (programski jezik)|Ada]], [[Algol 68]], [[Modula-2]], [[Fortran]] 77, [[Mitril]], [[Vižual bejsik]]. Forme finalnih ključnih reči:
** Ada: Finalna ključna reč je <code>end</code> + ''spejs'' + inicijalna ključna reč npr. <code>if</code> ... <code>end if</code>, <code>loop</code> ... <code>end loop</code>
** Algol 68, Mitril: inicijalna ključna reč pisana otpozadi npr. <code>if</code> ... <code>fi</code>, <code>case</code> ... <code>esac</code>
** Fortran 77: finalna ključna reč je <code>end</code> + inicijalna ključna reč npr. <code>IF</code> ... <code>ENDIF</code>, <code>DO</code> ... <code>ENDDO</code>
** Modula-2: ista finalna ključna reč <code>END</code> za sve
** Vižual bejsik: svaka kontrolna struktura ima svoju ključnu reč. <code>If</code> ... <code>End If</code>; <code>For</code> ... <code>Next</code>; <code>Do</code> ... <code>Loop</code>; <code>While</code> ... <code>Wend</code>

== Izbor ==

=== If-then-(else) naredbe ===
Uslovni izrazi i uslovne konstrukcije su odlike [[Programski jezik|programskog jezika]] koji izvršava različite operacije u zavisnosti da li Bulov ''uslov ''vraća true ili false.

* <code>IF.</code><code>.</code><code>GOTO</code>. Forma koja se sreće u nestrukturiranim programskim jezicima koja imitira običnu instrukciju mašinskog koda, bi trebalo da skoči (GOTO) do oznake ili linijskog broja kada se uslov ispuni.
* <code>IF.</code><code>.THEN..</code><code>(ENDIF)</code>. Umesto da budu ograničene na skok, bilo koja prosta naredba ili ugnežđeni bi mogli da prate THEN ključnu reč. Ovo je strukturirana forma.
* <code>IF.</code><code>.THEN..ELSE..</code><code>(ENDIF)</code>. Kao gorenavedeno, ali preduzimajući drugu radnju ukoliko je uslov false. Ovo je jedna od najzastupljenijih formi, sa mnogo varijacija. Neke zahtevaju završno <code>ENDIF</code>, neke ne. [[C (programski jezik)|C]] i slični jezici ne zahtevaju završnu ključnu reč, ili 'then', ali zahtevaju zagrade oko uslova.
* Uslovne naredbe su često ugnežđene unutar uslovnih naredbi. Neki jezici dozvoljavaju <code>ELSE</code> i <code>IF</code> da se kombinuju u <code>ELSEIF</code>, izbegavajući potrebuza većim brojem <code>ENDIF</code> ili ostalih finalnih naredbi na kraju složene naredbe.

Manje poznate varijacije uključuju:-
* Neki jezici, kao što je [[Fortran]], imaju "trostruko" ili "[[aritmetičko if]]", testiranje, koje proverava da li je numerička vrednost pozitivna, negativna ili nula..
* Neki jezici poseduju [[funkcionalnu]] formu "if" naredbe, na primer [[Lisp]]ov <code>cond</code>.
* Neki jezici poseduju operatorsku formu "if" naredbe, kao na primer trojni operator u jeziku C.
* Perl pruža <code>if</code> sa <code>when</code> i <code>unless po uzuru na C</code>.
* [[Smalltalk]] koristi <code>ifTrue</code> i <code>ifFalse</code> poruke za implementaciju kondicionala, radije nego neke osnovne jezičke konstrukcije.

=== Naredbe zamene i predmeta ===
[[Naredbe zamene]] (ili naredbe predmeta, ili višestruke grane) porede zadatu vrednost sa određenim konstantama i započinju izvršavanje u zavisnosti od prve konstante sa kojom se poklope. Obično postoji ograničen broj uobičajenih akcija ("else", "otherwise") koje se preduzimaju ako se nijedno poklapanje ne dogodi. Naredbe zamene dozvoljavaju optimizaciju kompajlera, kao što su [[Lukap tabela|lukap tabele]]. U [[dinamičkim jezicima]], predmeti ne moraju biti ograničeni konstantnim izrazima, i moguće je da se produže do [[poklapanja šablona]], kao u primeru [[šel skripte]] sa desne strane, gde <code>*)</code> implementira uobičajeni slučaj kao glob koji se poklapa sa bilo kojim stringom. Logika slučaja se takođe može implementirati u funkcionalnu formu, kao u [[SQL]]-ovoj <code>decode</code> naredbi.



== Petlje ==
Petlja predstavlja niz naredbi koji se definiše jednom ali se može izvršite više puta uzastopno. Kod "unutar" petlje (''telo'' petlje, ispod prikazano kao ''hhh'') se izvršava određen broj puta, ili jedanput za kolekciju stavki, ili dok se ne ispuni određeni uslov, ili [[Beskonačna petlja|neograničeno mogo puta]].

U [[Funkcionalno programiranje|funkcionalnim programskim jezicima]], kao što su [[Haskel (programski jezik)|Haskel]] i [[Scheme (programski jezik)|Scheme]], petlje se mogu iskazati pomoću [[Rekurzija|rekurzije]] ili [[iteracije sa zadatom tačkom]] bolje nego eksplicitnim konstrukcijama petlje. [[Repna rekurzija]] predstavlja specijalni slučaj rekurzije koja se lako može pretvoriti u iteraciju.

=== Petlje kontrolisane brojanjem ===

Većina programskih jezika poseduje konstrukcije za ponavljanje petlje određen broj puta. Treba zapaziti da, ako je N manje od 1 u ovim slučajevima, onda jezik zapravo specifikuje da telo treba potpuno preskočiti, ili izvršiti jedanput ako je N=1. U većini slučajeva, brojanje je moguće i unazad, a ne mora ni biti uzastopno.
    FOR I = 1 TO N           | **for** I := 1 **to** N **do** **begin**
        xxx                  |     xxx
    NEXT I                   | **end**;
 ------------------------------------------------------------
    DO I = 1,N               | **for** ( I=1; I<=N; ++I ) {
        xxx                  |     xxx
    END DO                   | }
U velikom broju programskih jezika, samo se intidžeri mogu pouzdano koristiti za petlju koja je kontrolisana brojačem. Flouting-point brojevi nisu precizno predstavljeni zbog ograničenja hardvera, tako da petlja npr.:
    **for** X := 0.1 **step** 0.1 **to** 1.0 **do**
možda može biti ponovljena 9 ili 10 puta, u zavisnosti od grešaka sa saokruživanjem brojeva i/ili hardvera i/ili verzije kompajlera. Osim toga, ako se povećanje H-a dogodi puetm ponovljenjog sabiranja, nagomilane greške u zaokruživanju značiti da se vrednost H u svakoj iteraciji može dosta razlikovati od očekivanog niza 0.1, 0.2, 0.3, ..., 1-0.

=== Uslovno-kontrolisane petlje ===

Većina programskih jezika poseduje strukture za ponavljanje petlje sve dok se neki uslov ne promeni. Treba napomenuti da je kod nekih varijacija provera na početku, a kod nekih na kraju petlje. U slučaju da je provera pre petlje, telo petlje se može u potpunosti preskočiti, ali ako se nalazi posle tela petlje, petlja se mora izvršiti bar jedanput.
    DO WHILE (test)          | **repeat** 
        xxx                  |     xxx 
    LOOP                     | **until** test;
 ----------------------------------------------
    **while** (test) {           | **do**
        xxx                  |     xxx
    }                        | **while** (test);
[[Prekid kontrole]] je metoda detekcije promene vrednosti koja se koristi u običnim petljama za započinjanje obrade grupe promenljivih. Ključna promenljiva vrednost ili vrednosti se nadgledaju unutar petlje a njihova promena menja tok rada programa u zavisnosti od zadatih naredbi koje zavise od tih promenljivih vrednosti.
    DO UNTIL (End-of-File)
       IF new-zipcode <> current-zipcode
          display_tally(current-zipcode, zipcount)
          
          current-zipcode = new-zipcode
          zipcount = 0
       ENDIF
       
       zipcount++
    LOOP

=== Petlje kontrolisane kolekcijom ===

Nekolicina programskih jezika (npr. [[Ada (programski jezik)|Ada]], [[D (programski jezik)|D]], [[Smalltalk]], [[PHP]], [[Perl (programski jezik)|Perl]], [[Objektni Paskal]], [[Java (programski jezik)|Java]], [[C Sharp|C#]], [[MATLAB|Matlab]], [[Mitril]], [[Vižual Bejsik]], [[Rubi (programski jezik)|Rubi]], [[Pajton]], [[Javaskript]], [[Fortran|Fortran 95]] i kasniji) poseduju specijalne strukture koje dozvoljavaju ponavljanje petlje kroz sve elemente niza, ili sve članove kompleta ili kolekcije.
    nekaKolekcija **do**: [:svakiElement |xxx].

    **for** Predmet **in** Kolekcija **do** **begin** xxx **end**;
 
    **foreach** (predmet; mojaKolekcija) { xxx }
 
    **foreach** nekiNiz { xxx }
 
    **foreach** ($nekiNiz as $k => $v) { xxx }
 
    Kolekcija<Niska> coll; **for** (Niska s : coll) {}
 
    **foreach** (**niska** s **in** mojaNiskaKolekcija) { xxx }
 
    $nekaKolekcija | ZaSvaki-Objekat { $_ }

    **forall** ( index = first:last:step... )
[[Skala]] ima for-naredbe, koje generalizuju petlje kontrolisane kolekcijama, i pomažu druge radnje, kao što je [[paralelna obrada]]. Haskel ima do-naredbe, koje pružaju sličnu funkcionalnost kao i for-izraza u Skali.

=== Opšta iteracija ===
Strukture generalne iteracije, kao što je **for**-naredba u C-u i **do** forma u [[Common Lisp]]-u, se mogu iskoristiti za izražavanje bilo koje od gore navedenih petlji, kao i ostalih—npr. petljanje preko niza zbirki paralelno. Tamo gde se može primeniti konkretnija struktura petlje, ona je prioritetnija od obične iterativne strukture, pošto čini svrhu izraza jasnijom.

=== Beskonačne petlje ===
[[Beskonačna petlja|Beskonačne petlje]] se koriste da osiguraju da deo programa prolazi kroz petlju zauvek ili dok se ne pojavi izuzetan uslov, kao što je greška. Na primer, program koji radi na principu događaja (kao što je [[server]]) bi trebalo da se nalazi u beskonačnoj petlji, obrađujući u momentu kad se dogode , zaustavljajući se samo u slučaju kada se proces prekine od strane operatora.

Beskonačne petlje mogu biti realizovane korišćenjem drugih konstrukcija za kontrolu toka. Najčešće, kod nestrukturiranog programiranja ovo je skok unazad (goto), dok je u strukturiranom programiranju ovo beskonačna petlja (while petlja) podešena da se nikada ne završi, tako što se uslov izostavi ili jednostavno postavljanje istog uslova na True, kao <code>while (true) .</code><code>..</code>. Neki jezici poseduju specijalne konstrukcije za beskonačne petlje, obično je to izostavljanje uslova iz beskonačne petlje. Neki od pomenutih jezika su Ada (<code>loop ... end loop</code>), Fotran (<code>DO .</code><code>.. </code><code>END DO</code>), Gou (<code>for { ... }</code>), i Rubi (<code>loop do ... end</code>).

Često se dešava da se beskonačna petlja stvori kao posledica greške u uslovno-kontrolisanoj petlji, gde petlja koristi promenljive koje se u stvari nikada ne menjaju unutar te same petlje.

=== Kontinuacija sa narednom iteracijom ===
Ponekad u telu petlje postoji potreba da se preskoči ostatak petlje i da se nastavi sa sledećom iteracijom petlje. U nekim jezicima postoji naredba kao što je <code>continue</code> (većina jezika), <code>skip</code>, ili <code>next</code> (Perl i Rubi), koja će to učiniti. Cilj je da se eliminiše izvršenje tela petlje koja se nalazi u sredini koda i da se nastavi sa normalnim izvršavanjem sledeće iteracije. Ako je iteracija na poslednjem mestu u petlji, cilj je da se rano eliminiše čitava petlja.

=== Ponavljanje trenutne iteracije ===
Neki jezici, poput Perla i Rubija, poseduju <code>redo</code> naredbu koja započinje trenutnu iteraciju od početka.

=== Ponovno pokretanje petlje ===
Rubi poseduje <code>retry</code> naredbu koja pokreće celu petlju ispočetka, od prve iteracije.

=== Rani izlazak iz petlje ===
Pri korišćenju petlje kontrolisane brojanjem za pretragu tabele, poželjno je da se pretraga obustavi u momentu kada se željena stavka pronađe. Neki programski jezici poseduju naredbu kao što je <code>break</code> (većina jezika), <code>exit</code>, ili <code>last</code> (Perl), čiji je cilj da odmah prekine petlju i prebaci upravljanje na naredbu koja direktno sledi nakon petlje.

Naredni primer je prikazan u jeziku [[Ada (programski jezik)|Ada]] koji podržava i ''rani izlaz iz petlje'' i ''[[petlje sa proverom u sredini]]''. Obe odlike su veoma slične i samo poređenjem isečaka iz oba koda može se videti razlika: ''rani izlaz'' zahteva da stoji u kombinaciji sa **if **naredbom, dok je ''provera u sredini'' samostalna konstrukcija.<syntaxhighlight lang="ada">
with Ada.Text IO;
with Ada.Integer Text IO;

procedure Štampaj_Kvadrate is 
    X : Integer;
begin
    Read_Data : loop
        Ada.Integer Text IO.Get(X);
    exit Read_Data when X = 0;
        Ada.Text IO.Put (X * X);
        Ada.Text IO.New_Line;
    end loop Read_Data;
end Štampaj_Kvadrate;
</syntaxhighlight>[[Pajton]] podržava uslovno izvršavanje koda u zavisnosti od toga da li je se rano izašlo iz petlje (sa <code>break</code> naredbom), ili nije - koristeći se else-klauzulom sa petljom. Na primer,<syntaxhighlight lang="python">
for n in niz_brojeva:
    if prost_broj(n):
        print "Niz sadrži prost broj"
        break
else:
    print "Niz ne sadrži prost broj"
</syntaxhighlight>Treba zapaziti da je <code>else</code> klauzula u gorenavedenom primeru zakačena za <code>for</code> naredbu, a ne unutrašnju <code>if</code> naredbu. Obe petlje u Pajtonu,  <code>for</code> i <code>while</code> , podržavaju else klauzulu, koja se izvršava samo u slučaju da se rani izlazak iz petlje nije dogodio.

Neki jezici podržavaju prekidanje iz ugnežđenih petlji; u teorijskim krugovima, to se zove izbijanje sa više nivoa. Tipična primena ovog principa je pretraživanje višedimenzionalnih tabela. Ovo se može uraditi pomoću prekidanja sa više nivoa (prekidanje sa ''N'' nivoa), kao u bash-u i PHP-u, ili putem označenih prekida (izbij i nastavi kod date oznake), kao u Javi i Perlu. Alternative za prekide sa više nivoa uključuju jednostruke prekide, zajedno sa neredbenim promenljivama koji se koriste za prekid još jednom nivou; izuzeci, koji se nalaze na nivou na koji se prekida; stavljanje ugnežđene petlje u funkciju i korišćenje return naredbe za izazivanje prekida čitave ugnežđene petlje; ili korišćenje oznake i goto iskaza. C ne podržava prekid sa više nivoa, i uobičajena alternativa je korišćenje goto naredbe za implementaciju označenog prekida. Pajton ne poseduje prekid sa više nivoa niti nastavak – ovo je predloženo u [https://www.python.org/dev/peps/pep-3136/ PEP 3136], ali je odbačeno na osnovu toga što dodatna kompleksnost nije bila vredna legitimne.

Pojam prekida sa više nivoa nekim delom bitna za [[teorijsko računarstvo]], jer dovodi do nečega što se danas naziva the '',, kosaradžu hijerarhija**' Godine 1973. S. Rao Kosaradžu je preradio teoremu strukturiranih programa tako što je dokazao da je moguće da se izbegne dodavanje dodatnih promenljivih u strukturiranom programiranju, dok kod su proizvoljno-duboki prekidi sa više nivoa dozvoljeni u petlji. Štaviše, Kosaradžu je dokazao da postoji stroga hijerarhija programa: za svaki intedžer *n* postoji program koji sadrži prekid sa više nivoa dubine *n* koji se ne može preraditi kao program sa prekidima sa više nivoa dubine manje od *n* bez uvođenja dodatnih promenljivih.

Takođe se može koristiti `return` naredba u potprogramu koja izvršava naredbe u petlji, vršeći time prekid kako ugnežđene petlje, tako i potprograma. There are other proposed control structures for multiple breaks, but these are generally implemented as exceptions instead.

U svom udžbeniku iz 2004., Dejvid Vat koristi Tenentov pojam of sekvencera za objašnjenje sličnosti prekida sa više nivoa sa return naredbama. Vat napominje da klasa sekvencera poznatih kao *izlazni sekvenceri*, definisanih kao "sekvencer koji prekida izvršavanje komande ili procedure koja prima tekst", obuhvata kako prekide petlji (uključujući prekide sa više nivoa) i return naredbe. Međutim, iako se često implementira, return sekvenceri takođe mogu nositi (return) vrednost, dok the break sekvencer implementiran u savremenim jezicima obično ne može.

### Varijante i invarijante petlji
Varijante petlji i invarijante petlji se koriste za izražavanje ispravnosti petlji.

U praksi, varijanta petlje je ceo izraz koji ima početnu ne-negativnu vrednost. Vrednost varijante se mora smanjitivati tokom svake iteracije petlje, ali nikad ne sme postati negativna tokom pravilnog izvršavanja petlje. Varijante petlje se koriste da zagarantuju okončanje petlje.

Invarijanta petlje je tvrdnja koja mora biti tačna pre prve iteracije u petlji i ostati tačna posle svake iteracije. Ovo podrazumeva da kada se petljanje ispravno okonča, i izlazni uslov i invarijanta petlje moraju biti zadovoljeni. Invarijante petlje se koriste za praćenje određenih svojstava petlje tokom uzastopnih iteracija.

Neki programski jezici, poput Ajfela sadrže ugrađenu podršku za varijante i invarijante petlji. U ostalim slučajevima podrška je dodatak, kao što je specifikacija Java jezika za modeliranje za naredbe u petlji u Javi.

## Podjezik petlje
Neki Lisp dijalekti pružaju bogat podjezik za opisivanje petlji. Rani primer se može naći u Konverzionalnom Lisp-u Interlispa. Common Lisp  pruža makro za petlje koji implementira takav podjezik.

## Tabela sistema koji upravljaju petljama

#  `while (true)` se ne računa kao beskonačna petlja u ovu svrhu, jer nije prava jezička struktura.
#  C-ova `for (''init''; ''test''; ''increment'')` petlja je generalna konstrukcija petlje, ali ne nužno brojeća, iako je često korišćena u tu svrhu.
#  Duboki prekidi se mogu ostvariti u jezicima C, C++ i C# korišćenjem oznaka i goto-a.
#  Iteracija nad objektima je dodata u PHP 5.
#  Petlja sa brojanjem se može imitirati iteracijom nad an listom koja se povećava ili generatorom, na primer Pajtonova `range()` naredba.
#  Duboki prekidi se mogu ostvariti pomoću upravljanja izuzecima.
#  Ne postoji specijalna konstrukcija, pošto se `while` funkcija može koristiti u ovu svrhu.
#  Ne postoji specijalna konstrukcija, ali korisnici mogu definisati obične funkcije petlje.
#  Nacrt C++11 je uveo for funkciju na osnovu niza. U STL postoji `std::for_each` šablon koji može vršiti iteracije nad STL kolekcijama i pozvati unarnu funkciju za svaki element. Funkcionalnost se takođe može konstruisati kao macro nad ovim kolekcijama.
#  Petljanje kontrolisano brojanjem je pod uticajem iteracije kroz interval celih brojeva; rani izlaz iz petlje uključujući dodatni uslov za izlaz.
#  Ajfel podržava rezervisanu reč `retry`, ali se ona koristi u upravljanju izuzecima, a ne kontroli petlje.
#  Zahteva Java Jezik za Modelovanje (JML).
#  Zahteva da varijante petlje budu celi brojevi; transfinit varijante nisu podržane. http://archive.eiffel.com/doc/faq/variant.html
#  D podržava beskonačne kolekcije, i mogućnost iteracije nad tim kolekcijama. Ovo ne zahteva nikakvu specijalnu konstrukciju.
#  Duboki prekidi se mogu ostvariti korišćenjem `GO TO` i procedura.
#  Common Lisp prethodi konceptu generičkog tipa kolekcija.

## Strukturirano vanlokalno upravljanje tokom
Mnogi programski jezici, posebno oni u kojima se praktikuje dinamičan stil programiranja, nude konstrukcije za **vanlokalno upravljanje tokom**. One dovode do toga da tok izvršavanja iskoči iz datog konteksta i nastavi se u nekoj određenoj tački. *[[Izuzetak (programiranje)|Uslovi]]*, *[[Izuzetak (programiranje)|izuzeci]]* i *[[kontinuacije]]* su tri opšte vrste vanlokalnih kontrolnih konstrukcija; postoje i kompleksnije vrste, kao što su generatori, koprogrami i ključna reč async.

### Uslovi
PL/I poseduje 22 standardna uslova (npr. ZERODIVIDE SUBSCRIPTRANGE ENDFILE) koji se mogu podići i presresti putem: ON *uslovnom* akcijom; Programeri takođe mogu definisati i koristiti svoje imenovane uslove.

Poput *nestrukturiranog if*, samo jedna naredba može biti određena tako da je u mnoštvu slučajeva GOTO potreban za odluku kuda se upravljanje tokom treba nastaviti.

Nažalost, neke implementacije su imale značajan overhead kako sa prostorom tako i sa vremenom (posebno SUBSCRIPTRANGE), tako da su mnogi programeri pokušavali da ih zaobiđu korišćenjem uslova.

Prosti primeri sintakse:
  **ON** *uslov* **GOTO** *oznaka*

### Izuzeci

Savremeni jezici have poseduju specijalizovane strukturirane konstrukcije za upravljanje izuzecima koje se ne oslanja na korišćenje naredbe `GOTO` ili break (sa više nivoa) ili return naredbama. Na primer, u jeziku C++ može se napisati:
```cpp
try {
    xxx1                                  // Negde unutar ovoga
    xxx2                                  //     use: '''throw''' someValue;
    xxx3
} catch (nekaKlasa& someId) { // uhvati vrednost od nekaKlasa
    actionForSomeClass 
} catch (nekiTip& anotherId) { // uhvati vrednost od nekiTip
    actionForSomeType
} catch (...) { // uhvati bilo šta što još nije uhvaćeno
    actionForAnythingElse
}
```
Bilo koji broj i varijetet `catch` klauzula se može koristiti u gorenavedenom primeru. Ako ne postoji `catch` koji se podudara sa određenim `throw`, kontrola se vraća nazad kroz pozive potprograma i/ili ugnežđene blokove dok se ne pronađe `catch` koji se poklapa ili dok se ne dostigne kraj glavnog programa, u tom slučaju se program nasilno gasi sa odgovarajućim obaveštenjem o grešci.

Zahvaljujući uticaju jezika C++, `catch` je ključna reč rezervisana za deklaraciju upravljača izuzetaka koji radi na principu prepoznavanja šablona u ostalim, danas popularnim, jezicima, kao što su Java ili C#. Neki drugi jezici kao što je Ada koriste ključnu reč `exception` za uvođenje upravljača izuzecima i možda upotrebe drugu ključnu reč (`when` u jeziku Ada) za poklapanje šablona. Nekoliko jezika poput EplSkripta uvode plejsholdere u sintaksu upravljača izuzecima za automatsko vađenje nekoliko delova informacija kada se izuzetak dogodi. Ovaj pristup je dat u primeru ispod kosriteći `on error` konstrukciju u EplSkriptu:
```applescript
try
    set mojBroj to mojBroj / 0
on error e number n from f to t partial result pr
    if ( e = "Nemoguće deliti nulom" ) then display dialog "Ne smete to raditi"
end try
```
U udžbeniku Davida Vata iz 2004 godine se takođe analizira upravljanje izuzecima u okviru sekvencera (o ovome više piše u ovom članku, u odeljku o ranim izlazima iz petlji.) Vat ističe da abnormalna situacija, kao na primer aritmetičko prelivanje ili input/output kvara kao što je ,, datoteka nije pronađena“, je poput greške koja "se detektuje u nekoj jedinici programa na niskom nivou, ali [za koju] se upravljač u većini slučajeva nalazi u programskoj jedinici visokog nivoa". Na primer, program može da sadrži više poziva za čitanje datoteka, ali radnja koja treba da se izvrši u slučaju da datoteka nije pronađena zavisi od značenja (svrhe) te datoteke za program i zato se rutina za upravljanje ovom abnormalnom situacijom ne može naći u sistemskom kodu niskog nivoa. Kasnije Vat navodi da uvođenje testiranja statusnih oznaka u pozivaocu, kako bi se to zahtevalo u jednoizlaznom strukturiranom programiranju ili čak (višeizlaznom) povratnom sekvenceru, rezultuje u tome da "aplikacijski kod obično biva pretrpan testovima statusnih oznaka" i da "programer možda ne testira statusnu oznaku kao posledica lenjosti ili zaboravnosti. U stvari, abnormalne situacije predstavljene od strane statusnih oznaka su po pravilu ignorisane!" Vat naglašava da u suprotnosti sa testiranjem statusnih oznaka, izuzeci imaju suprotno opšte ponašanje, što dovodi do gašenja programa osim u slučaju da se programer ne pozabavi sa izuzetkom na neki način, npr. dodajući u kod naredbe za ignorisanje. Na osnovu ovih argumenata, Vat donosi zaključak da jump sekvenceri ili escape sekvenceri nisu pogodni koliko i sekvencer izuzetaka sa dolenavedenom semantikom.

U jezicima Obdžekt Paskal, D, Java, C#, i Pajton, klauzula `finally` se može dodati na `try` konstrukciju. Bez obzira na to kako kontrola napušta `try`, kod unutar finally klauzule se zagarantovano izvršava. Ovo je korisno u slučaju pisanja koda koji treba da se odrekne bitnih resursa (kao što je otvorena datoteka ili veza sa bazom podataka) na kraju izračunavanja:
```csharp
FileStream stm = null; // C# primer
try {
    stm = new FileStream ("logfile.txt", FileMode.Create);
    return ProcessStuff(stm);             // možda izbaci izuzetak
} finally {
    if (stm != null)
        stm.Close();
}
```
Pošto je ovakav šablon dosta zastupljen, C# ima specijalnu sintaksu:
```csharp
using (FileStream stm = new FileStream ("logfile.txt", FileMode.Create)) {
    return ProcessStuff(stm);             // možda izbaci izuzetak
}
```
Po napuštanju `using`-bloka, kompilator garantuje da je `stm` objekat oslobođen, spajajući tako promenljivu za tok datoteka dok paralelno abstrahuje od sporednih efekata inicijalizacije i oslobađanja datoteke. Pajtonova `with` naredba i Rubijev blok argument za `File.open` se koriste uz slične ishode.

Svi gorepomenuti jezici definišu standardne izuzetke i okolnosti pod kojima su izbačeni.

Korisnici mogu da izbacuju sopstvene izuzetke; C++ dozvoljava korisnicima da izbace i hvataju bilo koji tip, uključujući osnovne tipove poput `int`, dok neki drugi jezici ne dozvoljavaju takve radnje.

### Kontinuacije

### Async
C# 5.0 je uveo async ključnu reč kao podršku asinhronom I/O u "direktnom stilu".

### Generatori
Generatori, takođe poznati pod nazivom polu-koprograme, dozvoljavaju privremenu predaju upravljanja potrošačkoj metodi, obično koristeći ključnu reč yield. Poput async ključne reči, ovo podržava programiranje u "direktnom stilu".

### Koprogrami
Koprogrami su funkcije koje mogu da međusobno predaju kontrolu - oblik ko-operativnog multitaskinga.

Koprogrami se mogu implementirati kao biblioteka u slučaju da programski jezik omogućava kontinuacije ili generatore - tako da razlike između koprograma i generatora u praksi postaju samo tehnički detalj.

### Tabela van-lokalnog upravljanja tokom

## Predložene kontrolne strukture
U satiričnom članku lista Datamejšn iz 1973., R. Lorens Klark je predložio da se GOTO naredba može zameniti COMEFROM naredbom, i naveo neke zanimljive primere. Ovo je zaista implementrirano u jeziku INTERCAL, a namenski ezoteričnom programskom jeziku.

U svom članku iz 1974. "Strukturirano Programiranje sa go to Naredbama", Donald Knut je prepoznao dve situacije koje nisu objašnjene gorenavedenim kontrolnim strukturama, i izneo primere kontrolnih struktura koje bi mogle da upravljaju ovim situacijama. Uprkos njihovoj korisnosti, ove konstrukcije i dalje nisu zastupljene u konvencionalnim programskim jezicima.

### Petlja sa središnjim testiranjem
Predloženo od strane  in 1972:
    **loop**                           **loop**
        xxx1                           read(char);
    **while** test;                    **while** **not** atEndOfFile;
        xxx2                           write(char);
    **repeat**;                        **repeat**;
Ako se izostavi *xxx1*, dobijamo petlju sa testiranjem na vrhu.

Ako se izostavi *xxx2, *dobijamo petlju sa testiranjem na kraju.

Ako se **while** izostavi, dobijamo beskonačnu petlju.

Zato ova jedna konstrukcija može zameniti više različitih konstrukcija u većini programskih jezika.

Jedna od mogućih varijanti je da se dozvoli testiranje **while** naredbe više puta; unutar petlje, ali upotreba **exitwhen** (pogledaj sledeći odeljak) bolje pokriva ovaj slučaj.

Jezici koji ne poseduju ovu konstrukciju mogu da je imitiraju koristeći idiome beskonačnih petlji sa izlazom:
 **while** (true) {
     xxx1
     **if** (**not** test)
         **break**
     xxx2
 }
U jeziku Ada, gorenavedena konstrukcija petlje (**loop**-**while**-**repeat**) se može predstaviti korišćenjem standardne beskonačne petlje (**loop** - **end loop**) koja ima **exit when** klauzulu u sredini (ne treba pomešati sa **exitwhen** naredbom iz narednog odeljka).
```ada
with Ada.Text_IO;
with Ada.Integer_Text_IO;

procedure Print_Squares is 
    X : Integer;
begin
    Read_Data : loop
        Ada.Integer_Text_IO.Get(X);
    exit Read_Data when X = 0;
        Ada.Text IO.Put (X * X);
        Ada.Text IO.New_Line;
    end loop Read_Data;
end Print_Squares;
```
Dodavanje imena petlji (kao *Read_Data* u ovom primeru) je opcionalno ali dozvoljava izlaženje iz spoljne petlje koja se nalazi u nekoliko ugnežđenih petlji.

### Višestruki rani izlaz/izlaz iz ugnežđenih petlji
Ovo je predložio Can1974. Promenjena verzija je prikazana ovde.
    **exitwhen** DogađajA **or** DogađajB **or** DogađajC;
        xxx
    **exits**
        DogađajA: radnjaA
        DogađajB: radnjaB
        DogađajC: radnjaC
    **endexit**;
**exitwhen** se koristi za specifikaciju događaja koji se mogu odigrati unutar *xxx*,
njihovo događanje je dokazano korišćenjem imena događaja kao naredbe.

Kad se neki događaj manifestuje, izvrši se relevantna radnja, i upravljanje se prebacuje odmah nakon **endexit**.

Ova konstrukcija pruža veoma jasnu razliku između određivanja da li se neka situacija primenjuje i radnje koja se treba izvržiti za tu situaciju.

**exitwhen** je po konceptu slično upravljanju izuzetaka, a u ovu svrhu se koriste izuzeci ili slične konstrukcije u dosta jezika.

Prost primer koji sledi uključuje pretragu dvodimenzionalne tabele u cilju pronalaženja određene stavke.
    **exitwhen** found **or** missing;
        **for** I := 1 **to** N **do**
            **for** J := 1 **to** M **do**
                **if** table[I,J] = target **then** found;
        missing;
    **exits**
        found:   print ("item is in table");
        missing: print ("item is not in table");
    **endexit**;

## Povezano
* Grana (računarstvo)
* dijagram upravljanja tokom
* Grafik upravljanja tokom
* Tabela upravljanja
* Koprogram
* Ciklomatička kompleksnost
* Dijagram toka
* GOTO
* Džeru, pomaže pri učenju kontrolnih struktura
* Glavna petlja
* Rekurzija
* Raspoređivanje
* Špageti kod
* Strukturirano programiranje
* Potprogram
* Naredba zamene, uslovno menja tok upravljanja

## Reference

## Vanjske veze

* Go To Statement Considered Harmful
* A Linguistic Contribution of GOTO-less Programming 
* &nbsp;PDF&nbsp;(2.88&nbsp;MB)
* &nbsp;PDF&nbsp;(31.4&nbsp;MB)