814 lines
25 KiB
JavaScript
814 lines
25 KiB
JavaScript
/*
|
|
* [Č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);
|
|
}
|
|
}
|