Programavimas

Leksinė analizė ir „Java“: 1 dalis

Leksinė analizė ir analizavimas

Rašant „Java“ programas, vienas iš dažniausiai pasitaikančių dalykų, kurį turėsite sukurti, yra analizatorius. Analizatoriai svyruoja nuo paprastų iki sudėtingų ir yra naudojami viskam, pradedant komandinės eilutės parinkčių žvalgymu ir baigiant Java šaltinio kodo aiškinimu. Į „JavaWorld“Gruodžio mėn. leidime parodžiau jums Jacką - automatinį analizatorių generatorių, kuris aukšto lygio gramatikos specifikacijas paverčia „Java“ klasėmis, kurios įgyvendina tose specifikacijose aprašytą analizatorių. Šį mėnesį aš jums parodysiu šaltinius, kuriuos „Java“ teikia tikslinių leksikos analizatorių ir analizatorių rašymui. Šie šiek tiek paprastesni analizatoriai užpildo spragą tarp paprasto eilučių palyginimo ir sudėtingų Jacko sudarytų gramatikų.

Leksinių analizatorių paskirtis yra surinkti įvesties simbolių srautą ir juos iššifruoti į aukštesnio lygio žetonus, kuriuos gali suprasti analizatorius. Analizatoriai sunaudoja leksinio analizatoriaus išvestį ir veikia analizuodami grąžinamų žetonų seką. Analizatorius suderina šias sekas su galutine būsena, kuri gali būti viena iš galimų būsenų. Galinės būsenos apibrėžia tikslus analizatoriaus. Pasiekus galutinę būseną, programa, naudojanti analizatorių, atlieka tam tikrą veiksmą - arba sukuria duomenų struktūras, arba įvykdo tam tikrą veiksmo kodą. Be to, analizatoriai iš apdorotų žetonų sekos gali nustatyti, kada negalima pasiekti jokios teisinės galinės būsenos; tuo metu analizatorius nustato dabartinę būseną kaip klaidos būseną. Programa turi nuspręsti, kokių veiksmų imtis, kai analizatorius nustato galinę arba klaidos būseną.

Į standartinę „Java“ klasių bazę įeina pora leksinių analizatorių klasių, tačiau joje nėra apibrėžtos bendrosios paskirties analizatorių klasės. Šiame stulpelyje aš nuodugniai išnagrinėsiu leksinius analizatorius, pateiktus su „Java“.

Java leksiniai analizatoriai

„Java“ kalbos specifikacijos 1.0.2 versija apibrėžia dvi leksikos analizatorių klases, „StringTokenizer“ ir „StreamTokenizer“. Iš jų vardų galite tai padaryti „StringTokenizer“ naudoja Stygos objektai kaip jo įvestis ir „StreamTokenizer“ naudoja „InputStream“ objektai.

„StringTokenizer“ klasė

Iš dviejų galimų leksinių analizatorių klasių yra lengviausia suprasti „StringTokenizer“. Kai sukursite naują „StringTokenizer“ objektas, konstruktoriaus metodas nominaliai paima dvi reikšmes - įvesties eilutę ir atribotojo eilutę. Tada klasė sukuria žetonų seką, kuri žymi simbolius tarp atribotojų simbolių.

Kaip leksinis analizatorius, „StringTokenizer“ galima oficialiai apibrėžti taip, kaip parodyta žemiau.

[~ delim1, delim2, ..., delimN] :: Žetonas 

Šis apibrėžimas susideda iš taisyklingos išraiškos, atitinkančios kiekvieną simbolį išskyrus skiriamieji simboliai. Visi gretimi atitikimo simboliai surenkami į vieną žetoną ir grąžinami kaip žetonas.

Dažniausiai naudojamas „StringTokenizer“ klasė skirta išskirti parametrų rinkinį, pavyzdžiui, kableliais atskirtą skaičių sąrašą. „StringTokenizer“ yra idealus atliekant šį vaidmenį, nes pašalina separatorius ir grąžina duomenis. „StringTokenizer“ klasėje taip pat pateikiamas sąrašas, kuriame yra „nuliniai“ žetonai, identifikavimo mechanizmas. Nenaudojamus žetonus naudosite programose, kuriose kai kurie parametrai turi numatytąsias reikšmes arba kurių nebūtina pateikti visais atvejais.

