Ohjelmointi

Etsitkö Java- ja lex-tiedostoja? Et tunne Jackiä

Sun on julkaissut Jackin, uuden Java-kielellä kirjoitetun työkalun, joka luo automaattisesti jäsentimet kokoamalla tekstitiedostoon tallennetun korkean tason kieliopin määrittelyn. Tämä artikkeli toimii johdantona tähän uuteen työkaluun. Artikkelin ensimmäinen osa kattaa lyhyen johdannon automaattiseen jäsentäjien luomiseen ja ensimmäiset kokemukseni niistä. Sitten artikkeli keskittyy Jackiin ja kuinka voit käyttää sitä jäsentäjien ja näiden parsereiden kanssa rakennettujen sovellusten luomiseen korkean tason kielioppisi perusteella.

Automaattinen kääntäjän jäsennin

Jäsennys on yksi yleisimmistä tietokoneohjelman komponenteista. Se muuntaa tekstin, jonka ihmiset voivat lukea, tietokonerakenteiksi, joita kutsutaan jäsennyspuiksi, jotka tietokone ymmärtää. Muistan selvästi johdannon automaattiseen jäsentäjien luomiseen: Olin yliopistossa suorittanut luokan kääntäjän rakentamisesta. Vaimoni avustuksella olin kirjoittanut yksinkertaisen kääntäjän, joka pystyi muuttamaan luokalle tarkoitetulla kielellä kirjoitetut ohjelmat suoritettaviksi ohjelmiksi. Muistan, että tunsin olevani hyvin saavutettu siinä vaiheessa.

Ensimmäisessä "todellisessa" työssäni yliopiston jälkeen sain tehtävän luoda uusi grafiikan käsittelykieli, joka koottaisiin grafiikan apuprosessorin komentoihin. Aloitin juuri sävelletyllä kieliopilla ja valmistauduin aloittamaan kääntäjän kokoamisen monen viikon projektissa. Sitten ystäväni näytti minulle Unix-apuohjelmia lex ja yacc. Lex - rakennettu leksikaalianalysaattoreita säännöllisistä lausekkeista ja yacc pienensi kieliopin määrittelyn taulukkopohjaiseksi kääntäjäksi, joka pystyi tuottamaan koodia, kun se oli jäsennellyt kyseisen kieliopin tuotokset. käytin lex ja yacc, ja alle viikossa kääntäjäni oli toiminnassa! Myöhemmin Free Software Foundation -säätiön GNU-projekti tuotti "parannettuja" versioita lex ja yacc - nimetty joustava ja biisoni - käytettäväksi alustoilla, jotka eivät ole käyttäneet johdannaista Unix-käyttöjärjestelmästä.

Automaattisen jäsentäjien sukupolven maailma eteni jälleen, kun Terrence Parr, silloinen opiskelija Purdue-yliopistossa, loi Purdue Compiler Construction Tool Setin tai PCCTS: n. Kaksi PCCTS-komponenttia - DFA ja ANTLR - tarjoavat samat toiminnot kuin lex ja yacc; kuitenkin kieliopit ANTLR hyväksyy ovat LL (k) -kielioppeja toisin kuin LALR-kieliopit yacc. Lisäksi PCCTS: n tuottama koodi on paljon luettavampi kuin sen tuottama koodi yacc. Luomalla koodia, joka on helpommin luettavissa, PCCTS helpottaa koodia lukevan ihmisen ymmärtämään, mitä eri kappaleet tekevät. Tämä ymmärtäminen voi olla välttämätöntä, kun yritetään diagnosoida virheitä kieliopin määrittelyssä. PCCTS kehitti nopeasti joukon ihmisiä, joiden mielestä tiedostoja oli helpompi käyttää kuin yacc.

Automaattisen jäsentimen luomisen voima on, että se antaa käyttäjille mahdollisuuden keskittyä kielioppiin ja olla huolimatta toteutuksen oikeellisuudesta. Tämä voi olla valtava aikaa säästävä sekä yksinkertaisissa että monimutkaisissa projekteissa.

Jack astuu lautaselle

Pidän työkalut niiden ratkaiseman ongelman yleisyyden perusteella. Koska tekstinsyötön jäsentämistä koskeva vaatimus nousee uudestaan ​​ja uudestaan, automaattinen jäsentäjien generointi on melko korkea työkalupakissa. Yhdistettynä Javan nopeaan kehitysjaksoon automaattinen jäsentäjien luonti tarjoaa työkalun kääntäjän suunnitteluun, jota on vaikea voittaa.

