Rakenna tulkki Java-kielellä — Toteutusmoottori

niille teistä, jotka juuri liityitte seuraamme, olen parin viime kuukauden aikana keskustellut ”Java in Depth” – palstallani siitä, miten tulkkia voitaisiin rakentaa Javalla. Ensimmäisellä tulkki-palstalla Käsittelimme joitakin tulkin toivottavia ominaisuuksia, toisella palstalla käsittelimme sekä tulkin jäsentämistä että luokkapaketin asettelua tulkin toteuttamiseksi. Tällä palstalla tarkastelemme tulkin pyörittämistä ja siihen tarvittavia tukiluokkia. Lopuksi lopetan sarjan tähän keskusteluun siitä, miten tulkki voidaan kytkeä muihin Java-luokkiin, mikä parantaa heidän kykyjään.

relevanttien bittien tarkistaminen

sallikaa minun aloittaa hahmottelemalla, mitä olemme tähän mennessä käsitelleet, ja tuoda esiin ne suunnittelun osat, jotka tulevat tärkeämmiksi, kun keskustelemme toteutustavasta. Tarkempi kuvaus näistä luokista löytyy aiemmista sarakkeistani tai lähdekoodin linkeistä, jotka ovat

resurssit-osiossa

alla.

tulkin toteutuksessa on kolme perustusluokkaa, Program, Statement ja Expression. Seuraava osoittaa, miten nämä kolme liittyvät toisiinsa:

ohjelma

tämä Program Luokka liimaa yhteen jäsentimen jäsennys-ja suorituskomponentit. Tässä luokassa määritellään kaksi pääasiallista menetelmää, load ja run. load – menetelmä lukee lauseet tulovirrasta ja jäsentää ne lauseiden kokoelmaksi, run – menetelmä iteroi kokoelman yli ja toteuttaa jokaisen lausuman. Program – luokka tarjoaa myös kokoelman muuttujia ohjelman käytettäväksi sekä pinon tietojen tallentamiseen.

lausuma

Statement luokka sisältää yhden jäsennellyn lausuman. Tämä luokka on itse asiassa aliluokitettu tietyntyyppiseksi lausekkeeksi (PRINT, GOTO, IF ja niin edelleen), mutta kaikki lausekkeet sisältävät menetelmän execute, jota kutsutaan lausuman toteuttamiseksi Program Luokka-instanssin yhteydessä.

lauseke

Expression luokka sisältää lausekkeen jäsenpuun. Suorituksen aikana käytetään value – menetelmää lausekkeen arvioimiseksi ja sen arvon palauttamiseksi. Kuten Statement, myös Expression – luokka on suunniteltu ensisijaisesti tietyntyyppisten lausekkeiden alaryhmäksi.

kaikki nämä luokat toimivat yhdessä tulkin pohjana. Program Luokka kapseloi samanaikaisesti jäsennysoperaation ja suoritusoperaation, kun taas Statement ja Expression luokat kapseloivat toteuttamamme kielen varsinaiset laskennalliset käsitteet. Näissä kolmessa rakennustulkkeja käsittelevässä kirjoituksessa esimerkkikieli on ollut perus.

laskennan tilat

tulkissa on kaksi suoritettavaa luokkaa,

Statement

ja

Expression

. Katsotaan ensin

Expression

esiintymät Expression luodaan menetelmällä expression luokassa ParseExpression. ParseExpression – luokka toteuttaa ilmaisun jäsennin tässä tulkinnassa. Tämä luokka on ParseStatement – luokan vertainen, joka käyttää statement – menetelmää PERUSLAUSEIDEN jäsentämiseen. Esiintymillä Expression on sisäinen type, joka tunnistaa, mitä operaattoria esiintymä edustaa, ja kaksi menetelmää, value ja stringValue, jotka palauttavat lausekkeen laskennallisen arvon. Lisäksi, kun lauseke instanssi luodaan, sille annetaan nimellisesti kaksi parametria, jotka edustavat lausekkeen toiminnan vasenta ja oikeaa puolta. Esitetty lähdemuodossa, lausekkeen alkuosa on seuraava:

class Expression { Expression arg1, arg2; int oper; final static int OP_ADD = 1; // Addition '+' final static int OP_SUB = 2; // Subtraction '-' final static int OP_MUL = 3; // Multiplication '*' final static int OP_DIV = 4; // Division '/' final static int OP_BNOT = 19; // Boolean negation '.NOT.' final static int OP_NEG = 20; // Unary minus

kuten yllä olevasta koodista näkyy, on olemassa instanssimuuttujat, operaattorityyppi nimeltä oper, sekä operaation kaksi puoliskoa arg1: ssä ja arg2: ssa ja sitten joitakin vakioita, joilla määritellään eri tyypit. Lisäksi on olemassa kaksi konstruktiota, joita käytetään lausekkeessa jäsennin; nämä luovat uuden lausekkeen kahdesta lausekkeesta. Niiden lähde näkyy alla:

protected Expression(int op, Expression a, Expression b) throws BASICSyntaxError { arg1 = a; arg2 = b; oper = op; /* * If the operator is a boolean, both arguments must be boolean. */ if (op > OP_GE) { if ( (! (arg1 instanceof BooleanExpression)) || (! (arg2 instanceof BooleanExpression)) ) throw new BASICSyntaxError(typeError); } else { if ((arg1 instanceof BooleanExpression) || (arg2 instanceof BooleanExpression)) throw new BASICSyntaxError(typeError); } } protected Expression(int op, Expression a) throws BASICSyntaxError { arg2 = a; oper = op; if ((oper == OP_BNOT) && (! (arg2 instanceof BooleanExpression))) throw new BASICSyntaxError(typeError); }

ensimmäinen konstruktori rakentaa mielivaltaisen lauseke-objektin, ja toinen rakentaa ”unary” lauseke-objektin-kuten unary minus. On huomattava, että jos on vain yksi argumentti, arg2: ta käytetään sen arvon tallentamiseen.

Expression luokassa useimmin käytetty menetelmä on value, joka määritellään seuraavasti:

 double value(Program pgm) throws BASICRuntimeError { switch (oper) { case OP_ADD : return arg1.value(pgm) + arg2.value(pgm); case OP_SUB : return arg1.value(pgm) - arg2.value(pgm); ... etc for all of the other operator types. ...

voit nähdä, että jokainen lauseke objekti edustaa monikkoa, joka koostuu operaattorista ja yhdestä tai kahdesta argumentista. Hauskinta lausekkeen toteutusmoottorin suunnittelussa tällä tavalla on se, että kun rakennat tämän lausekkeiden joukon Expression objektin pohjalta, voit laskea lausekkeen arvon yksinkertaisesti vetoamalla value – menetelmään. value – menetelmä vetoaa rekursiivisesti tämän lausekkeen muodostavien kahden argumentin value – menetelmään, soveltaa operaatiota niihin ja palauttaa tuloksen. Tätä muotoilua käytettiin, jotta ilmaisut olisivat helposti ymmärrettäviä.

luokkarakenteen puhtaana pitämiseksi kaikki laskennalliset yksiköt — vakioista trigonometrisiin funktioihin — ovat alaluokkia Expression. Tämä Lispiltä häpeämättömästi varastettu ajatus kiteyttää täysin käsitteen” aiheuttaa ”arvioinnin tapahtuvan, siitä tosiasiallisesta toteutuksesta” miten ” arviointi tapahtuu. Osoittaaksemme, miten tätä periaatetta sovelletaan, meidän tarvitsee vain tarkastella joitakin erikoistuneita alaluokkia Expression.

vakioita omassa basic-versiossani, jonka nimesin KAAKAOKSI, edustaa luokka ConstantExpression, joka alaluokittaa Expression ja yksinkertaisesti tallentaa numeerisen arvon johonkin jäsenarvoon. ConstantExpression: n lähdekoodi on esitetty käsitteellisesti alla. Sanon ”käsitteellisesti”, koska valitsin niputtaa sen, mikä olisi ollut StringConstantExpression ja NumericConstantExpression yhdeksi luokaksi. Reaaliluokkaan kuuluu siis konstruktori, jolla luodaan vakio merkkijonoargumentilla ja palautetaan sen arvo merkkijonona. Seuraava koodi näyttää, miten ConstantExpression – Luokka käsittelee numeerisia vakioita.

class ConstantExpression extends Expression { private double v; ConstantExpression(double a) { super(); v = a; } double value(Program pgm) throws BASICRuntimeError { return v; }}

edellä esitetty koodi korvaa Expression monimutkaisemmat konstruktiot yksinkertaisella instanssimuuttujan varastolla; value – menetelmä korvataan yksinkertaisesti tallennetun arvon palauttamisella.

on totta, että Expression luokan saattoi koodata hyväksymään konstruktioissaan vakion, joka säästäisi luokan. Yksi etu Expression: n muotoilussa on kuitenkin se, että Expression: n koodi pysyy maksimaalisesti yleisenä. Koen, että tämä koodaustyyli auttaa minua poistamaan erikoistapausten monimutkaisuuden ja näin Kun olen ”valmis” Expression – koodin kanssa, voin siirtyä ilmaisujen muihin näkökohtiin käymättä perusluokkaa uudelleen ja uudelleen. Etu kirkastuu, kun kaivaudutaan toiseen Expression – alaluokkaan nimeltä FunctionExpression.

luokassa FunctionExpression oli kaksi suunnitteluvaatimusta, jotka minun mielestäni piti täyttää, jotta tulkki pysyisi joustavana. Ensimmäinen oli toteuttaa standardin perustoiminnot; toinen oli kapseloida jäsentämällä funktioiden argumentit samaan luokkaan, joka toteutti nämä funktiot. Toisen vaatimuksen, jäsentämisen, taustalla oli halu tehdä tämä PERUSJATKETTAVA luomalla ylimääräisiä funktiokirjastoja, jotka voitiin siirtää jäsentäjälle alaluokiksi FunctionExpression. Edelleen, nämä läpäistyt luokat voitaisiin käyttää jäsennin lisätä toimintojen määrää käyttäjän ohjelman.

FunctionExpression – luokka on vain kohtalaisen monimutkaisempi kuin a ConstantExpression ja se on esitetty tiivistettynä alla:

 1 class FunctionExpression extends Expression { 2 3 double value(Program p) throws BASICRuntimeError { 4 try { 5 switch (oper) { 6 case RND : 7 if (r == null) 8 r = p.getRandom(); 9 return (r.nextDouble() * arg2.value(p));10 case INT :11 return Math.floor(arg2.value(p));12 case SIN :13 return Math.sin(arg2.value(p));14 15 default :16 throw new BASICRuntimeError("Unknown or non-numeric function.");17 }18 } catch (Exception e) {19 if (e instanceof BASICRuntimeError)20 throw (BASICRuntimeError) e;21 else22 throw new BASICRuntimeError("Arithmetic Exception.");23 }24 }

yllä oleva lähde kertoo, miten value – menetelmä on toteutettu. Oper-muuttujaa käytetään uudelleen funktion identiteetin pitämiseksi, ja arg1: n ja arg2: n viittaamia lausekkeita käytetään argumentteina itse funktioille. Lopuksi on suuri kytkinlausunto, joka lähettää pyynnön. Yksi mielenkiintoinen seikka on se, että value – menetelmä ottaa huomioon mahdolliset aritmeettiset poikkeukset ja muuntaa ne esiintymiksi BASICRuntimeError. Jäsennyskoodi FunctionExpression näkyy alla, jälleen tiivistettynä tilan säästämiseksi. (Muista, että kaikki lähdekoodi on saatavilla linkkien avulla resurssit-osiossa.)

 1 static FunctionExpression parse(int ty, LexicalTokenizer lt) throws BASICSyntaxError { 2 FunctionExpression result; 3 Expression a; 4 Expression b; 5 Expression se; 6 Token t; 7 8 t = lt.nextToken(); 9 if (! t.isSymbol('(')) {10 if (ty == RND) {11 lt.unGetToken();12 return new FunctionExpression(ty, new ConstantExpression(1));13 } else if (ty == FRE) {14 lt.unGetToken();15 return new FunctionExpression(ty, new ConstantExpression(0));16 }17 throw new BASICSyntaxError("Missing argument for function.");18 }19 switch (ty) {20 case RND:21 case INT:22 case SIN:23 case COS:24 case TAN:25 case ATN:26 case SQR:27 case ABS:28 case CHR:29 case VAL:30 case STR:31 case SPC:32 case TAB:33 case LOG:34 a = ParseExpression.expression(lt);35 if (a instanceof BooleanExpression) {36 throw new BASICSyntaxError(functions.toUpperCase()+" function cannot accept boolean expression.");37 }38 if ((ty == VAL) && (! a.isString()))39 throw new BASICSyntaxError(functions.toUpperCase()+" requires a string valued argument.");40 result = new FunctionExpression(ty, a);41 break; 42 default:43 throw new BASICSyntaxError("Unknown function on input.");4445 }46 t = lt.nextToken();47 if (! t.isSymbol(')')) {48 throw new BASICSyntaxError("Missing closing parenthesis for function.");49 }50 return result;51 }

huomaa, että tämä koodi hyödyntää sitä, että lausekkeen jäsennin ParseStatement on jo tajunnut tarkastelevansa lauseketta ja ohittanut lausekkeen identiteetin as-parametrissa ty. Tämä jäsennin sitten tarvitsee vain paikantaa avaaminen suluissa ja sulkeminen suluissa, jotka sisältävät argumentti(s). Mutta katso huolellisesti: riveillä #9 kautta #18 jäsennin sallii joidenkin funktioiden ei ole argumentteja (tässä tapauksessa RND ja FRE). Tämä osoittaa joustavuutta, jonka tarjoaa ottaa funktion subparser rakennettu tähän luokkaan, sen sijaan pakottaa kaikki toiminnot mukautua jonkin ennalta mallin. Koska parametrissa ty on funktion tyyppi, kytkinlauseke valitsee haaran, joka voi jäsentää kyseisen funktion vaatimia argumentteja, olivatpa ne merkkijonoja, numeroita, muita lausekkeita ja niin edelleen.

muut näkökohdat: jouset ja taulukot

kaksi muuta peruskielen osaa on kaakaon tulkin toteuttamia: jouset ja taulukot. Katsotaanpa täytäntöönpanoa Jouset ensin.

merkkijonojen toteuttamiseksi muuttujina Expression luokkaa muutettiin siten, että siihen sisällytettiin käsite ”merkkijono” – lausekkeet. Tämä muutos tehtiin kahtena lisäyksenä: isString ja stringValue. Näiden kahden uuden menetelmän lähde on esitetty alla.

 String stringValue(Program pgm) throws BASICRuntimeError { throw new BASICRuntimeError("No String representation for this."); } boolean isString() { return false; }

on selvää, että PERUSOHJELMALLE ei ole kovin hyödyllistä saada kantalausekkeen merkkijonoarvoa (joka on aina joko numeerinen tai Boolen lauseke). Hyödyllisyyden puutteesta voisi päätellä, että nämä menetelmät eivät silloin kuuluneet Expression vaan kuuluivat sen sijaan alaluokkaan Expression. Asettamalla nämä kaksi menetelmää perusluokkaan kaikki Expression oliot voidaan kuitenkin testata, ovatko ne todellisuudessa merkkijonoja.

toinen suunnittelutapa on palauttaa numeeriset arvot merkkijonoina käyttäen StringBuffer – objektia arvon luomiseksi. Niinpä esimerkiksi sama koodi voitaisiin kirjoittaa uudelleen:

 String stringValue(Program pgm) throws BASICRuntimeError { StringBuffer sb = new StringBuffer(); sb.append(this.value(pgm)); return sb.toString(); }

ja jos yllä olevaa koodia käytetään, voit poistaa isString käytön, koska jokainen lauseke voi palauttaa merkkijonon arvon. Lisäksi value – menetelmää voi muokata niin, että yrittää palauttaa luvun, jos lauseke arvioi merkkijonon ajamalla sen valueOf – menetelmällä java.lang.Double. Monissa kielissä, kuten Perl, TCL ja REXX, tällaista amorfista kirjoitusta käytetään suureksi hyödyksi. Molemmat lähestymistavat ovat päteviä, ja sinun tulisi tehdä valintasi tulkin suunnittelun perusteella. BASIC-järjestelmässä tulkin on palautettava virhe, kun merkkijono on annettu numeeriselle muuttujalle, joten valitsin ensimmäisen lähestymistavan (palauttamalla virheen).

kuten taulukoissa, on olemassa erilaisia tapoja, joilla voit suunnitella oman kielesi tulkitsemaan niitä. C käyttää hakasulkeita array-elementtien ympärillä erottaakseen array: n indeksiviitteet funktioviitteistä, joiden argumenttien ympärillä on sulkeita. Basic-kielen suunnittelijat päättivät kuitenkin käyttää sulkeita sekä funktioissa että matriiseissa, joten kun teksti NAME(V1, V2) on jäsentäjän näkemä, se voi olla joko funktiokutsu tai matriisiviite.

leksikaalinen analysaattori erottaa toisistaan tokeneita, joita seuraavat sulut, olettaen ensin, että ne ovat funktioita ja testaamalla sitä. Sitten se menee nähdä, jos ne ovat avainsanoja tai muuttujia. Tämä päätös estää ohjelmaasi määrittelemästä muuttujaa nimeltä ” SIN.”Jokainen muuttuja, jonka nimi vastasi funktion nimeä, palautettaisiin leksikaalisella analysaattorilla funktiotunnuksena sen sijaan. Toinen temppu, jota lexical analyzer käyttää, on tarkistaa, onko muuttujan nimen perässä välittömästi” (”. Jos se on, analysaattori olettaa, että se on array viittaus. Jäsentämällä tätä leksikaalisessa analysaattorissa poistamme merkkijonon ”MYARRAY ( 2 ) ” tulkitsemasta kelvolliseksi rivistöksi (huomaa muuttujan nimen ja avoimen sulun välinen tila).

viimeinen juju toteutuksessa on Variable – luokassa. Tätä luokkaa käytetään muuttujan ilmentymänä, ja kuten viime kuun palstalla käsittelin, se on alaluokka Token. Kuitenkin, se on myös joitakin koneita tukemaan taulukoita ja se on mitä näytän alla:

class Variable extends Token { // Legal variable sub types final static int NUMBER = 0; final static int STRING = 1; final static int NUMBER_ARRAY = 2; final static int STRING_ARRAY = 4; String name; int subType; /* * If the variable is in the symbol table these values are * initialized. */ int ndx; // array indices. int mult; // array multipliers double nArrayValues; String sArrayValues;

yllä oleva koodi esittää muuttujaan liittyvät instanssimuuttujat, kuten ConstantExpression – luokassa. On tehtävä valinta käytettävien luokkien määrästä ja luokan monimutkaisuudesta. Yksi suunnitteluvalinta voisi olla rakentaa Variable – luokka, johon mahtuu vain skalaarimuuttujia, ja lisätä sitten ArrayVariable – alaluokka käsittelemään matriisien koukeroita. Päätin yhdistää ne, kääntämällä skalaarimuuttujat olennaisesti matriisit Pituus 1.

jos luet yllä olevaa koodia, näet array-indeksit ja-kertoimet. Nämä ovat tässä, koska Basicin moniulotteiset matriisit on toteutettu yhden lineaarisen Java-matriisin avulla. Lineaarinen indeksi Java-matriisiin lasketaan manuaalisesti käyttäen kertojajoukon elementtejä. PERUSOHJELMASSA käytettyjen indeksien pätevyys tarkistetaan vertaamalla niitä indeksien ndx-matriisin enimmäisindeksiin.

esimerkiksi perusjoukolla, jonka kolme ulottuvuutta ovat 10, 10 ja 8, olisi ndx: ään tallennetut arvot 10, 10 ja 8. Tämän avulla lausekkeen arvioija voi testata” indeksin out of bounds ” ehdon vertaamalla PERUSOHJELMASSA käytettyä lukua ndx: ään tallennettuun lakimääräiseen maksimilukuun. Kerroinrivistö esimerkissämme sisältäisi arvot 1, 10 ja 100. Nämä vakiot edustavat lukuja, joita käytetään kartoittamaan moniulotteisesta matriisiindeksimäärityksestä lineaariseksi matriisiindeksimääritykseksi. Todellinen yhtälö on:

Java Index = Index1 + Index2 * maksimikoko Index1 + Index3 * (maksimikoko Index1 * MaxSizeIndex 2)

seuraava Java-array Variable – luokassa on esitetty alla.

 Expression expns;

expns-taulukkoa käytetään käsittelemään taulukoita, jotka kirjoitetaan ”A(10*B, i).”Tällöin indeksit ovat itse asiassa lausekkeita vakioiden sijaan, joten viittauksen on sisällettävä osoittimia niihin lausekkeisiin, jotka arvioidaan suorituksen aikana. Lopuksi on tämä melko rumannäköinen koodinpätkä, joka laskee indeksin sen mukaan, mitä ohjelmassa läpäistiin. Tämä yksityinen menetelmä on esitetty alla.

 private int computeIndex(int ii) throws BASICRuntimeError { int offset = 0; if ((ndx == null) || (ii.length != ndx.length)) throw new BASICRuntimeError("Wrong number of indices."); for (int i = 0; i < ndx.length; i++) { if ((ii < 1) || (ii > ndx)) throw new BASICRuntimeError("Index out of range."); offset = offset + (ii-1) * mult; } return offset; }

kun katsoo yllä olevaa koodia, huomaa, että koodi tarkistaa ensin, että taulukkoon viitattaessa käytettiin oikeaa määrää indeksejä, ja sitten, että kukin indeksi oli kyseisen indeksin lainmukaisen vaihteluvälin sisällä. Jos virhe havaitaan, tulkille heitetään poikkeus. Menetelmät numValue ja stringValue palauttavat muuttujan arvon vastaavasti numerona tai jonona. Nämä kaksi menetelmää on esitetty alla.

 double numValue(int ii) throws BASICRuntimeError { return nArrayValues; } String stringValue(int ii) throws BASICRuntimeError { if (subType == NUMBER_ARRAY) return ""+nArrayValues; return sArrayValues; }

muuttujan arvon asettamiseen on muitakin menetelmiä, joita ei ole esitetty tässä.

piilottamalla suuren osan kunkin kappaleen toteutustavan monimutkaisuudesta, kun lopulta tulee aika suorittaa perusohjelma, Java-koodi on melko suoraviivainen.

juokseva koodi

koodi PERUSLAUSEIDEN tulkitsemiseen ja toteuttamiseen sisältyy

run

menetelmä

Program

Luokka. Koodi tämä menetelmä on esitetty alla, ja minä askel sen kautta huomauttaa mielenkiintoisia osia.

 1 public void run(InputStream in, OutputStream out) throws BASICRuntimeError { 2 PrintStream pout; 3 Enumeration e = stmts.elements(); 4 stmtStack = new Stack(); // assume no stacked statements ... 5 dataStore = new Vector(); // ... and no data to be read. 6 dataPtr = 0; 7 Statement s; 8 9 vars = new RedBlackTree();1011 // if the program isn't yet valid.12 if (! e.hasMoreElements())13 return;1415 if (out instanceof PrintStream) {16 pout = (PrintStream) out;17 } else {18 pout = new PrintStream(out);19 }

yllä oleva koodi osoittaa, että run menetelmä vaatii InputStream ja OutputStream käytettäväksi suoritusohjelman ”konsolina”. Rivillä 3 arvojoukko objekti e asetetaan kokoelman lausekkeiden joukkoon nimeltä stmts. Tässä kokoelmassa käytin muunnelmaa binäärisestä hakupuusta nimeltä ”punamusta” puu. (Lisätietoja binäärihakupuista on edellisessä kolumnissani geneeristen kokoelmien rakentamisesta.) Tämän jälkeen luodaan kaksi lisäkokoelmaa — toinen käyttäen a Stack ja toinen käyttäen a Vector. Pinoa käytetään kuten pinoa missä tahansa tietokoneessa, mutta vektoria käytetään nimenomaan perusohjelman DATALAUSEISSA. Loppukokoelma on toinen punamusta puu, jossa on viitteet perusohjelman määrittelemille muuttujille. Tämä puu on symboli taulukko, jota ohjelma käyttää, kun se suoritetaan.

alustuksen jälkeen Tulo-ja ulostulovirrat asetetaan, ja jos e ei ole nolla, aloitetaan keräämällä kaikki ilmoitetut tiedot. Tämä tehdään kuten seuraavassa koodissa.

 /* First we load all of the data statements */ while (e.hasMoreElements()) { s = (Statement) e.nextElement(); if (s.keyword == Statement.DATA) { s.execute(this, in, pout); } }

yllä oleva silmukka tarkastelee yksinkertaisesti kaikkia väittämiä, minkä jälkeen kaikki sen löytämät DATALAUSEET suoritetaan. Kunkin TIETOLAUSEKKEEN suoritus lisää kyseisessä lausekkeessa ilmoitetut arvot dataStore-vektoriin. Seuraavaksi suoritamme ohjelman oikein, joka tehdään käyttämällä tätä seuraavaa koodinpätkää:

 e = stmts.elements(); s = (Statement) e.nextElement(); do { int yyy; /* While running we skip Data statements. */ try { yyy = in.available(); } catch (IOException ez) { yyy = 0; } if (yyy != 0) { pout.println("Stopped at :"+s); push(s); break; } if (s.keyword != Statement.DATA) { if (traceState) { s.trace(this, (traceFile != null) ? traceFile : pout); } s = s.execute(this, in, pout); } else s = nextStatement(s); } while (s != null); }

kuten yllä olevasta koodista näkyy, ensimmäinen vaihe on käynnistää e uudelleen. seuraava vaihe on hakea ensimmäinen lauseke muuttujaan s ja syöttää sen jälkeen suoritussilmukka. On olemassa joitakin koodia tarkistaa vireillä syöte tulovirrassa, jotta ohjelman eteneminen voidaan keskeyttää kirjoittamalla ohjelma, ja sitten silmukka tarkistaa, jos suoritettava lauseke olisi tietojen lauseke. Jos näin on, silmukka ohittaa lausunnon sellaisena kuin se on jo suoritettu. Melko mutkikas tekniikka suorittaa kaikki tiedot lausekkeet ensin tarvitaan, koska BASIC mahdollistaa tiedon lausekkeet, jotka täyttävät lukea lauseke näkyvät missä tahansa lähdekoodissa. Lopuksi, jos jäljitys on käytössä, tulostetaan jäljitystietue ja vedotaan erittäin epäuskottavaan lausumaan s = s.execute(this, in, pout);. Kauneus on siinä, että kaikki pyrkimys kapseloida peruskäsitteet helppotajuisiksi luokiksi tekee lopullisesta koodista triviaalin. Jos se ei ole triviaali sitten ehkä sinulla on vihje, että voisi olla toinen tapa jakaa suunnittelu.

paketointi ja lisäajatukset

tulkki on suunniteltu siten, että se voisi toimia lankana, jolloin ohjelmatilassasi voi olla samanaikaisesti useita COCOA interpreter-kierteitä. Lisäksi funktion laajentamisen avulla voimme tarjota keinon, jolla nämä kierteet voivat olla vuorovaikutuksessa keskenään. Apple II: lle ja myöhemmin PC: lle ja Unixille oli olemassa ohjelma nimeltä C-robots, joka oli vuorovaikuttavien ”robottien” kokonaisuuksien järjestelmä, joka ohjelmoitiin yksinkertaisella perusjohdannaisella. Peli tarjosi minulle ja muille monta tuntia viihdettä, mutta oli myös erinomainen tapa esitellä laskennan perusperiaatteet nuoremmille opiskelijoille (jotka virheellisesti uskoivat, että he vain pelasivat eivätkä oppineet). Java – pohjainen tulkki alijärjestelmät ovat paljon tehokkaampia kuin niiden ennen Java kollegansa, koska ne ovat heti saatavilla millä tahansa Java-alustalla. COCOA juoksi Unix-järjestelmissä ja Macintoshes samana päivänä sain työskennellä Windows 95-pohjainen PC. Vaikka Java saa Hakataan yhteensopimattomuudet kierre tai ikkuna toolkit toteutukset, mitä usein unohdetaan on tämä: paljon koodia ”vain toimii.”

Chuck McManis on tällä hetkellä FreeGate Corp.-nimisen, riskirahoitteisen start-up-yrityksen johtaja, joka tutkii mahdollisuuksia Internetin markkinoilla. Ennen Freegateen liittymistä Chuck oli Java-yhtyeen jäsen. Hän liittyi Java-konserniin heti FirstPerson Inc: n perustamisen jälkeen. ja oli jäsenenä portable OS group (Ryhmä vastuussa Osportti Java). Myöhemmin, kun FirstPerson lakkautettiin, hän pysyi ryhmän mukana kehittämällä Java-alustan alpha-ja betaversions-versioita. Hän loi ensimmäisen ”all Java” – kotisivun Internetiin, kun hän teki ohjelmoinnin Sun-kotisivun Javaversion-sivulle toukokuussa 1995. Hän kehitti myös Javalle akryptografisen kirjaston ja Java classloaderin versiot, joilla pystyi seulomaan luokkia digitaalisten allekirjoitusten perusteella.Ennen firstpersoniin liittymistään Chuck työskenteli Sunsoftin käyttöjärjestelmäalueella kehittäen verkostoitumissovelluksia, joissa hän teki NIS+: n alkuperäisen suunnittelun. Katso myös hänen kotisivunsa. : END_BIO

lisätietoja aiheesta

  • tässä linkit yllä mainittuihin lähdetiedostoihin:
    • jatkuva ilme.java
    • Funktioekspressio.java
    • ohjelma.java
    • Statement.java
    • Stringekspressio.java
    • muuttuja.java
    • variable Expression.Jaava
  • ja tässä on .Lähdetiedostojen ZIP-tiedosto:
    syvällinen.zip
  • ”Uncommon Lisp” — Javalla kirjoitettu Lisp-tulkki
    http://user03.blue.aol.com/thingtone/workshop/lisp.htm
  • Mike Cowlishaw ’ n NetREXX tulkki kirjoitettu Java
    http://www2.hursley.ibm.com/netrexx/
  • vanha kopio USENET BASIC FAQ (se on edelleen hyödyllistä tietoa siinä.)
    http://whitworth.me.ic.ac.uk/people/students/djbur/qbasic.htm
  • COCOA, perus tulkki kirjoitettu Java
    http://www.mcmanis.com/~cmcmanis/java/javaworld/examples/BASIC.html
  • Chuckin Java resources-sivu
    http://www.mcmanis.com/~cmcmanis/java/javaworld/
  • TCL tulkki kirjoitettu Java
    http://www.cs.cornell.edu/home/ioi/Jacl/
  • :
  • ”How to build an interpreter in Java, Part 2rakenne”
    the trick to assembling the foundation classes for a simple interpreter.
  • ”How to build an interpreter in Java, Part 1The BASICs”
    monimutkaisissa ohjelmissa, jotka vaativat komentosarjakieltä, Javaa voidaan käyttää tulkin toteuttamiseen lisäämällä skriptauskykyjä mihin tahansa Java-sovellukseen.
  • ”Lexical analysis, Part 2Build an application”
    kuinka StreamTokenizer-objektia käytetään interaktiivisen laskimen toteuttamiseen.
  • ” Lexical analysis and JavaPart 1″
    Opi muuntamaan ihmisen luettava teksti koneellisesti luettavaksi tiedoksi StringTokenizer-ja StreamTokenizer-luokkien avulla.
  • ”Code reuse and object-oriented systems”
    käytä apuluokkaa dynaamisen käyttäytymisen toteuttamiseen.
  • ” konttien tuki kohteille Javassa 1.0.2″
    esineiden järjestäminen on helppoa, kun ne laittaa konttiin. Tämä artikkeli opastaa suunnittelussa ja toteutuksessa säiliön.
  • ”the basics of Java class loaders”
    the fundamentals of this key component of the Java architecture.
  • ”ei käytä roskien keruuta”
    minimoi kasojen rymistely Java-ohjelmissasi.
  • ”Threads and applets and visual controls”
    tämä sarjan päätösosa tutkii useiden datakanavien lukemista.
  • ”Using communication channels in applets, Part 3”
    Develop Visual Basic-tyylisiä tekniikoita applet design — and convert temperatures in the process.
  • ” synkronoivat kierteet Java, osa II”
    Opettele kirjoittamaan datakanavaluokka ja luo sitten yksinkertainen esimerkkisovellus, joka havainnollistaa luokan reaalimaailman toteutusta.
  • ” Synchronizing threads in Java”
    entinen Java-tiimin Kehittäjä Chuck McManis opastaa yksinkertaisen esimerkin, joka havainnollistaa, miten säikeitä synkronoidaan luotettavan ja ennustettavan sovelmien käyttäytymisen varmistamiseksi.

Vastaa

Sähköpostiosoitettasi ei julkaista.