Žemiau esanti programėlė yra paprasta „StringTokenizer“ treniruoklis. StringTokenizer programėlės šaltinis yra čia. Norėdami naudoti programėlę, įveskite analizuojamą tekstą į įvesties eilutės sritį, tada skyriklio eilutės srityje įveskite eilutę, susidedančią iš skiriamųjų simbolių. Galiausiai spustelėkite Tokenize! mygtuką. Rezultatas bus rodomas žetonų sąraše po įvesties eilute ir bus sutvarkytas kaip vienas žetonas kiekvienoje eilutėje.

Norint pamatyti šią programėlę, reikia „Java“ palaikančios naršyklės.

Panagrinėkime kaip eilutę „a, b, d“, perduodamą a „StringTokenizer“ objektas, sukonstruotas kableliu (,) kaip skiriamąjį simbolį. Jei šias vertes įdėsite į aukščiau esantį treniruoklio programėlę, pamatysite, kad Tokenizer objektas grąžina eilutes „a“, „b“ ir „d“. Jei ketinote pažymėti, kad trūksta vieno parametro, galbūt nustebote, kad prieigos raktų sekoje to nematote. Galimybę aptikti trūkstamus žetonus įgalina „Return Separator“ loginė banga, kurią galima nustatyti, kai kuriate Tokenizer objektas. Kai šis parametras nustatytas, kai Tokenizer sukonstruotas, kiekvienas separatorius taip pat grąžinamas. Pirmiau esančioje programėlėje pažymėkite žymės langelį „Grąžinimo separatorius“, o eilutę ir skyriklį palikite ramybėje. Dabar Tokenizer grąžina „a, comma, b, comma, comma and d“. Atkreipdami dėmesį į tai, kad gausite du skiriamuosius simbolius iš eilės, galite nustatyti, kad įvesties eilutėje buvo „null“ prieigos raktas.

