Programavimas

Sukurkite vertėją „Java“ - įdiegkite vykdymo variklį

Ankstesnis 1 2 3 Puslapis 2 Kitas 2 puslapis iš 3

Kiti aspektai: eilutės ir masyvai

COCOA vertėjas įgyvendina dar dvi pagrindines BASIC kalbos dalis: eilutes ir masyvus. Pirmiausia pažvelkime į stygų įgyvendinimą.

Norėdami įgyvendinti eilutes kaip kintamuosius, Išraiška klasė buvo modifikuota įtraukiant „styginių“ posakių sąvoką. Ši modifikacija buvo dviejų papildymų forma: isString ir eilutės reikšmė. Šių dviejų naujų metodų šaltinis parodytas žemiau.

 String stringValue (Programos pgm) išmeta BASICRuntimeError {throws new BASICRuntimeError ("Tam nėra eilutės atvaizdavimo."); } loginis isString () {return false; } 

Aišku, BASIC programai nėra labai naudinga gauti pagrindinės išraiškos eilutės vertę (kuri visada yra skaitmeninė arba loginė išraiška). Iš naudingumo trūkumo galite padaryti išvadą, kad šie metodai tada nepriklausė Išraiška ir priklausė poklasiui Išraiška vietoj to. Tačiau priskyrus šiuos du metodus pagrindinei klasei, visi Išraiška objektus galima patikrinti, ar jie iš tikrųjų yra stygos.

Kitas dizaino metodas yra grąžinti skaitines reikšmes kaip eilutes, naudojant a „StringBuffer“ objektas sukurti vertę. Pavyzdžiui, tą patį kodą būtų galima perrašyti taip:

 String stringValue (Programos pgm) išmeta BASICRuntimeError {StringBuffer sb = nauja StringBuffer (); sb.append (this.value (pgm)); grąžinti sb.toString (); } 

Ir jei naudojamas aukščiau pateiktas kodas, galite atsisakyti isString nes kiekviena išraiška gali grąžinti eilutės reikšmę. Be to, galite modifikuoti vertė metodas bandyti grąžinti skaičių, jei išraiška įvertina eilutę, paleisdama ją per vertė metodas java.lang.Dvigubai. Daugeliu kalbų, tokių kaip „Perl“, „TCL“ ir „REXX“, toks amorfinis spausdinimas yra labai naudingas. Abu požiūriai galioja, todėl turėtumėte pasirinkti remdamiesi vertėjo dizainu. BASIC vertėjui reikia pateikti klaidą, kai eilutė priskiriama skaitiniam kintamajam, todėl aš pasirinkau pirmąjį metodą (grąžindamas klaidą).

Kalbant apie masyvus, yra įvairių būdų, kaip galite suprojektuoti savo kalbą, kad juos interpretuotumėte. C naudoja laužtinius skliaustus aplink masyvo elementus, kad išskirtų masyvo indekso nuorodas nuo funkcijų nuorodų, kurių argumentuose yra skliaustai. Tačiau BASIC kalbos dizaineriai pasirinko skliaustus naudoti tiek funkcijoms, tiek masyvams, kai tekstas VARDAS (V1, V2) mato analizatorius, tai gali būti funkcijos iškvietimas arba masyvo nuoroda.

