Programmēšana

Veidojiet tulku Java - ieviesiet izpildes dzinēju

Iepriekšējais 1 2 3 Lapa 2 Nākamais 2. lapa no 3

Citi aspekti: virknes un masīvi

Divas citas BASIC valodas daļas īsteno COCOA tulks: virknes un masīvi. Vispirms apskatīsim virkņu ieviešanu.

Lai virknes ieviestu kā mainīgos, Izteiksme klase tika modificēta, iekļaujot jēdzienu "virknes" izteicieni. Šī modifikācija notika divu papildinājumu veidā: isString un stringValue. Šo divu jauno metožu avots ir parādīts zemāk.

 String stringValue (Programma pgm) izmet BASICRuntimeError {mest jaunu BASICRuntimeError ("Šim nav virknes attēlojuma."); } boolean isString () {return false; } 

Skaidrs, ka BASIC programmai nav pārāk noderīgi iegūt bāzes izteiksmes virknes vērtību (kas vienmēr ir vai nu ciparu, vai būla izteiksme). No lietderības trūkuma jūs varētu secināt, ka šīs metodes toreiz nepiederēja Izteiksme un piederēja Izteiksme tā vietā. Tomēr, ieliekot šīs divas metodes bāzes klasē, visas Izteiksme objektus var pārbaudīt, vai patiesībā tie ir stīgas.

Vēl viena dizaina pieeja ir skaitlisko vērtību atgriešana kā virknes, izmantojot a StringBuffer objektu, lai ģenerētu vērtību. Tā, piemēram, to pašu kodu varētu pārrakstīt kā:

 String stringValue (Programma pgm) izmet BASICRuntimeError {StringBuffer sb = new StringBuffer (); sb.append (this.value (pgm)); atgriezties sb.toString (); } 

Un, ja tiek izmantots iepriekš minētais kods, varat izslēgt isString jo katra izteiksme var atgriezt virknes vērtību. Turklāt jūs varat modificēt vērtība metodi, lai mēģinātu atgriezt skaitli, ja izteiksme tiek novērtēta kā virkne, palaižot to caur valueOf metode java.lang.Dubulta. Daudzās valodās, piemēram, Perl, TCL un REXX, šāda veida amorfā rakstīšana tiek izmantota ļoti izdevīgi. Abas pieejas ir derīgas, un jums jāizdara izvēle, pamatojoties uz tulka dizainu. Programmā BASIC tulkotājam ir jāatgriež kļūda, kad virknei tiek piešķirts skaitliskais mainīgais, tāpēc es izvēlējos pirmo pieeju (atgriežot kļūdu).

Attiecībā uz masīviem ir dažādi veidi, kā varat noformēt savu valodu, lai tos interpretētu. C izmanto kvadrātiekavas ap masīva elementiem, lai atšķirtu masīva indeksa atsauces no funkciju atsaucēm, kuru argumentos ir iekavas. Tomēr valodas dizaineri BASIC izvēlējās iekavas izmantot gan funkcijām, gan masīviem tā, kad teksts VĀRDS (V1, V2) Parsētājs redz, tas var būt vai nu funkciju izsaukums, vai masīva atsauce.

Leksiskais analizators izšķir marķierus, kuriem seko iekavas, vispirms pieņemot, ka tie ir funkcijas, un to pārbaudot. Tad tas turpina redzēt, vai tie ir atslēgvārdi vai mainīgie. Šis lēmums neļauj jūsu programmai definēt mainīgo ar nosaukumu "SIN". Jebkuru mainīgo, kura nosaukums atbilda funkcijas nosaukumam, leksiskais analizators tā vietā atgriezīs kā funkcijas marķieri. Otrais leksiskā analizatora izmantotais triks ir pārbaudīt, vai mainīgā nosaukumam uzreiz seko "(". Ja tas tā ir, analizators pieņem, ka tā ir masīva atsauce. Parsējot to leksiskajā analizatorā, mēs izslēdzam virkni "MYARRAY (2)'netiks interpretēts kā derīgs masīvs (ņemiet vērā atstarpi starp mainīgā nosaukumu un atvērto iekavu).

