/* * [Česky] * Projekt: Robot Karel * Copyright: Viz KOPIROVANI v kořenovém adresáři projektu * * [English] * Project: Karel, the Robot * Copyright: See COPYING in the top level directory */ // JavaScript - vykonávání příkazů // =========================================================================== // =~ Globální nastavení ~==================================================== // Největší počet příkazů provedených v jedné smyčce nastaveni.maximum_prikazu_smycky = 10; // Maximální délka smyčky v milisekundách nastaveni.maximalni_delka_smycky = 25; // Prodleva mezi vykonáváním příkazů // nastaveni.prodleva = 500; // Nyní definováno v souboru nastaveni-funkce.js // =========================================================================== // =~ Globální proměnné ~===================================================== // Informace a data o příkazech prikazy = new Object(); // Jádro vykonávající příkazy // // Každá funkce pro jednotlivé příkazy je navržena tak, aby byla schopna jak // vykonat příkaz, tak rozpoznat případné chyby syntaxe. Režim práce je předán // v parametru syntaxe, který při hodnotě true rozhodne pouze o syntaxi a při // hodnotě false vykoná příkaz. prikazy.jadro = new Object(); // Verzování prikazy.VERZE_10 = 1; prikazy.VERZE_11 = 2; prikazy.VERZE_12 = 4; prikazy.VERZE_20 = 8; prikazy.min_VERZE_20 = prikazy.VERZE_20; prikazy.min_VERZE_12 = prikazy.min_VERZE_20 | prikazy.VERZE_12; prikazy.min_VERZE_11 = prikazy.min_VERZE_12 | prikazy.VERZE_11; prikazy.min_VERZE_10 = prikazy.min_VERZE_11 | prikazy.VERZE_10; // =========================================================================== // =~ Formátování chyby provádění ~=========================================== prikazy.formatuj_chybu_provadeni = function (jmeno, cislo_radky, telo, text) { if ( jmeno ) { var prikaz_radky = ""; if ( cislo_radky < telo.length ) { prikaz_radky = ": " + prikazy.formatovac.zformatuj_jednu_radku(telo[cislo_radky]); } return "Chyba při provádění příkazu " + jmeno + " na řádce " + (cislo_radky+1) + prikaz_radky + ".\n\n" + text; } else { return "Chyba při provádění příkazu.\n\n" + text; } } // =========================================================================== // =~ Testy ~================================================================= // Test spuštění. Vrací true, jestli se může pokračovat prikazy.test_spusteni = function () { var prikaz = prikazy.jadro.probiha(); if ( prikaz ) { var uzivatel_chce = window.confirm( "Právě je prováděn příkaz " + prikaz.jmeno + ".\n\n" + "Pro pokračování je nutné provádění ukončit.\n" + "Mám příkaz ukončit?" ); if ( uzivatel_chce ) { prikazy.jadro.zastav(); return true; } return false; } return true; } // =========================================================================== // =~ Stav provádění příkazů ~================================================ prikazy.Stav = function (prikaz) { this.probiha = false; this.casovac = { id: null }; this.doplnit_konec = true; this.rychle = 0; this.byla_rychla_akce = false; this.historie = new Array(); this.pozice = new Object(); if ( prikaz ) { this.prikaz = prikaz; } else { this.syntaxe = true; } } // Funkce najde odpovídající přikaz KONEC, případně KONEC, JINAK, nebo AŽ. Vrací // objekt Vysledek s nastavenou chybou, pokud k nějaké došlo. Kontroluje // syntaxi a jako jediná funkce není omezená na počet kroků. Po návratu je // příkaz připraven na další krok. prikazy.Stav.prototype.najdi_konec = function () { var stara_syntaxe = this.syntaxe; this.syntaxe = true; var vysledek = new Vysledek(); if ( ! this.historie.length || this.historie.length < 1 ) { ladici_vypis(CHYBA, "stav.najdi_konec", "nebyl spuštěn žádný příkaz, nebo už skončil"); this.syntaxe = stara_syntaxe; return vysledek; } var historie_pozice = this.historie.length - 1; var konec_jinak = ( this.historie[historie_pozice][0] != prikazy.KONEC_JINAK ); if ( konec_jinak ) { ladici_vypis(DETAIL, "stav.najdi_konec", "přeskakuji na další KONEC nebo KONEC, JINAK") } else { ladici_vypis(DETAIL, "stav.najdi_konec", "přeskakuji na další KONEC") } while ( !vysledek.byla_chyba() && historie_pozice < this.historie.length && ( !konec_jinak || konec_jinak && this.historie[historie_pozice][0] != prikazy.KONEC_JINAK) ) { vysledek.nastav( this.krok() ); } this.syntaxe = stara_syntaxe; return vysledek; } prikazy.Stav.prototype.dotaz_na_doplneni = function (dotaz, doplneni, text) { if ( this.doplnit_konec && window.confirm(dotaz) ) { if ( doplneni instanceof Array ) { for ( var i = 0; i < doplneni.length; i++ ) { ladici_vypis( DETAIL, "stav.dotaz_na_doplneni", this.pozice.prikaz.jmeno, "doplňuji na konec příkaz " + doplneni[i].jmeno ); this.pozice.prikaz.telo.push( [doplneni[i]] ); } } else { ladici_vypis( DETAIL, "stav.dotaz_na_doplneni", this.pozice.prikaz.jmeno, "doplňuji na konec příkaz " + doplneni.jmeno ); this.pozice.prikaz.telo.push( [doplneni] ); } return new Vysledek( false, Vysledek.BYL_UPRAVEN ); } else { return new Vysledek( new Chyba(true, text) ); } } // Doplnění příkazů KONEC a KONEC, JINAK pro všechny cykly a podmínky. Vrací // objekt Vysledek, pokud došlo k chybě. Vrací null, pokud nemohlo být doplnění // provedeno prikazy.Stav.prototype.dopln_konec = function (posledni) { var obecna_chyba = new Vysledek( new Chyba( true, "Na konci chybí příkaz KONEC.\n" + "Zkontrolujte příkazy podmínek, opakování a rychlých bloků." ) ); // Nejdříve kontrola, jestli historie vůbec něco obsahuje a jestli náhodou // neobsahuje další volání - v tom případě se vrátíme bez jakékoliv úpravy if ( !this.historie || this.historie && !this.historie.length ) return obecna_chyba; if ( !this.pozice || this.pozice && !this.pozice.prikaz ) return obecna_chyba; if ( this.doplnit_konec ) { var prikaz_doplneni = false; // Jestli je poslední příkaz pro doplnění for ( var i = 0; i < this.historie.length; i++ ) { if ( ! this.historie[i][0].systemovy ) { prikaz_doplneni = ( this.historie[i][0] == this.pozice.prikaz ); } } if ( !prikaz_doplneni ) return obecna_chyba; } var stara_historie = new Array(); if ( !posledni ) { posledni = this.historie.pop(); stara_historie.unshift(posledni); } var vysledek = new Vysledek(); do { if ( !posledni[0].systemovy ) { vysledek.nastav( this.dotaz_na_doplneni( "Příkaz " + this.pozice.prikaz.jmeno + " není ukončen příkazem KONEC.\n\nDoplnit?", prikazy.KONEC, "Příkaz není ukončen příkazem KONEC.\n" + "Prosím ukončete svůj příkaz slovem KONEC.") ); } else if ( posledni[0] == prikazy.KDYZ ) { vysledek.nastav( this.dotaz_na_doplneni( "Podmínka KDYŽ není ukončena sérií příkazů KONEC, JINAK a KONEC.\n\n" + "Doplnit?", [ prikazy.KONEC_JINAK, prikazy.KONEC ], "Podmínka KDYŽ není ukončena alespoň příkazem KONEC.\n\n" + "Prosím ukončete podmínku KDYŽ slovem KONEC.") ); } else if ( posledni[0] == prikazy.KONEC_JINAK ) { vysledek.nastav( this.dotaz_na_doplneni( "Podmínka KDYŽ není ukončena příkazem KONEC.\n\n" + "Doplnit?", prikazy.KONEC, "Podmínka KDYŽ je ukončena pouze slovem KONEC, JINAK.\n\n" + "Prosím ukončete podmínku KDYŽ slovem KONEC.") ); } else if ( posledni[0] == prikazy.DOKUD ) { vysledek.nastav( this.dotaz_na_doplneni( "Cyklus DOKUD není ukončen příkazem KONEC, nebo AŽ.\n\n" + "Doplnit příkaz KONEC?", prikazy.KONEC, "Ukončení cyklu DOKUD není ukončeno alespoň příkazem KONEC.\n\n" + "Prosím ukončete cyklus DOKUD slovem KONEC.") ); } else if ( posledni[0] == prikazy.OPAKUJ ) { vysledek.nastav( this.dotaz_na_doplneni( "Cyklus OPAKUJ není ukončen příkazem KONEC, nebo AŽ.\n\n" + "Doplnit příkaz KONEC?", prikazy.KONEC, "Cyklus OPAKUJ není ukončen alespoň příkazem KONEC.\n\n" + "Prosím ukončete cyklus OPAKUJ slovem KONEC.") ); } else if ( posledni[0] == prikazy.RYCHLE ) { vysledek.nastav( this.dotaz_na_doplneni( "Blok RYCHLE není ukončen příkazem POMALU.\n\n" + "Doplnit?", prikazy.POMALU, "Rychlý blok RYCHLE není ukončen slovem POMALU, nebo KONEC.\n\n" + "Prosím ukončete bloku rychlého provádění slovem POMALU.") ); } else { vysledek = obecna_chyba; break; } if ( this.doplnit_konec ) { posledni = this.historie.pop(); if ( posledni ) stara_historie.unshift(posledni); } } while ( this.doplnit_konec && !vysledek.byla_chyba() && posledni ); if ( this.historie.length > 0 ) { this.historie = this.historie.concat(stara_historie); } else { this.historie = stara_historie; } return vysledek; } // Proveď kontrolu syntaxe a vrať výsledek prikazy.Stav.prototype.kontrola_syntaxe = function (prikaz, doplnit_konec) { this.syntaxe = true; this.doplnit_konec = doplnit_konec; this.historie = new Array(); this.prikaz = prikaz; delete this.pozice; this.rychle = 0; var vysledek = this.proved_volani( prikaz ); this.pozice = vysledek.hodnota; while ( !vysledek.byla_chyba() && this.historie.length > 0 ) { vysledek.nastav( this.krok() ); } return vysledek; } // Proveď (první) příkaz prikazy.Stav.prototype.proved_volani = function (prikaz) { var cislo_radky = 0; while ( cislo_radky < prikaz.telo.length && prikaz.telo[cislo_radky][0].ignoruj ) { cislo_radky++; } if ( this.pozice instanceof Object && this.pozice.prikaz ) { // Kam se vrátit this.historie.push( [ this.pozice.prikaz, this.pozice.cislo_radky + 1 ] ); } else { // První nastavení - nikam se nevracíme this.historie.push( [ this.prikaz ] ); } return new Vysledek( false, Vysledek.NIC, { prikaz: prikaz, cislo_radky: cislo_radky } ); } // Rychlé vykonávání příkazů prikazy.Stav.prototype.proved_rychle = function (prikaz) { this.rychle++; ladici_vypis( DETAIL, "stav.proved_rychle", "rychlé provádění, počet volání: " + this.rychle ); } // Rychlé vykonávání příkazů prikazy.Stav.prototype.proved_pomalu = function (prikaz) { var provedl_akci = false; if ( this.rychle ) this.rychle--; if ( this.rychle ) { ladici_vypis( DETAIL, "stav.proved_pomalu", "zůstává rychlé provádění, počet volání: " + this.rychle ); } else { provedl_akci = this.byla_rychla_akce; ladici_vypis( DETAIL, "stav.proved_pomalu", "nastaveno pomalé (normální) provádění, akce " + (provedl_akci?"byla":"nebyla") + " provedena" ); this.byla_rychla_akce = false; } if ( provedl_akci ) { return new Vysledek( false, Vysledek.PROVEDL_AKCI ); } else { return new Vysledek(); } } // Spusť vykonávání příkazu prikazy.Stav.prototype.spust = function () { var vysledek = new Vysledek(); if ( this.prikaz.systemovy ) { vysledek.nastav( this.prikaz.spust() ); this.probiha = false; } else { prikazy.obnov_stav( true ); this.probiha = true; vysledek.nastav( this.proved_volani(this.prikaz) ); if ( !vysledek.je_konec() ) { var pozice = this.pozice = vysledek.hodnota; vysledek.chyba.formatuj = function (text) { return prikazy.formatuj_chybu_provadeni(pozice.jmeno, pozice.cislo_radky, prikazy.prikaz[pozice.jmeno].telo, text); } vysledek.nastav( this.dalsi_krok(0) ); } } return vysledek; } // Vynulování časovače prikazy.Stav.prototype.nuluj_casovac = function () { if ( this.casovac && this.casovac.id ) { clearTimeout(this.casovac.id); this.casovac.id = null; delete this.casovac.cas; delete this.casovac.prodleva; delete this.casovac.funkce; } } // Nastav časovač prikazy.Stav.prototype.nastav_casovac = function (funkce, prodleva) { this.nuluj_casovac(); this.casovac.cas = new Date(); this.casovac.prodleva = prodleva; this.casovac.funkce = funkce; this.casovac.id = setTimeout( funkce, prodleva ); } // Přenastav časovač prikazy.Stav.prototype.prenastav_casovac = function (prodleva) { if ( this.casovac && this.casovac.id ) { clearTimeout(this.casovac.id); var cas = new Date(); var rozdil = cas-this.casovac.cas; if ( rozdil >= prodleva ) { prodleva = 0; } else { prodleva -= rozdil; } this.casovac.cas = cas; this.casovac.prodleva = prodleva; this.casovac.id = setTimeout( this.casovac.funkce, prodleva ); } } // Zastav vykonávání příkazů prikazy.Stav.prototype.zastav = function () { if ( this.probiha ) { this.probiha = false; prikazy.obnov_stav( this.probiha ); this.nuluj_casovac(); } return new Vysledek(new Chyba(), Vysledek.KONEC); } // =========================================================================== // =~ Opakované provádění příkazů ~=========================================== prikazy.Stav.prototype.dalsi_krok = function (pocet_prikazu) { var vysledek = new Vysledek(); if ( pocet_prikazu == undefined ) { pocet_prikazu = nastaveni.maximum_prikazu_smycky; } this.nuluj_casovac(); var start = new Date(); var i = 0; while ( i < pocet_prikazu && ((new Date())-start) <= nastaveni.maximalni_delka_smycky ) { vysledek.nastav( this.krok() ); if ( vysledek.byl_upraven() && this.pozice.prikaz ) { editor.prikaz_upraven( this.pozice.prikaz ); } if ( vysledek.je_konec() || !this.rychle && vysledek.byla_akce() ) { break; } if ( this.rychle && vysledek.byla_akce() ) { this.byla_rychla_akce = true; } i++; } if ( vysledek.je_konec() ) { this.zastav(); var pozice = this.pozice; vysledek.chyba.formatuj = function (text) { return prikazy.formatuj_chybu_provadeni(pozice.prikaz.jmeno, pozice.cislo_radky, pozice.prikaz.telo, text); } vysledek.zobraz_chybu(); } else { var interval = nastaveni.prodleva; if ( i == pocet_prikazu || this.rychle || pocet_prikazu == 0 ) { interval = 0; } this.nastav_casovac( prikazy.dalsi_krok, interval ); } return vysledek; } // Proveď jeden krok příkazu. Vrací objekt Vysledek prikazy.Stav.prototype.krok = function () { var vysledek = new Vysledek(); var cislo_radky = this.pozice.cislo_radky; if ( cislo_radky >= this.pozice.prikaz.telo.length ) { ladici_vypis( DETAIL, "stav.krok", this.pozice.prikaz.jmeno, "příkaz není správně ukončen" ); vysledek.nastav( this.dopln_konec() ); if ( vysledek.je_konec() ) { // Aktualizace čísla řádku this.pozice.cislo_radky = this.pozice.prikaz.telo.length; } // Aktualizuj pozici chyby vysledek.nastav( false, vysledek.stav, this.pozice ); } else { var radka = this.pozice.prikaz.telo[cislo_radky]; if ( !this.syntaxe || this.syntaxe && radka[0].syntaxe ) { if ( !radka[0].ignoruj ) { vysledek.nastav( radka[0].spust(radka, this) ); } } } if ( vysledek.hodnota ) { this.pozice = vysledek.hodnota; } else if ( !vysledek.je_konec() ) { this.pozice.cislo_radky++; } else if( vysledek.byla_chyba() ) { // Byla chyba, ale nebyla nastavena řádka chyby - aktualizuj vysledek.nastav( false, vysledek.stav, this.pozice ); } if ( vysledek.ma_preskocit() ) { vysledek.nastav( this.najdi_konec() ); } return vysledek; } // =========================================================================== // =~ Základní systémové funkce ~============================================= prikazy.jadro.KROK = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "KROK"); return mesto.proved_krok(); } prikazy.jadro.VLEVO_VBOK = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "VLEVO-VBOK"); return mesto.proved_vlevo_vbok(); } prikazy.jadro.POLOZ = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "POLOŽ"); return mesto.proved_poloz(); } prikazy.jadro.ZVEDNI = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "ZVEDNI"); return mesto.proved_zvedni(); } prikazy.jadro.STOP = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "STOP"); if ( !stav.syntaxe ) { var vysledek = new Vysledek( new Chyba(true, "Bohužel musím končit.\n\n" + "Narazil jsem na příkaz STOP.") ); vysledek.zobraz_chybu(); return vysledek; } else { return new Vysledek(); } } prikazy.jadro.RYCHLE = function (radka, stav) { stav.historie.push( radka ); ladici_vypis(INFORMACE, "prikazy.jadro", "RYCHLE"); if ( !stav.syntaxe ) stav.proved_rychle(); return new Vysledek(); } prikazy.jadro.POMALU = function (radka, stav) { var posledni = stav.historie.pop(); if ( !posledni || posledni && posledni[0] != prikazy.RYCHLE ) { return new Vysledek( new Chyba( true, "Nalezen příkaz POMALU bez odpovídajícího RYCHLE." ) ); } ladici_vypis(INFORMACE, "prikazy.jadro", "POMALU"); if ( !stav.syntaxe ) { return stav.proved_pomalu(); } return new Vysledek(); } // =========================================================================== // =~ Konce ~================================================================= prikazy.jadro.KONEC_JINAK = function (radka, stav) { var posledni = stav.historie.pop(); if ( !stav.syntaxe ) ladici_vypis(INFORMACE, "prikazy.jadro", "KONEC, JINAK"); if ( !posledni || posledni && posledni[0] != prikazy.KDYZ ) { return new Vysledek( new Chyba( true, "Nalezen příkaz KONEC, JINAK bez odpovídající podmínky KDYŽ.\n" + "Na příkaz KDYŽ a KONEC, JINAK se prosím koukněte do nápovědy." ) ); } stav.historie.push( radka ); if ( !stav.syntaxe ) { // Přeskoč až na další konec return new Vysledek(false, Vysledek.PRESKOC_KONEC); } else { return new Vysledek(); } } // Vyhodnotí konec opakování příkazu OPAKUJ prikazy.jadro.konec_OPAKUJ = function (radka, stav, posledni) { // Opakování příkazu if ( posledni.length == 2 || (posledni.length == 3 && posledni[1] > 0) ) { if ( posledni.length == 3 ) { ladici_vypis(DETAIL, "prikazy.jadro", "nový test cyklu OPAKUJ, " + "počet opakování:" + posledni[1]); posledni[1]--; } else { ladici_vypis(DETAIL, "prikazy.jadro", "zpět na cyklus OPAKUJ, " + "nekonečný počet opakování"); } stav.historie.push( posledni ); return new Vysledek(false, Vysledek.NIC, { prikaz: stav.pozice.prikaz, cislo_radky: posledni[posledni.length-1] }); } else { ladici_vypis(DETAIL, "prikazy.jadro", "nový test cyklu OPAKUJ, " + "konec opakování"); return new Vysledek(); } } // Vyhodnotí konec opakování příkazu DOKUD prikazy.jadro.konec_DOKUD = function (radka, stav, posledni) { // Cyklus DOKUD ladici_vypis(DETAIL, "prikazy.jadro", "nový test příkazu DOKUD"); if ( prikazy.jadro.podminka(posledni) ) { // Podmínka je splněna, posuň se zpět za příkaz DOKUD stav.historie.push(posledni); return new Vysledek( false, Vysledek.NIC, { prikaz: stav.pozice.prikaz, cislo_radky: posledni[2] } ); } else { return new Vysledek(); } } prikazy.jadro.KONEC = function (radka, stav) { var posledni = stav.historie.pop(); if ( !stav.syntaxe ) ladici_vypis(INFORMACE, "prikazy.jadro", "KONEC"); if ( !posledni || posledni && posledni[0].systemovy && posledni[0] != prikazy.KDYZ && posledni[0] != prikazy.KONEC_JINAK && posledni[0] != prikazy.DOKUD && posledni[0] != prikazy.OPAKUJ && posledni[0] != prikazy.RYCHLE ) { return new Vysledek( new Chyba( true, "Nalezen příkaz KONEC, který neukončuje ani uživatelský příkaz, "+ "ani podmínku, ani opakování.\n" + "Na ukončování příkazů se prosím koukněte do nápovědy.") ); } if ( !posledni[0].systemovy ) { // Konec příkazu var prikaz = stav.pozice.prikaz; var prazdny = true; var dalsi_cislo_radky = stav.pozice.cislo_radky+1; if ( dalsi_cislo_radky < prikaz.telo.length ) { var dalsi_prikaz = prikaz.telo[dalsi_cislo_radky][0]; stav.historie.push(posledni); if ( !dalsi_prikaz.ignoruj ) { return new Vysledek( new Chyba( true, "Nalezen příkaz za posledním příkazem KONEC. " + "Pravděpodobně nějaká podmínka nebo cyklus byl špatně " + "ukončen." ), Vysledek.NIC, { prikaz: prikaz, cislo_radky: dalsi_cislo_radky } ); } else { return new Vysledek( new Chyba( true, "Nalezen " + dalsi_prikaz.jmeno + " za posledním příkazem KONEC, který ukončuje popis " + "celého příkazu." ), Vysledek.NIC, { prikaz: prikaz, cislo_radky: dalsi_cislo_radky } ); } } if ( stav.historie.length == 0 ) { return new Vysledek(false, Vysledek.KONEC); } else { return new Vysledek(false, Vysledek.NIC, { prikaz:posledni[0], cislo_radky: posledni[1] } ); } } else if ( posledni[0] == prikazy.OPAKUJ && !stav.syntaxe ) { // Cyklus OPAKUJ return prikazy.jadro.konec_OPAKUJ(radka, stav, posledni); } else if ( posledni[0] == prikazy.DOKUD && !stav.syntaxe ) { // Cyklys DOKUD return prikazy.jadro.konec_DOKUD(radka, stav, posledni); } else if ( posledni[0] == prikazy.RYCHLE ) { // Konec rychlého bloku return stav.proved_pomalu(); } // Všechno ostatní prostě skončí (KDYŽ-KONEC, KDYŽ-KONEC_JINAK-KONEC) return new Vysledek(); } // =========================================================================== // =~ Podmínky a cykly ~====================================================== prikazy.jadro.podminka = function (radka) { var vysledek = prikazy.podminky[Math.abs(radka[1])-1].test(); if ( radka[1] < 0 ) vysledek = !vysledek; ladici_vypis(INFORMACE, "prikazy.jadro", "podmínka " + prikazy.formatuj_podminku(radka) + " " + (vysledek?"je":"není") + " pravdivá" ); return vysledek; } prikazy.jadro.KDYZ = function (radka, stav) { stav.historie.push( radka ); if ( !stav.syntaxe && !prikazy.jadro.podminka(radka) ) { return new Vysledek( false, Vysledek.PRESKOC_KONEC ); } else { return new Vysledek(); } } prikazy.jadro.DOKUD = function (radka, stav) { stav.historie.push( radka.concat(stav.pozice.cislo_radky+1) ); if ( !stav.syntaxe && !prikazy.jadro.podminka(radka) ) { return new Vysledek( false, Vysledek.PRESKOC_KONEC ); } else { return new Vysledek(); } } prikazy.jadro.OPAKUJ = function (radka, stav) { var historie = radka.concat(stav.pozice.cislo_radky+1); if ( !stav.syntaxe && radka.length == 2 && radka[1] == 0 ) { ladici_vypis(INFORMACE, "prikazy.jadro", "cyklus OPAKUJ s nulovým počtem opakování" ); stav.historie.push( historie ); return new Vysledek(false, Vysledek.PRESKOC_KONEC); } else { if ( historie.length == 3 ) { ladici_vypis(INFORMACE, "prikazy.jadro", "cyklus OPAKUJ, počet opakování:" + historie[1]); historie[1]--; } else { ladici_vypis(INFORMACE, "prikazy.jadro", "cyklus OPAKUJ, nekonečný počet opakování"); } stav.historie.push( historie ); return new Vysledek(); } } prikazy.jadro.AZ = function (radka, stav) { var posledni = stav.historie.pop(); if ( !posledni || posledni && posledni[0] != prikazy.OPAKUJ && posledni[0] != prikazy.DOKUD ) { return new Vysledek( new Chyba( true, "Nalezen příkaz AŽ, který neukončuje opakování OPAKUJ nebo DOKUD.\n" + "Na příkaz AŽ se prosím koukněte do nápovědy." ) ); } if ( !stav.syntaxe && !prikazy.jadro.podminka(radka) ) { if ( posledni[0] == prikazy.OPAKUJ ) { return prikazy.jadro.konec_OPAKUJ(radka, stav, posledni); } else { return prikazy.jadro.konec_DOKUD(radka, stav, posledni); } } else { return new Vysledek(); } } // =========================================================================== // =~ Uživatelské příkazy ~=================================================== prikazy.jadro.UZIVATELSKY = function (radka, stav) { ladici_vypis(INFORMACE, "prikazy.jadro", "Uživatelský příkaz " + radka[0].jmeno ); if ( !stav.syntaxe ) { // TODO: Optimalizace rekurze, pokud za voláním následuje KONEC (případně // nějaký ignorovaný příkaz) - neukládat volání jako nové volání. Ale pouze // v případě, pokud je poslední příkaz v historii ten samý - nastavit první // parametr na počet vnoření return stav.proved_volani( radka[0] ); } else { return new Vysledek(); } } // =========================================================================== // =~ Provádení příkazů ~===================================================== prikazy.dalsi_krok = function () { if ( prikazy.stav ) { prikazy.stav.dalsi_krok(); } } prikazy.jadro.proved = function (jmeno) { prikazy.stav = new prikazy.Stav( prikazy.prikaz[jmeno] ); return prikazy.stav.spust(); } prikazy.jadro.zastav = function () { if ( prikazy.stav ) { var vysledek = prikazy.stav.zastav(); delete prikazy.stav; return vysledek; } else { return new Vysledek(false, Vysledek.KONEC); } } // Zjisti, jestli nějaký příkaz zrovna probíhá prikazy.jadro.probiha = function () { var spusteno = ( prikazy.stav && prikazy.stav.probiha ); if ( spusteno ) { return prikazy.stav.prikaz; } else { return false; } } prikazy.jadro.proved_nebo_zastav = function(jmeno) { if ( prikazy.stav && prikazy.stav.probiha ) { return prikazy.jadro.zastav(); } else { return prikazy.jadro.proved(jmeno); } } prikazy.jadro.prenastav_casovac = function(prodleva) { if ( prikazy.stav && prikazy.stav.probiha ) { prikazy.stav.prenastav_casovac(prodleva); } }