Leksinis analizatorius išskiria žetonus, po kurių yra skliaustai, darant prielaidą, kad jie yra funkcijos, ir išbandydami tai. Tada jis tikrina, ar tai yra raktiniai žodžiai, ar kintamieji. Būtent šis sprendimas neleidžia jūsų programai apibrėžti kintamojo, pavadinto „SIN“. Bet kurį kintamąjį, kurio vardas atitiko funkcijos pavadinimą, leksinis analizatorius grąžins kaip funkcijos žetoną. Antrasis leksinio analizatoriaus triukas yra patikrinti, ar iškart po kintamojo pavadinimo yra „(“. Jei taip, analizatorius mano, kad tai yra masyvo nuoroda. Analizuodami tai leksiniame analizatoriuje, mes pašaliname eilutę "MYARRAY (2)'nėra aiškinamas kaip galiojantis masyvas (atkreipkite dėmesį į tarpą tarp kintamojo pavadinimo ir atviros skliaustų).

Paskutinė masyvų gudrybė yra Kintamas klasė. Ši klasė naudojama kintamojo egzemplioriui, ir, kaip aptariau praėjusio mėnesio stulpelyje, tai yra poklasis Žetonas. Tačiau jame taip pat yra keletas masyvų palaikymo mašinų, ir tai aš parodysiu žemiau:

klasės kintamasis praplečia žetoną {// Teisinių kintamųjų potipių galutinis statinis int NUMBER = 0; galutinis statinis int STRING = 1; galutinis statinis int NUMBER_ARRAY = 2; galutinis statinis int STRING_ARRAY = 4; Stygos pavadinimas; int potipis; / * * Jei kintamasis yra simbolių lentelėje, šios vertės * inicijuojamos. * / int ndx []; // masyvo indeksai. int mult []; // masyvo daugikliai dvigubi nArrayValues ​​[]; Stygos sArrayValues ​​[]; 

Pirmiau pateiktas kodas rodo egzempliorių kintamuosius, susietus su kintamuoju, kaip Pastovi išraiška klasė. Reikia pasirinkti, kiek klasių reikia naudoti, palyginti su klasės sudėtingumu. Vienas dizaino pasirinkimas gali būti pastatyti Kintamas klasė, kurioje yra tik skaliariniai kintamieji, o tada pridėkite MasyvasKintamas poklasį, kad būtų galima spręsti masyvų subtilybes. Aš nusprendžiau juos sujungti, iš esmės skaliarinius kintamuosius paversdamas 1 ilgio masyvais.

Perskaičius aukščiau pateiktą kodą, pamatysite masyvo indeksus ir daugiklius. Taip yra todėl, kad daugiamatės masyvai BASIC yra įgyvendinami naudojant vieną tiesinį „Java“ masyvą. Linijinis indeksas į „Java“ masyvą apskaičiuojamas rankiniu būdu naudojant daugiklio masyvo elementus. BASIC programoje naudojamų indeksų galiojimas tikrinamas lyginant juos su maksimaliu teisiniu indeksu indeksuose. ndx masyvas.

Pavyzdžiui, BASIC masyvo, kurio trys matmenys yra 10, 10 ir 8, vertės 10, 10 ir 8 būtų saugomos ndx. Tai leidžia išraiškų vertintojui patikrinti sąlygą „indeksas yra už ribų“ palygindamas BASIC programoje naudojamą skaičių su didžiausiu teisiniu skaičiumi, kuris dabar saugomas ndx. Mūsų pavyzdžio daugiklio masyve būtų reikšmės 1, 10 ir 100. Šios konstantos reiškia skaičius, kuriuos naudoja žemėlapiai iš daugiamatės masyvo indekso specifikacijos į linijinę masyvo indekso specifikaciją. Tikroji lygtis yra:

„Java Index“ = „Index1 + Index2“ * maksimalus „Index1 + Index3“ dydis * („Index1 MaxSize * MaxSizeIndex 2“ dydis)

Kitas Java masyvas Kintamas klasė parodyta žemiau.

 Išraiška skaičiuojama []; 

skaičiuoja masyvas naudojamas tvarkyti masyvus, kurie parašyti kaip "A (10 * B, i). "Tokiu atveju indeksai iš tikrųjų yra išraiškos, o ne konstantos, todėl nuorodoje turi būti nurodymai į tas išraiškas, kurios yra vertinamos vykdymo metu. Galiausiai yra šis gana negražiai atrodantis kodas, kuris apskaičiuoja indeksą, priklausomai nuo to, kas buvo perduota programoje. Šis privatus metodas parodytas žemiau.

 privatus int computeIndex (int ii []) meta BASICRuntimeError {int offset = 0; if ((ndx == null) || (ii.length! = ndx.length)) mesti naują BASICRuntimeError ("Neteisingas indeksų skaičius."); for (int i = 0; i <ndx.length; i ++) {if (((ii [i] ndx [i]))) mesti naują BASICRuntimeError ("Rodyklė už diapazono ribų."); poslinkis = poslinkis + (ii [i] -1) * mult [i]; } grąžinimo kompensavimas; } 

Pažvelgę ​​į aukščiau esantį kodą, pastebėsite, kad kodas pirmiausia patikrina, ar nurodant masyvą buvo naudojamas teisingas indeksų skaičius, o tada kiekvienas indeksas buvo to indekso teisiniame diapazone. Aptikus klaidą, vertėjui išmetama išimtis. Metodai numValue ir eilutės reikšmė grąžinti kintamojo reikšmę atitinkamai kaip skaičių arba eilutę. Šie du metodai parodyti toliau.

 dvigubas numValue (int ii []) meta BASICRuntimeError {return nArrayValues ​​[computeIndex (ii)]; } String stringValue (int ii []) išmeta BASICRuntimeError {if (subType == NUMBER_ARRAY) grąžina "" + nArrayValues ​​[computeIndex (ii)]; grąžinti sArrayValues ​​[computeIndex (ii)]; } 

Yra papildomų kintamojo vertės nustatymo metodų, kurie čia nerodomi.

Paslėpus daug sudėtingumo, kaip kiekvienas kūrinys yra įgyvendinamas, kai pagaliau ateina laikas vykdyti BASIC programą, „Java“ kodas yra gana paprastas.

Vykdomas kodas

Kodas, skirtas aiškinti BASIC sakinius ir juos vykdyti, yra

paleisti

metodas

Programa

klasė. Šio metodo kodas parodytas žemiau, ir aš jį peržengsiu, norėdamas nurodyti įdomias dalis.

 1 viešas tuštumas (InputStream in, OutputStream out) išmeta BASICRuntimeError {2 „PrintStream“ išklotinę; 3 Surašymas e = stmts.elements (); 4 stmtStack = naujas kaminas (); // prisiimame, kad nėra sukrautų sakinių ... 5 dataStore = new Vector (); // ... ir jokių duomenų negalima skaityti. 6 duomenysPtr = 0; 7 pareiškimas s; 8 9 vars = new RedBlackTree (); 10 11 // jei programa dar negalioja. 12 if (! E.hasMoreElements ()) 13 grįžta; 14 15 if (out of PrintStream) {16 pout = (PrintStream) out; 17} else {18 pout = new PrintStream (out); 19} 

Aukščiau pateiktas kodas rodo, kad paleisti metodas reikalauja „InputStream“ ir an „OutputStream“ naudoti kaip vykdančiosios programos „konsolę“. 3 eilutėje - surašymo objektas e yra nustatytas teiginių rinkinys iš pavadintos kolekcijos stmts. Šiai kolekcijai naudojau dvejetainio paieškos medžio, vadinamo „raudonai-juodu“, variantą. (Norėdami gauti daugiau informacijos apie dvejetainius paieškos medžius, žr. Mano ankstesnį stulpelį apie bendrųjų kolekcijų kūrimą.) Po to sukuriamos dvi papildomos kolekcijos - viena naudojant Sukrauti ir vienas naudojant a Vektorius. Šūsnis naudojamas kaip kaminas bet kuriame kompiuteryje, tačiau vektorius yra aiškiai naudojamas DATA sakiniams BASIC programoje. Galutinė kolekcija yra dar vienas raudonai juodas medis, kuriame yra nuorodos į kintamuosius, apibrėžtus BASIC programoje. Šis medis yra simbolių lentelė, kurią programa naudoja vykdydama.

Po inicijavimo nustatomi įvesties ir išvesties srautai, o tada, jei e nėra niekinis, mes pradedame rinkti bet kokius deklaruotus duomenis. Tai daroma taip, kaip parodyta šiame kode.

 / * Pirmiausia įkeliame visus duomenų teiginius * / while (e.hasMoreElements ()) {s = (Pareiškimas) e.nextElement (); if (s.keyword == Pareiškimas.DUOMENYS) {s.execute (this, in, pout); }} 

Pirmiau pateiktoje cikle paprasčiausiai apžvelgiami visi teiginiai, o visi rasti DATA sakiniai tada vykdomi. Kiekvieno DATA sakinio vykdymas įterpia tuo sakiniu deklaruotas vertes į duomenų saugykla vektorius. Tada mes vykdome programą, kuri atliekama naudojant šį kitą kodo fragmentą:

 e = stmts.elementai (); s = (Pareiškimas) e.nextElement (); padaryti {int yyy; / * Bėgdami mes praleidžiame duomenų teiginius. * / bandykite {yyy = in.available (); } pagauti (IOException ez) {yyy = 0; } if (yyy! = 0) {pout.println ("Sustojo ties:" + s); stūmimas (-ai); pertrauka; } if (s.keyword! = Pareiškimas.DUOMENYS) {if (traceState) {s.trace (this, (traceFile! = null)? traceFile: pout); } s = s.vykdyti (tai, į, menkė); } else s = nextStatement (s); } o (s! = niekinis); } 

Kaip matote aukščiau pateiktame kode, pirmiausia reikia iš naujo suaktyvinti e. Kitas žingsnis - pirmojo sakinio atėmimas į kintamąjį s tada įvesti vykdymo ciklą. Yra tam tikras kodas, skirtas patikrinti laukiamą įvestį įvesties sraute, kad būtų galima nutraukti programos eigą įvedant programą, o tada ciklas patikrina, ar vykdomasis sakinys būtų DATA sakinys. Jei taip, ciklas praleidžia teiginį, nes jis jau buvo įvykdytas. Pirmiausia reikalinga gana suviliota visų duomenų teiginių vykdymo technika, nes BASIC leidžia DATA sakiniams, kurie tenkina READ sakinį, pasirodyti bet kur šaltinio kode. Galiausiai, jei atsekimas įgalintas, atspausdinamas pėdsakų įrašas ir labai neslėpiantis teiginys s = s.vykdyti (tai, į, menkė); yra iškviečiamas. Gražiausia yra tai, kad visos pastangos sukomponuoti pagrindines sąvokas į lengvai suprantamas klases daro galutinį kodą nereikšmingą. Jei tai nėra nereikšminga, galbūt jūs turite nuojautą, kad gali būti dar vienas būdas suskaidyti savo dizainą.

Apvyniojimas ir tolesnės mintys

Vertėjas buvo sukurtas taip, kad jis galėtų veikti kaip gija, taigi vienu metu jūsų programos erdvėje gali būti kelios COCOA vertėjo gijos. Be to, naudodami funkcijų išplėtimą, galime suteikti priemonę, pagal kurią tos gijos gali sąveikauti viena su kita. Buvo sukurta „Apple II“, o vėliau ir „PC“ bei „Unix“ programa, vadinama „C-robots“, kuri buvo sąveikaujančių „robotinių“ objektų sistema, užprogramuota naudojant paprastą BASIC išvestinę kalbą. Žaidimas man ir kitiems suteikė daugybę pramogų valandų, bet taip pat buvo puikus būdas supažindinti pagrindinius skaičiavimo principus su jaunesniais studentais (kurie klaidingai manė, kad jie tiesiog žaidžia ir nesimoko). „Java“ pagrindu veikiančių vertėjų posistemiai yra daug galingesni nei ankstesni „Java“ atitikmenys, nes jie iškart pasiekiami bet kurioje „Java“ platformoje. COCOA tą pačią dieną, kai dirbau su „Windows 95“ kompiuteriu, veikė „Unix“ sistemose ir „Macintoshes“. Nors „Java“ sumuša nesuderinamumas siūlų ar langų įrankių rinkinio diegime, dažnai nepaisoma: daug kodo „tiesiog veikia“.

$config[zx-auto] not found$config[zx-overlay] not found