Jack (riimi yacc: n kanssa) on PCCTS: n hengessä jäsentäjä, jonka Sun on julkaissut ilmaiseksi Java-ohjelmointiyhteisölle. Jack on poikkeuksellisen helppo työkalu kuvata: Yksinkertaisesti sanottuna, annat sille yhdistettyjä kielioppi- ja lexisääntöjä .jack-tiedostona ja suoritat työkalun, ja se antaa sinulle takaisin Java-luokan, joka jäsentää kyseisen kieliopin. Mikä voisi olla helpompaa?

Jackin saaminen on myös melko helppoa. Ensin lataat kopion Jackin kotisivulta. Tämä tulee sinulle itsestään purettavan Java-luokan muodossa Asentaa. Jackin asentamiseksi sinun on käytettävä tätä Asentaa luokka, joka Windows 95-koneella tehdään komennolla: C:> Java-asennus.

Yllä esitetty komento olettaa, että java komento on komentopolulla ja että luokan polku on määritetty asianmukaisesti. Jos yllä oleva komento ei toiminut tai et ole varma, onko asiat määritetty oikein, avaa MS-DOS-ikkuna kulkemalla Käynnistä-> Ohjelmat-> MS-DOS-kehote -valikkokohdat. Jos Sun JDK on asennettu, voit kirjoittaa nämä komennot:

C:> polku C: \ java \ bin;% polku% C:> aseta CLASSPATH =; c: \ java \ lib \ class.zip 

Jos Symantec Cafe -versio 1.2 tai uudempi on asennettu, voit kirjoittaa nämä komennot:

C:> polku C: \ kahvila \ java \ bin;% polku% 

Luokan polku on jo määritettävä tiedostoon nimeltä sc.ini kahvilan roskakorihakemistossa.

Kirjoita seuraavaksi Java-asennus komento ylhäältä. Asennusohjelma kysyy, mihin hakemistoon haluat asentaa, ja sen alle luodaan Jack-alihakemisto.

Jackin käyttö

Jack on kirjoitettu kokonaan Java-kielellä, joten Jack-luokkien saaminen tarkoittaa, että tämä työkalu on heti käytettävissä kaikilla alustoilla, jotka tukevat Java-virtuaalikonetta. Se tarkoittaa kuitenkin myös sitä, että Windows-laatikoissa sinun on suoritettava Jack komentoriviltä. Oletetaan, että valitsit hakemiston nimen JavaTools, kun asennit Jackin järjestelmään. Jos haluat käyttää Jackiä, sinun on lisättävä Jackin luokat luokan polulle. Voit tehdä tämän omassa autoexec.bat tiedostossa tai .cshrc tiedosto, jos olet Unix-käyttäjä. Kriittinen komento on jotain alla olevan rivin kaltaista:

C:> set CLASSPATH =; C: \ JavaTools \ Jack \ java; C: \ java \ lib \ class.zip 

Huomaa, että Symantec Cafen käyttäjät voivat muokata sc.ini tiedosto ja sisällytä Jack-luokat siellä, tai he voivat asettaa CLASSPATH nimenomaisesti kuten yllä on esitetty.

Ympäristömuuttujan asettaminen yllä esitetyllä tavalla tuo Jack-luokat CLASSPATH välillä "." (nykyinen hakemisto) ja Java-perusjärjestelmäluokat. Jackin pääluokka on COM.sun.labs.jack.Main. Isot kirjaimet ovat tärkeitä! Komennossa on täsmälleen neljä isoa kirjainta ('C', 'O', 'M' ja toinen 'M'). Suorita Jack manuaalisesti kirjoittamalla komento:

C:> java COM.sun.labs.jack.Main jäsennin-input.jack

Jos luokkasi polussa ei ole Jack-tiedostoja, voit käyttää tätä komentoa:

C:> java -classpath.; C: \ JavaTools \ Jack \ java; c: \ java \ lib \ class.zip COM.sun.labs.jack.Main parser-input.jack 

Kuten näette, tämä kestää vähän. Kirjoittamisen minimoimiseksi laitan kutsun a: han lepakko tiedoston nimi Jack. Lepakko. Jossain vaiheessa tulevaisuudessa yksinkertainen C-kääreohjelma tulee saataville, ehkä jopa kun luet tätä. Katso Jackin kotisivulta tämän ja muiden ohjelmien saatavuus.