Apgaulė sėkmingai naudoti „StringTokenizer“ analizatoriuje apibrėžia įvestį taip, kad atribotuvo simbolis nebūtų rodomas duomenyse. Aišku, jūs galite išvengti šio apribojimo, sukurdami jį savo programoje. Toliau pateiktą metodo apibrėžimą galima naudoti kaip programėlės dalį, kurios parametrų sraute spalva priimama raudonos, žalios ir mėlynos spalvos pavidalu.

 / ** * Analizuokite formos „10,20,30“ parametrą kaip * RGB paketą spalvos vertei. * / 1 Color getColor (String name) {2 Stygos duomenys; 3 „StringTokenizer“ st; 4 int raudona, žalia, mėlyna; 5 6 duomenys = getParameter (vardas); 7 if (duomenys == null) 8 grąžina null; 9 10 st = naujas StringTokenizer (duomenys, ","); 11 pabandykite {12 raudona = Sveikasis skaičius.parseInt (st.nextToken ()); 13 žalia = sveikasis skaičius.parseInt (st.nextToken ()); 14 mėlyna = sveikasis skaičius.parseInt (st.nextToken ()); 15} sugavimas (e išimtis) {16 return null; // (KLAIDOS VALSTYBĖ) negalėjo jos išanalizuoti 17} 18 grąžinti naują Spalva (raudona, žalia, mėlyna); // (PABAIGOS VALSTYBĖ) padaryta. 19} 

Aukščiau pateiktas kodas įgyvendina labai paprastą analizatorių, kuris nuskaito eilutę „skaičius, skaičius, skaičius“ ir grąžina naują Spalva objektas. 10 eilutėje kodas sukuria naują „StringTokenizer“ objektas, kuriame yra parametrų duomenys (tarkime, kad šis metodas yra programėlės dalis), ir atskyrimo simbolių sąrašas, sudarytas iš kablelių. Tada 12, 13 ir 14 eilutėse kiekvienas žetonas ištraukiamas iš eilutės ir paverčiamas skaičiumi naudojant sveikąjį skaičių parseInt metodas. Šias konversijas supa a pabandyti / pagauti blokas tuo atveju, jei skaičių eilutės nebuvo teisingi skaičiai arba Tokenizer meta išimtį, nes baigėsi žetonai. Jei visi skaičiai konvertuojami, pasiekiama galutinė būsena ir a Spalva objektas grąžinamas; priešingu atveju pasiekiama klaidos būsena ir niekinis yra grąžinamas.

Vienas iš „StringTokenizer“ klasė yra ta, kad ji lengvai sukraunama. Pažvelkite į įvardytą metodą „getColor“ žemiau, tai yra aukščiau nurodyto metodo 10–18 eilutės.

 / ** * Spalvotą atkarpą „r, g, b“ analizuokite į AWT Spalva objektas. * / 1 Spalva getColor (eilutės duomenys) {2 int raudona, žalia, mėlyna; 3 „StringTokenizer“ st = naujas „StringTokenizer“ (duomenys, „,“); 4 pabandykite {5 raudonas = Sveikasis skaičius.parseInt (st.nextToken ()); 6 žalia = sveikasis skaičius.parseInt (st.nextToken ()); 7 mėlyna = sveikas skaičius.parseInt (st.nextToken ()); 8} pagauti (e išimtis) {9 grąžinti nulį; // (KLAIDOS VALSTYBĖ) negalėjo jos išanalizuoti 10} 11 grąžinti naują Spalva (raudona, žalia, mėlyna); // (PABAIGOS VALSTYBĖ) padaryta. 12} 

Šiek tiek sudėtingesnis analizatorius parodytas žemiau esančiame kode. Šis analizatorius yra įgyvendinamas metode „getColors“, kuris apibrėžiamas kaip grąžinti masyvą Spalva objektai.

 / ** * Išanalizuokite spalvų rinkinį „r1, g1, b1: r2, g2, b2: ...: rn, gn, bn“ į * AWT Color objektų masyvą. * / 1 Spalva [] getColors (Styginių duomenys) {2 Vektorių sankaupa = naujas Vektorius (); 3 Spalva cl, rezultatas []; 4 „StringTokenizer“ st = naujas „StringTokenizer“ (duomenys, „:“); 5, kol (st.hasMoreTokens ()) {6 cl = getColor (st.nextToken ()); 7 if (cl! = Null) {8 akumul.addElement (cl); 9} else {10 System.out.println ("Klaida - bloga spalva."); 11} 12} 13 if (umul.size () == 0) 14 grąžinti nulį; 15 rezultatas = nauja spalva [akumuliatoriaus dydis ()]; 16 už (int i = 0; i <akumuliatoriaus dydis (); i ++) {17 rezultatas [i] = (spalva) akumuliacijos elementas at (i); 18} 19 grąžinimo rezultatas; 20} 

Aukščiau aprašytu metodu, kuris tik šiek tiek skiriasi nuo „getColor“ metodas, kodas 4–12 eilutėse sukuria naują Tokenizer išgauti žetonus, kuriuos supa dvitaškis (:) simbolis. Kaip galite perskaityti metodo dokumentacijos komentare, šis metodas tikisi, kad spalvų rinkiniai bus atskirti dvitaškiais. Kiekvienas skambutis kitasToken viduje konors „StringTokenizer“ klasė grąžins naują žetoną, kol eilutė bus išnaudota. Grąžintos žetonai bus kableliais atskirtos skaičių eilutės; šios žetonų eilutės yra tiekiamos „getColor“, kuri tada išgauna spalvą iš trijų skaičių. Kuriant naują „StringTokenizer“ objektą naudojant kito grąžintą žetoną „StringTokenizer“ objektas leidžia mūsų parašytam analizatoriaus kodui šiek tiek patobulinti, kaip jis interpretuoja eilutės įvestį.

Kad ir kaip tai būtų naudinga, jūs galų gale išnaudosite „StringTokenizer“ klasę ir turi pereiti pas didįjį brolį „StreamTokenizer“.

„StreamTokenizer“ klasė

Kaip rodo klasės pavadinimas, a „StreamTokenizer“ objektas tikisi, kad jo indėlis bus iš „InputStream“ klasė. Kaip „StringTokenizer“ aukščiau, ši klasė konvertuoja įvesties srautą į gabalus, kuriuos gali interpretuoti jūsų analizavimo kodas, tačiau tuo panašumas ir baigiasi.

„StreamTokenizer“ yra stalo varomas leksinis analizatorius. Tai reiškia, kad kiekvienam įmanomam įvesties simboliui priskiriama reikšmė, o skaitytuvas naudoja dabartinio simbolio reikšmę nuspręsdamas, ką daryti. Įgyvendinant šią klasę, simboliams priskiriama viena iš trijų kategorijų. Šitie yra:

  • Balta vieta simboliai - jų leksinė reikšmė apsiriboja žodžių atskyrimu

  • Žodis simboliai - jie turėtų būti sujungti, kai jie yra šalia kito žodžio simbolio

  • Paprastas simboliai - juos reikia nedelsiant grąžinti analizatoriui

Įsivaizduokite šios klasės įgyvendinimą kaip paprastą valstybės mašiną, turinčią dvi būsenas - tuščiąja eiga ir kaupti. Kiekvienoje valstybėje įvestis yra simbolis iš vienos iš pirmiau nurodytų kategorijų. Klasė perskaito simbolį, patikrina jo kategoriją ir atlieka tam tikrus veiksmus ir pereina į kitą būseną. Šioje lentelėje parodyta ši būsenos mašina.

ValstijaĮvestisVeiksmasNauja valstybė
tuščiąja eigažodis charakterisatstumti charakterįkaupti
paprastas charakterisgrįžimo personažastuščiąja eiga
balta vieta charakterissunaudoti charakterįtuščiąja eiga
kauptižodis charakterispridėti prie dabartinio žodžiokaupti
paprastas charakteris

grąžinti dabartinį žodį

atstumti charakterį

tuščiąja eiga
balta vieta charakteris

grąžinti dabartinį žodį

vartoja charakterį

tuščiąja eiga

Šio paprasto mechanizmo viršuje „StreamTokenizer“ klasė prideda keletą euristinių rodiklių. Tai apima skaičių apdorojimą, cituojamų eilučių apdorojimą, komentarų apdorojimą ir eilutės pabaigos apdorojimą.

Pirmasis pavyzdys yra skaičių apdorojimas. Tam tikras simbolių sekas galima interpretuoti kaip skaitinę vertę. Pavyzdžiui, 1, 0, 0,. Ir 0 ženklų seka, esanti greta vienas kito įvesties sraute, reiškia skaitmeninę vertę 100,0. Kai visi skaitmenų simboliai (nuo 0 iki 9), taškinis simbolis (.) Ir minusas (-) yra nurodomi kaip žodis nustatyti „StreamTokenizer“ klasei gali būti liepta interpretuoti žodį, kurį ketinama grąžinti, kaip galimą skaičių. Šis režimas nustatomas iškviečiant parseNumbers metodas žymeklio objekte, kurį jūs iš karto sukūrėte (tai yra numatytasis nustatymas). Jei analizatorius yra kaupimosi būsenoje, tai padarytų kitas simbolis ne būti skaičiaus dalimi, tikrinamas šiuo metu sukauptas žodis, ar jis yra galiojantis skaičius. Jei jis galioja, jis grąžinamas ir skaitytuvas pereina į kitą reikiamą būseną.

Kitas pavyzdys yra cituojamas eilutės apdorojimas. Dažnai pageidautina kaip vieną žetoną perduoti eilutę, kurią supa kabutės simbolis (paprastai dviguba (") arba viena (') citata). „StreamTokenizer“ klasė leidžia nurodyti bet kurį simbolį kaip cituojantį simbolį. Pagal numatytuosius nustatymus jie yra vienos citatos (') ir dvigubos kabutės (") simboliai. Būsenos mašina modifikuojama taip, kad sunaudotų simbolius kaupimo būsenoje, kol bus apdorotas kitas citatos simbolis arba eilutės pabaigos simbolis. cituoju citatos simbolį, analizatorius citatos simbolį, prieš kurį įvesties sraute ir kabutėje yra priešais pasvirasis brūkšnys (\), laiko žodžio simboliu.