Galīgais masīvu ieviešanas triks ir Mainīgs klasē. Šī klase tiek izmantota mainīgā gadījumam, un, kā es to aplūkoju pagājušā mēneša slejā, tā ir Žetons. Tomēr tam ir arī daži mehānismi masīvu atbalstam, un to es parādīšu tālāk:

klases mainīgais paplašina marķieri {// Juridisko mainīgo apakštipi galīgais statiskais int NUMBER = 0; galīgā statiskā int STRING = 1; galīgais statiskais int NUMBER_ARRAY = 2; galīgā statiskā int STRING_ARRAY = 4; Stīgas nosaukums; int apakštips; / * * Ja mainīgais atrodas simbolu tabulā, šīs vērtības * tiek inicializētas. * / int ndx []; // masīvu indeksi. int mult []; // masīvu reizinātāji dubultā nArrayValues ​​[]; Stīgu sArrayValues ​​[]; 

Iepriekš minētais kods parāda ar mainīgo saistītos instances mainīgos, tāpat kā ConstantExpression klasē. Jāizvēlas izmantojamo klašu skaits pret klases sarežģītību. Viena dizaina izvēle varētu būt a Mainīgs klase, kurā ir tikai skalāri mainīgie un pēc tam pievienojiet Masīvs Mainīgs apakšklase, lai risinātu masīvu sarežģījumus. Es izvēlējos tos apvienot, skalāros mainīgos lielākoties pārvēršot 1. garuma masīvos.

Izlasot iepriekš minēto kodu, tiks parādīti masīva indeksi un reizinātāji. Tie ir šeit, jo BASIC daudzdimensionālie masīvi tiek ieviesti, izmantojot vienu lineāru Java masīvu. Java masīva lineārais indekss tiek aprēķināts manuāli, izmantojot reizinātāja masīva elementus. BASIC programmā izmantoto indeksu derīgums tiek pārbaudīts, salīdzinot tos ar maksimālo likumīgo indeksu indeksos. ndx masīvs.

Piemēram, BASIC masīvā ar trim izmēriem 10, 10 un 8 vērtības 10, 10 un 8 tiek saglabātas ndx. Tas ļauj izteiksmes vērtētājam pārbaudīt nosacījumu "indekss ārpus robežām", salīdzinot programmā BASIC izmantoto skaitli ar maksimālo likumīgo skaitu, kas tagad ir saglabāts ndx. Mūsu piemērā esošajā reizinātāja masīvā būtu vērtības 1, 10 un 100. Šīs konstantes apzīmē skaitļus, kurus izmanto, lai kartētu no daudzdimensiju masīva indeksa specifikācijas lineārā masīva indeksa specifikācijā. Faktiskais vienādojums ir:

Java indekss = Index1 + Index2 * Maksimālais Index1 + Index3 lielums * (Index1 maksimālais izmērs * MaxSizeIndex 2)

Nākamais Java masīvs Mainīgs klase ir parādīta zemāk.

 Izteiksme paredz []; 

The expns masīvs tiek izmantots, lai risinātu masīvus, kas rakstīti kā "A (10 * B, i). "Tādā gadījumā indeksi faktiski ir izteiksmes, nevis konstantes, tāpēc atsaucē ir jāietver norādes uz tām izteiksmēm, kuras tiek vērtētas izpildes laikā. Visbeidzot, ir šis diezgan neglītā izskata koda gabals, kas indeksu aprēķina atkarībā no tika nodota programmā. Šī privātā metode ir parādīta zemāk.

 private int computeIndex (int ii []) met BASICRuntimeError {int nobīde = 0; if ((ndx == null) || (ii.length! = ndx.length)) mest jaunu BASICRuntimeError ("Nepareizs indeksu skaits."); for (int i = 0; i <ndx.length; i ++) {if (((ii [i] ndx [i]))) mest jaunu BASICRuntimeError ("Indekss ārpus diapazona."); nobīde = nobīde + (ii [i] -1) * mult [i]; } atgriešanās nobīde; } 

Apskatot iepriekš minēto kodu, jūs ievērosiet, ka kods vispirms pārbauda, ​​vai, atsaucoties uz masīvu, tika izmantots pareizais indeksu skaits un pēc tam katrs indekss atradās šī indeksa likumīgajā diapazonā. Ja tiek atklāta kļūda, tulks tiek izmests ar izņēmumu. Metodes numValue un stringValue atgriež vērtību no mainīgā attiecīgi kā skaitli vai virkni. Šīs divas metodes ir parādītas zemāk.

 double numValue (int ii []) izmet BASICRuntimeError {return nArrayValues ​​[computeIndex (ii)]; } String stringValue (int ii []) izmet BASICRuntimeError {if (subType == NUMBER_ARRAY) return "" + nArrayValues ​​[computeIndex (ii)]; atgriezt sArrayValues ​​[computeIndex (ii)]; } 

Mainīgā vērtības iestatīšanai ir papildu metodes, kas šeit nav parādītas.

Slēpjot lielu daļu katra gabala ieviešanas sarežģītības, kad beidzot pienāk laiks izpildīt BASIC programmu, Java kods ir diezgan vienkāršs.

Palaist kodu

Kods BASIC paziņojumu interpretēšanai un to izpildei ir ietverts

palaist

metode

Programma

klasē. Šīs metodes kods ir parādīts zemāk, un es to izietu, lai norādītu uz interesantajām daļām.

 1 publiska tukšuma izpilde (InputStream in, OutputStream out) izmet BASICRuntimeError {2 PrintStream pout; 3 Uzskaitījums e = stmts.elements (); 4 stmtStack = jauna kaudze (); // pieņem, ka nav sakrautu paziņojumu ... 5 dataStore = new Vector (); // ... un nav lasāmu datu. 6 datiPtr = 0; 7 paziņojums s; 8 9 vars = new RedBlackTree (); 10 11 // ja programma vēl nav derīga. 12 if (! E.hasMoreElements ()) 13 atgriežas; 14 15 if (out of PrintStream gadījums) {16 pout = (PrintStream) out; 17} else {18 pout = new PrintStream (out); 19} 

Iepriekš minētais kods parāda, ka palaist metode prasa InputStream un an OutputStream lietošanai kā izpildes programmas "konsole". 3. rindā uzskaitījuma objekts e ir iestatīts uz nosaukto kolekciju paziņojumu kopu stmts. Šai kolekcijai es izmantoju binārā meklēšanas koka variāciju, ko sauc par "sarkanmelnu" koku. (Lai iegūtu papildinformāciju par bināro meklēšanas kokiem, skatiet manu iepriekšējo sleju par vispārīgo kolekciju veidošanu.) Pēc tam tiek izveidotas divas papildu kolekcijas - viena, izmantojot Kaudze un viens, izmantojot a Vector. Steks tiek izmantots tāpat kā kaudze jebkurā datorā, bet vektors tiek izmantots tieši DATA paziņojumiem programmā BASIC. Galīgā kolekcija ir vēl viens sarkanmelns koks, kurā glabājas atsauces uz mainīgajiem, ko definējusi programma BASIC. Šis koks ir simbolu tabula, kuru programma izmanto izpildes laikā.

Pēc inicializācijas tiek iestatītas ievades un izvades straumes un pēc tam, ja e nav null, mēs sākam apkopot visus deklarētos datus. Tas tiek darīts, kā parādīts nākamajā kodā.

 / * Vispirms mēs ielādējam visus datu paziņojumus * / while (e.hasMoreElements ()) {s = (Statement) e.nextElement (); if (s.atslēgvārds == Paziņojums.DATI) {s.izpilda (this, in, pout); }} 

Iepriekš minētā cilpa vienkārši aplūko visus paziņojumus, un visi tajā atrastie DATA paziņojumi tiek izpildīti. Katra DATA priekšraksta izpilde ievieto ar šo paziņojumu deklarētās vērtības dataStore vektors. Tālāk mēs izpildām pareizo programmu, kas tiek veikta, izmantojot šo nākamo koda daļu:

 e = stmts.elementi (); s = (paziņojums) e.nextElement (); darīt {int yyy; / * Skrienot mēs izlaižam Datu pārskatus. * / mēģiniet {yyy = in.available (); } nozveja (IOException ez) {yyy = 0; } if (gggg! = 0) {pout.println ("Apstājās:" + s); grūdiens (-i); pārtraukums; } if (s.atslēgvārds! = Paziņojums.DATA) {if (traceState) {s.trace (this, (traceFile! = null)? traceFile: pout); } s = s.izpildīt (tas, iekšā, menca); } else s = nextStatement (s); } kamēr (s! = nulle); } 

Kā redzat iepriekš redzamajā kodā, pirmais solis ir atkārtota inicializēšana e. Nākamais solis ir iegūt pirmo paziņojumu mainīgajā s un pēc tam ievadīt izpildes loku. Ir zināms kods, lai pārbaudītu gaidāmo ievadi ievades straumē, lai ļautu pārtraukt programmas virzību, ierakstot programmu, un pēc tam cilpa pārbauda, ​​vai izpildāmais paziņojums būtu DATA paziņojums. Ja tā ir, cilpa izlaiž paziņojumu, jo tas jau tika izpildīts. Vispirms ir nepieciešama diezgan samocīta visu datu pārskatu izpildes tehnika, jo BASIC ļauj DATA paziņojumiem, kas atbilst READ priekšrakstam, parādīties jebkur avota kodā. Visbeidzot, ja izsekošana ir iespējota, tiek izdrukāts izsekošanas ieraksts un ļoti neizteiksmīgs paziņojums s = s.izpildīt (tas, iekšā, menca); tiek izsaukts. Skaistums ir tas, ka visi centieni iekapsulēt pamatjēdzienus viegli saprotamās klasēs padara galīgo kodu par triviālu. Ja tas nav mazsvarīgi, iespējams, jums ir nojausma, ka varētu būt vēl viens veids, kā sadalīt savu dizainu.

Iesaiņošana un turpmākās domas

Tulks tika izveidots tā, lai tas varētu darboties kā pavediens, tādējādi vienlaikus jūsu programmas telpā vienlaikus var darboties vairāki COCOA tulka pavedieni. Turklāt, izmantojot funkciju paplašināšanu, mēs varam nodrošināt līdzekli, ar kuru šie pavedieni var mijiedarboties savā starpā. Bija Apple II un vēlāk PC un Unix programma ar nosaukumu C-robots, kas bija mijiedarbojošu "robotu" entītiju sistēma, kas tika ieprogrammēta, izmantojot vienkāršu BASIC atvasinājumu valodu. Spēle man un citiem sniedza daudzas izklaides stundas, bet bija arī lielisks veids, kā jaunākiem studentiem (kuri kļūdaini uzskatīja, ka viņi vienkārši spēlē un nemācās) iepazīstināt ar skaitļošanas pamatprincipiem. Java balstītas tulku apakšsistēmas ir daudz jaudīgākas nekā iepriekšējās Java kolēģes, jo tās uzreiz ir pieejamas jebkurā Java platformā. COCOA darbojās Unix sistēmās un Macintoshes tajā pašā dienā, kad es sāku strādāt ar datoru, kura pamatā ir Windows 95. Kaut arī Java tiek pārspēta ar nesavienojamību pavedienu vai logu rīkkopa ieviešanā, bieži tiek aizmirsts: daudz kodu "vienkārši darbojas".

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