Kun Jack on suoritettu, se luo nykyiseen hakemistoon useita tiedostoja, jotka myöhemmin käännetään jäsentäjääsi. Suurin osa niistä on joko etuliitteellä jäsentimen nimellä tai ne ovat yhteisiä kaikille jäsentäjille. Yksi näistä kuitenkin ASCII_CharStream.java, voi törmätä muihin jäsentäjiin, joten on luultavasti hyvä idea aloittaa hakemistossa, joka sisältää vain .jack tiedosto, jota aiot käyttää jäsentimen luomiseen.

Kun juokset Jackin, jos sukupolvi on sujunut sujuvasti, sinulla on joukko .java tiedostot nykyisessä hakemistossa useilla mielenkiintoisilla nimillä. Nämä ovat parsereitasi. Kehotan teitä avaamaan ne editorilla ja katsomaan niitä. Kun olet valmis, voit kääntää ne komennolla

C:> javac -d. ParserName.java

missä ParserName on nimi, jonka annoit jäsentäjälle syötetiedostossa. Lisää siitä vähän. Jos kaikkia jäsentimesi tiedostoja ei käännetä, voit kirjoittaa karkean voiman menetelmällä:

C:> javac * .java 

Tämä kokoaa kaiken hakemistosta. Tässä vaiheessa uusi jäsentimesi on käyttövalmis.

Jack-jäsentäjän kuvaukset

Jack-jäsentäjän kuvaustiedostoilla on laajennus .jack ja ne on jaettu kolmeen pääosaan: optiot ja perusluokka; leksikaaliset rahakkeet; ja ei-päätelaitteet. Katsotaanpa yksinkertaista jäsentimen kuvausta (tämä sisältyy esimerkkejä Jackin mukana toimitettu hakemisto).

vaihtoehdot {LOOKAHEAD = 1; } PARSER_BEGIN (Yksinkertainen 1) julkinen luokka Yksinkertainen 1 {public static void main (String args []) heittää ParseErrorin { Yksinkertainen 1 jäsennin = uusi Yksinkertainen 1(System.in); jäsennin.Input (); }} PARSER_END (Yksinkertainen 1) 

Muutama ensimmäinen rivi yllä kuvaa jäsentimen vaihtoehtoja; tässä tapauksessa KATSOA ETEENPÄIN on asetettu 1. Siellä voidaan asettaa myös muita vaihtoehtoja, kuten diagnostiikka, Java Unicode -käsittely ja niin edelleen. Seuraamalla vaihtoehtoja tulee jäsentimen perusluokka. Kaksi tagia PARSER_BEGIN ja PARSER_END haarukoi luokka, josta tulee tuloksena olevan jäsentimen Java-peruskoodi. Huomaa, että jäsenninmäärityksessä käytetty luokan nimi on pakko olla sama tämän osan alussa, keskellä ja lopussa. Yllä olevassa esimerkissä olen lisännyt luokan nimen lihavoituna, jotta tämä olisi selvää. Kuten yllä olevasta koodista näet, tämä luokka määrittää staattisen tärkein menetelmää, jotta Java-tulkki voi kutsua luokan komentoriville. tärkein menetelmä yksinkertaistaa uuden jäsentimen syöttövirran kanssa (tässä tapauksessa System.in) ja käyttää sitten Tulo menetelmä. Tulo menetelmä on kieliopissamme ei-terminaali, ja se määritellään EBNF-elementin muodossa. EBNF on lyhenne sanoista Extended Backus-Naur Form. Backus-Naur-muoto on tapa määrittää kontekstittomat kieliopit. Eritelmä koostuu a terminaali vasemmalla puolella tuotantosymboli, joka on tyypillisesti ":: =", ja yksi tai useampi tuotannot oikealla puolella. Käytetty merkintätapa on tyypillisesti jotain tällaista:

 Avainsana :: = "jos" | "sitten" | "muu" 

Tämän lukisi olevan " Avainsana terminaali on yksi merkkijono-literaaleista "jos", "sitten" tai "muu". "Jackissa tätä muotoa laajennetaan, jotta vasemmanpuoleinen osa voidaan esittää menetelmällä, ja vaihtoehtoiset laajennukset voidaan esittää säännölliset lausekkeet tai muut ei-päätteet. Jatkamalla yksinkertaista esimerkkiä, tiedosto sisältää seuraavat määritelmät:

void Input (): {} {MatchedBraces () "\ n"} void MatchedBraces (): {} {"{" [MatchedBraces ()] "}"}} 

Tämä yksinkertainen jäsentäjä jäsentää alla olevan kieliopin:

Tulo::=Yhteensopivat renkaat "\ n"
Yhteensopivat renkaat::="{" [ Yhteensopivat renkaat ] "}"

Olen käyttänyt kursivoitua näyttämään ei-päätteet tuotannon oikealla puolella ja lihavoitua osoittamaan literaaleja. Kuten näette, kielioppi yksinkertaisesti jäsentää sovitetut aaltosulkujoukot "{" ja "}". Jack-tiedostossa on kaksi tuotantoa kuvaamaan tätä kielioppia. Ensimmäinen terminaali, Tulo, määritellään tämän määritelmän mukaan kolmeksi eräksi peräkkäin: a Yhteensopivat renkaat pääte, uuden rivin merkki ja tiedoston lopun tunnus. Jack määrittelee tunnuksen, jotta sinun ei tarvitse määrittää sitä käyttöjärjestelmällesi.

Kun tämä kielioppi luodaan, tuotosten vasen puoli muutetaan menetelmiksi Yksinkertainen 1 luokka; kun se on koottu, Yksinkertainen 1 luokka lukee merkkejä Järjestelmä.sisään ja tarkistaa, että ne sisältävät vastaavan sarjan aaltosulkeita. Tämä saavutetaan käyttämällä luotua menetelmää Tulo, joka muunnetaan luomisprosessilla menetelmäksi, joka jäsentää Tulo ei-terminaalinen. Jos jäsentäminen epäonnistuu, menetelmä heittää poikkeuksen Jäsennysvirhe, jonka päärutiini voi saada kiinni ja sitten valittaa, jos se niin haluaa.

Tietysti on enemmän. Lohko, jonka rajaavat "{" ja "}" päätelaitteen nimen jälkeen - joka on tässä esimerkissä tyhjä - voi sisältää mielivaltaista Java-koodia, joka lisätään generoidun menetelmän eteen. Sitten jokaisen laajennuksen jälkeen on toinen valinnainen lohko, joka voi sisältää mielivaltaisen Java-koodin, joka suoritetaan, kun jäsennin vastaa kyseistä laajennusta.

Monimutkaisempi esimerkki

Joten entä esimerkki, joka on hieman monimutkaisempi? Harkitse seuraavaa kielioppia, joka on jälleen jaoteltu paloiksi. Tämä kielioppi on suunniteltu tulkitsemaan matemaattisia yhtälöitä käyttämällä neljää perusoperaattoria - yhteenlasku, kertolasku, vähennyslasku ja jako. Lähde löytyy täältä:

vaihtoehdot {LOOKAHEAD = 1; } PARSER_BEGIN (Calc1) julkinen luokka Calc1 {public static void main (String args []) heittää ParseError {Calc1 parser = uusi Calc1 (System.in); while (true) {System.out.print ("Anna lauseke:"); System.out.flush (); kokeile {switch (parser.one_line ()) {tapaus -1: System.exit (0); oletus: tauko; }} catch (ParseError x) {System.out.println ("Poistuminen"); heittää x; }}}} PARSER_END (Laskenta1) 

Ensimmäinen osa on melkein sama kuin Yksinkertainen 1, paitsi että päärutiini kutsuu nyt päätelaitetta yksi linja toistuvasti, kunnes se ei jäsennä. Seuraavaksi tulee seuraava koodi:

IGNORE_IN_BNF: {} "" TOKEN: {} {} TOKEN: / * KÄYTTÄJÄT * / {} TOKEN: {} 

Nämä määritelmät kattavat peruspäätteet, joissa kielioppi on määritelty. Ensimmäinen nimetty IGNORE_IN_BNF, on erityinen tunnus. Kaikki jäsentäjän lukemat merkit, jotka vastaavat merkinnässä määritettyjä merkkejä IGNORE_IN_BNF tunnus hylätään hiljaa. Kuten esimerkistämme näet, tämä saa jäsentimen jättämään välilyönnit, välilehdet ja rivinvaihtomerkit syötteessä.

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