Byg en tolk i Java-Implementer eksekveringsmotoren

for dem af jer, der bare slutter sig til os, i min “Java in Depth” – kolonne i løbet af de sidste par måneder har jeg diskuteret, hvordan man kan gå om at bygge en tolk i Java. I den første tolkekolonne dækkede vi nogle af de ønskelige egenskaber ved en tolk; i den anden kolonne diskuterede vi både parsing og layoutet af en klassepakke til implementering af tolken. I denne kolonne ser vi på at køre tolken og de supportklasser, der er nødvendige for at opnå det. Endelig vil jeg afslutte serien her med en diskussion om, hvordan en tolk kan tilsluttes andre Java-klasser og dermed forbedre deres evner.

gennemgang af de relevante bits

Lad mig starte med at skitsere, hvad vi hidtil har dækket, og påpege de dele af designet, der bliver vigtigere, når vi diskuterer udførelsestilstand. For en mere detaljeret beskrivelse af disse klasser henvises til mine tidligere kolonner eller til kildekodelinkene, der er i afsnittet

ressourcer

nedenfor.

der er tre grundklasser i implementeringen af tolken, Program, Statementog Expression. Følgende viser, hvordan de tre er relateret:

Program

denne Program klasse limer parsing-og eksekveringskomponenterne i parseren sammen. Denne klasse definerer to hovedmetoder, load og run. Metoden load læser udsagn fra en inputstrøm og analyserer dem i en samling af udsagn, metoden run gentager over samlingen og udfører hvert af udsagnene. Klassen Program indeholder også en samling variabler, som programmet kan bruge, samt en stak til lagring af data.

Erklæring

Statement klassen indeholder en enkelt analyseret erklæring. Denne klasse er faktisk underklasseret i en bestemt type erklæring (PRINT, GOTO, IF osv.), men alle udsagn indeholder metoden execute, som kaldes til at udføre udsagnet i sammenhæng med en Program klasseinstans.

udtryk

klassen Expression indeholder et udtryks parse-træ. Under udførelsen bruges value – metoden til at evaluere udtrykket og returnere dets værdi. Ligesom Statement er Expression – klassen primært designet til at blive underklasseret af specifikke typer udtryk.

alle disse klasser arbejder sammen for at danne grundlag for en tolk. Klassen Program indkapsler samtidig parsing-og eksekveringsoperationen, mens klasserne Statement og Expression indkapsler de faktiske beregningsbegreber for det sprog, vi har implementeret. For disse tre artikler om bygningstolke har eksempelsproget været grundlæggende.

faciliteter til beregning

der er to eksekverbare klasser i tolken,

Statement

og

Expression

. Lad os først se på

Expression

forekomsterne af Expression oprettes ved metoden expressioni klassen ParseExpression. ParseExpression – klassen implementerer ekspressionsparseren i denne tolk. Denne klasse er en peer af ParseStatement klassen, som bruger statement metoden til at analysere grundlæggende udsagn. Forekomster af Expression har en intern type, der identificerer, hvilken operatør forekomsten repræsenterer, og to metoder, value og stringValue, der returnerer den beregnede værdi af udtrykket. Derudover, når et udtryk instans er oprettet, er det nominelt givet to parametre, der repræsenterer venstre og højre side af udtrykket operation. Vist i kildeform er den første del af udtrykket som følger:

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

som du kan se i koden ovenfor, er der instansvariablerne, en operatørtype med navnet oper og to halvdele af operationen i arg1 og arg2 og derefter nogle konstanter til at definere de forskellige typer. Der er også to konstruktører, der bruges af udtryksparseren; disse skaber et nyt udtryk fra to udtryk. Deres kilde er vist nedenfor:

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); }

den første konstruktør bygger et vilkårligt ekspressionsobjekt, og den anden bygger et “unært” ekspressionsobjekt-såsom unary minus. En ting at bemærke er, at hvis der kun er et argument, bruges arg2 til at gemme dens værdi.

den metode, der bruges hyppigst i Expression klassen, er value, som er defineret som følger:

 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. ...

du kan se, at hvert udtryk objekt repræsenterer en tupel bestående af en operatør og en eller to argumenter. Den sjove del ved at designe ekspressionsudførelsesmotoren på denne måde er, at når du konstruerer dette sæt udtrykstupler baseret på Expression – objektet, kan du beregne værdien af udtrykket ved blot at påberåbe sig value – metoden. Metoden value påkalder rekursivt metoden value for de to argumenter, der komponerer dette udtryk, anvender handlingen på dem og returnerer resultatet. Dette design blev brugt, så udtryk ville være lette at forstå.

for at holde klassestrukturen ren er alle beregningsenheder-fra konstanter til trigonometriske funktioner-underklasser af Expression. Denne ide, stjålet skamløst fra Lisp, indkapsler fuldstændigt forestillingen om at “forårsage” en evaluering, fra den faktiske implementering af “hvordan” denne evaluering finder sted. For at demonstrere, hvordan dette princip anvendes, behøver vi kun se på nogle af de specialiserede underklasser af Expression.

konstanter i min version af BASIC, som jeg kaldte COCOA, er repræsenteret af klassen ConstantExpression, hvilke underklasser Expression og gemmer simpelthen den numeriske værdi i en medlemsværdi. Kildekoden til ConstantExpression vises konceptuelt nedenfor. Jeg siger “konceptuelt”, fordi jeg valgte at samle hvad der ville have været StringConstantExpression og NumericConstantExpression i en enkelt klasse. Så den virkelige klasse inkluderer en konstruktør til at skabe en konstant med et strengargument og til at returnere dens værdi som en streng. Følgende kode viser, hvordan klassen ConstantExpression håndterer numeriske konstanter.

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

koden vist ovenfor erstatter de mere komplicerede konstruktører af Expression med en simpel butik af en instansvariabel; value – metoden erstattes simpelthen med en retur af den lagrede værdi.

det er rigtigt, at du kunne kode Expression klassen for at acceptere i sine konstruktører en konstant, der ville spare dig for en klasse. En fordel ved at designe Expression den måde, jeg har, er imidlertid, at koden i Expression forbliver maksimalt generisk. Jeg finder ud af, at denne kodningsstil hjælper mig med at eliminere kompleksiteten i særlige tilfælde, og når jeg er “færdig” med Expression – koden, kan jeg gå videre til andre aspekter af udtryk uden at revidere basisklassen igen og igen. Fordelen bliver tydeligere, når vi dykker ned i en anden underklasse af Expression ved navn FunctionExpression.

i klassen FunctionExpression var der to designkrav, som jeg følte skulle opfyldes for at holde tolken fleksibel. Den første var at implementere standard grundlæggende funktioner; den anden var at indkapsle analysen af funktionsargumenterne i den samme klasse, der implementerede disse funktioner. Det andet krav, parsing, var motiveret af et ønske om at gøre dette grundlæggende udvideligt ved at oprette yderligere funktionsbiblioteker, der kunne overføres til parseren som underklasser af FunctionExpression. Desuden kunne de beståede klasser bruges af parseren til at øge antallet af funktioner, der er tilgængelige for brugerens program.

FunctionExpression klassen er kun moderat mere kompliceret end en ConstantExpression og vises i kondenseret form nedenfor:

 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 }

ovenstående kilde viser, hvordan metoden value implementeres. Oper-variablen genbruges til at holde funktionsidentiteten, og Ekspressionsobjekterne, der henvises til af arg1 og arg2, bruges som argumenter for selve funktionerne. Endelig er der en stor omskiftererklæring, der sender anmodningen. Et interessant aspekt er, at value – metoden fanger de potentielle aritmetiske undtagelser og konverterer dem til forekomster af BASICRuntimeError. Parsingskoden i FunctionExpression er vist nedenfor, igen kondenseret for at spare plads. (Husk, at hele kildekoden er tilgængelig ved hjælp af links i afsnittet Ressourcer.)

 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 }

Bemærk, at denne kode drager fordel af det faktum, at ekspressionsparseren i ParseStatement allerede har fundet ud af, at den ser på et udtryk og har bestået identiteten af udtrykket I som parameter ty. Denne parser behøver derefter kun at finde åbningsparentesen og den afsluttende parentes, der indeholder argumentet / argumenterne. Men se nøje: i linjer #9 til #18 tillader parseren, at nogle funktioner ikke har nogen argumenter (i dette tilfælde RND og FRE). Dette viser den fleksibilitet, der ydes ved at have funktions subpar indbygget i denne klasse, snarere end at tvinge alle funktioner til at overholde en foruddefineret skabelon. Givet en funktionstype i parameteren ty, skifter sætningen en gren, der kan analysere de argumenter, der kræves for den funktion, det være sig strenge, tal, andre udtryk osv.

andre aspekter: strenge og arrays

to andre dele af det grundlæggende sprog implementeres af COCOA-tolken: strenge og arrays. Lad os først se på implementeringen af strenge.

for at implementere strenge som variabler blev Expression – klassen ændret til at omfatte begrebet “streng” – udtryk. Denne ændring tog form af to tilføjelser: isString og stringValue. Kilden til disse to nye metoder er vist nedenfor.

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

det er klart, at det ikke er for nyttigt for et grundlæggende program at få strengværdien af et basisudtryk (som altid er enten numerisk eller boolsk udtryk). Du kan konkludere fra manglen på nytte, at disse metoder derefter ikke hørte hjemme i Expression og tilhørte i en underklasse af Expression i stedet. Men ved at sætte disse to metoder i basisklassen kan alle Expression objekter testes for at se, om de faktisk er strenge.

en anden designmetode er at returnere de numeriske værdier som strenge ved hjælp af et StringBuffer objekt til at generere en værdi. Så for eksempel kunne den samme kode omskrives som:

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

og hvis koden ovenfor bruges, kan du eliminere brugen af isString, fordi hvert udtryk kan returnere en strengværdi. Desuden kan du ændre value – metoden for at forsøge at returnere et tal, hvis udtrykket evalueres til en streng ved at køre det gennem valueOf – metoden i java.lang.Double. På mange sprog som f.eks Perl, TCL, og igen, denne form for amorf typing bruges til stor fordel. Begge tilgange er gyldige, og du bør gøre dit valg baseret på designet af din tolk. I BASIC skal tolken returnere en fejl, når en streng er tildelt en numerisk variabel, så jeg valgte den første tilgang (returnerer en fejl).

hvad angår arrays, er der forskellige måder, hvorpå du kan designe dit sprog til at fortolke dem. C bruger de firkantede parenteser omkring arrayelementer til at skelne arrayets indekshenvisninger fra funktionshenvisninger, der har parenteser omkring deres argumenter. Sprogdesignerne for BASIC valgte imidlertid at bruge parenteser til både funktioner og arrays, så når teksten NAME(V1, V2) ses af parseren, kan det enten være et funktionsopkald eller en array-reference.

den leksikale analysator skelner mellem tokens, der efterfølges af parenteser ved først at antage, at de er funktioner og tester for det. Derefter fortsætter det med at se, om de er nøgleord eller variabler. Det er denne beslutning, der forhindrer dit program i at definere en variabel med navnet ” synd.”Enhver variabel, hvis navn matchede et funktionsnavn, ville i stedet blive returneret af den leksikale analysator som et funktionstoken. Det andet trick, som den leksikale analysator bruger, er at kontrollere, om variabelnavnet straks efterfølges af `(‘. Hvis det er tilfældet, antager analysatoren, at det er en array-reference. Ved at analysere dette i den leksikale analysator eliminerer vi strengen `MYARRAY ( 2 )‘ fra at blive fortolket som et gyldigt array (Bemærk mellemrummet mellem variabelnavnet og den åbne parentes).

det sidste trick til implementering af arrays er i Variable klassen. Denne klasse bruges til en forekomst af en variabel, og som jeg diskuterede i sidste måneds kolonne, er det en underklasse af Token. Det har dog også nogle maskiner til at understøtte arrays, og det er det, jeg vil vise nedenfor:

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;

ovenstående kode viser instansvariablerne forbundet med en variabel, som i klassen ConstantExpression. Man skal træffe et valg om antallet af klasser, der skal bruges i forhold til kompleksiteten af en klasse. Et designvalg kan være at opbygge en Variable klasse, der kun indeholder skalære variabler og derefter tilføje en ArrayVariable underklasse for at håndtere de komplicerede arrays. Jeg valgte at kombinere dem, dreje skalære variabler væsentlige i arrays af længde 1.

hvis du læser ovenstående kode, vil du se array indekser og multiplikatorer. Disse er her, fordi multidimensionelle arrays i BASIC implementeres ved hjælp af et enkelt lineært Java-array. Det lineære indeks i Java-arrayet beregnes manuelt ved hjælp af elementerne i multiplikatorarrayet. De indekser, der bruges i GRUNDPROGRAMMET, kontrolleres for gyldighed ved at sammenligne dem med det maksimale juridiske indeks i Indeksens nds-array.

for eksempel ville et grundlæggende array med tre dimensioner på 10, 10 og 8 have værdierne 10, 10 og 8 gemt i NDS. Dette gør det muligt for ekspressionsevaluatoren at teste for en “indeks out of bounds” – tilstand ved at sammenligne det nummer, der bruges i GRUNDPROGRAMMET, med det maksimale juridiske nummer, der nu er gemt i nd. Multiplikatorarrayet i vores eksempel vil indeholde værdierne 1, 10 og 100. Disse konstanter repræsenterer de tal, man bruger til at kortlægge fra en multidimensionel array indeks specifikation i en lineær array indeks specifikation. Den faktiske ligning er:

Java-indeks = Indeks1 + Indeks2 * maks. størrelse på Indeks1 + Indeks3 * (maks.størrelse på Indeks1 * maks. indeks 2)

det næste Java-array i klassen Variable er vist nedenfor.

 Expression expns;

arrayet bruges til at håndtere arrays, der er skrevet som “A(10*B, i).”I så fald er indekserne faktisk udtryk snarere end konstanter, så referencen skal indeholde henvisninger til de udtryk, der evalueres på kørselstidspunktet. Endelig er der dette ret grimme stykke kode, der beregner indekset afhængigt af hvad der blev bestået i programmet. Denne private metode er vist nedenfor.

 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; }

når du ser på koden ovenfor, skal du bemærke, at koden først kontrollerer, at det korrekte antal indekser blev brugt, når du henviser til arrayet, og derefter at hvert indeks var inden for det juridiske interval for det indeks. Hvis der opdages en fejl, kastes en undtagelse til tolken. Metoderne numValue og stringValue returnerer en værdi fra variablen som henholdsvis et tal eller en streng. Disse to metoder er vist nedenfor.

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

der er yderligere metoder til indstilling af værdien af en variabel, der ikke vises her.

ved at skjule meget af kompleksiteten af, hvordan hvert stykke implementeres, når det endelig kommer tid til at udføre det grundlæggende program, er Java-koden ret ligetil.

kører koden

koden til at fortolke de grundlæggende udsagn og udføre dem er indeholdt i

run

metode af

Program

klasse. Koden til denne metode er vist nedenfor, og jeg vil gå igennem det for at påpege de interessante dele.

 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 }

ovenstående kode viser, at run – metoden tager en InputStream og en OutputStream til brug som “konsol” til det udførende program. I linje 3 er tællingsobjektet e indstillet til sæt af udsagn fra samlingen med navnet stmts. Til denne samling brugte jeg en variation på et binært søgetræ kaldet et “Rød-sort” træ. (For yderligere information om binære søgetræer, se min tidligere kolonne om opbygning af generiske samlinger.) Derefter oprettes to yderligere samlinger – en ved hjælp af en Stackog en ved hjælp af en Vector. Stakken bruges som stakken på enhver computer, men vektoren bruges udtrykkeligt til DATASÆTNINGERNE i basisprogrammet. Den endelige samling er et andet rød-sort træ, der indeholder referencerne for de variabler, der er defineret af det grundlæggende program. Dette træ er symboltabellen, der bruges af programmet, mens det udføres.

efter initialiseringen oprettes input-og outputstrømmene, og hvis e ikke er null, starter vi med at indsamle data, der er erklæret. Det gøres som vist i følgende kode.

 /* 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); } }

ovenstående loop ser simpelthen på alle udsagnene, og eventuelle DATAUDSAGN, den finder, udføres derefter. Udførelsen af hver DATAERKLÆRING indsætter de værdier, der er angivet ved denne erklæring, i datalagervektoren. Dernæst udfører vi programmet korrekt, hvilket gøres ved hjælp af dette næste stykke kode:

 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); }

som du kan se i koden ovenfor, det første trin er at initialisere e. det næste trin er at hente den første sætning i variablen s og derefter gå ind i udførelsessløjfen. Der er en kode, der skal kontrolleres for afventende input på inputstrømmen, så programmets fremskridt kan afbrydes ved at skrive på programmet, og derefter kontrollerer sløjfen for at se, om udsagnet, der skal udføres, ville være en DATAERKLÆRING. Hvis det er, springer sløjfen over udsagnet, da det allerede blev udført. Den temmelig indviklede teknik til at udføre alle dataerklæringer først er påkrævet, fordi BASIC tillader, at de dataerklæringer, der tilfredsstiller en LÆSEERKLÆRING, vises hvor som helst i kildekoden. Endelig, hvis sporing er aktiveret, udskrives en sporingspost, og den meget uinpressive erklæring s = s.execute(this, in, pout); påberåbes. Skønheden er, at al indsatsen for at indkapsle basiskoncepterne i letforståelige klasser gør den endelige kode triviel. Hvis det ikke er trivielt, har du måske en anelse om, at der kan være en anden måde at opdele dit design på.

indpakning og yderligere tanker

tolken blev designet, så den kunne køre som en tråd, således at der kan være flere COCOA-tolketråde, der kører samtidigt i dit programplads på samme tid. Yderligere, med brugen af funktionsudvidelse kan vi tilvejebringe et middel, hvorved disse tråde kan interagere med hinanden. Der var et program til Apple II og senere til PC ‘ en kaldet C-robots, der var et system af interagerende “robot” enheder, der blev programmeret ved hjælp af et simpelt grundlæggende afledt sprog. Spillet gav mig og andre mange timers underholdning, men var også en glimrende måde at introducere de grundlæggende principper for beregning til yngre studerende (som fejlagtigt troede, at de bare spillede og ikke lærte). Java-baserede tolk-undersystemer er meget mere kraftfulde end deres pre-Java-kolleger, fordi de øjeblikkeligt er tilgængelige på enhver Java-platform. COCOA kørte på unikke systemer og Macintoshes samme dag jeg fik arbejde på en vinduer 95 baseret PC. Mens Java bliver slået op af uforeneligheder i tråd-eller vinduesværktøjsimplementeringerne, er det, der ofte overses, dette: en masse kode “fungerer bare.”

Chuck McManis er i øjeblikket direktør for systemprogrammering hos FreeGate Corp., en venturefinansieret opstart, der udforsker muligheder på internetmarkedet. Før han sluttede sig til FreeGate, Chuck var medlem af Java-gruppen. Han sluttede sig til Java-gruppen lige efter dannelsen af FirstPerson Inc. og varet medlem af den bærbare OS-gruppe (den gruppe, der er ansvarlig for Osporten af Java). Senere, da FirstPerson blev opløst, blev hanmed gruppen gennem udviklingen af alpha og betaversions af Java-platformen. Han skabte den første” alle Java ” hjemmeside på internettet, da han gjorde programmeringen til Javaversion af Sun hjemmeside i maj 1995. Han udviklede også acryptographic library til Java og versioner af Java classloader der kunne screene klasser baseret på digitale signaturer.Før han kom til Førstperson, arbejdede Chuck i operativsystemerneområde af SunSoft, udvikling af netværksapplikationer, hvor han gjordedet oprindelige design af NIS+. Også, tjek hans hjemmeside. : END_BIO

Lær mere om dette emne

  • her er links til de kildefiler, der henvises til ovenfor:
    • Konstantudtryk.java
    • Funktionekspression.java
    • Program.java
    • Erklæring.java
    • Stringekspression.java
    • variabel.java
    • Variabeludtryk.java
  • og her er en .Lynlås fil af kildefilerne:
    indepth.lynlås
  • “Ikke almindelig Lisp” – en Lisp-tolk skrevet i Java
    http://user03.blue.aol.com/thingtone/workshop/lisp.htm
  • Net – tolk skrevet i Java
    http://www2.hursley.ibm.com/netrexx/
  • en gammel kopi af USENET BASIC ofte stillede spørgsmål (den har stadig nyttige oplysninger i den.)
    http://whitworth.me.ic.ac.uk/people/students/djbur/qbasic.htm
  • kakao, en grundlæggende tolk skrevet i Java
    http://www.mcmanis.com/~cmcmanis/java/javaworld/examples/BASIC.html
  • Chuck ‘ s Java resources page
    http://www.mcmanis.com/~cmcmanis/java/javaworld/
  • TCL tolk skrevet i Java
    http://www.cs.cornell.edu/home/ioi/Jacl/
  • :
  • “hvordan man opbygger en tolk i Java, del 2strukturen”
    tricket til at samle grundklasserne til en simpel tolk.
  • “Sådan opbygges en tolk i Java, del 1Det grundlæggende”
    for komplekse applikationer, der kræver et scriptsprog, kan Java bruges til at implementere tolken og tilføje scripting evner til enhver Java-app.
  • “leksikalsk analyse, del 2opbyg en applikation”
    Sådan bruges Streamtokenisatorobjektet til at implementere en interaktiv lommeregner.
  • ” leksikalsk analyse og JavaPart 1″
    Lær, hvordan man konverterer menneskelig læsbar tekst til maskinlæsbare data ved hjælp af Stringtokenisator-og Streamtokeniseringsklasserne.
  • “genbrug af kode og objektorienterede systemer”
    brug en hjælperklasse til at håndhæve dynamisk adfærd.
  • ” Containerstøtte til objekter i Java 1.0.2″
    organisering af objekter er let, når du lægger dem i containere. Denne artikel leder dig gennem design og implementering af en container.
  • ” det grundlæggende i Java class loaders”
    grundlaget for denne nøglekomponent i Java-arkitekturen.
  • ” ikke bruger garbage collection”
    Minimer heap thrashing i dine Java-programmer.
  • “tråde og applets og visuelle kontroller”
    denne sidste del af serien udforsker læsning af flere datakanaler.
  • “brug af kommunikationskanaler i applets, Del 3”
    udvikle Visual Basic-stil teknikker til applet design-og konvertere temperaturer i processen.
  • ” synkronisering af tråde i Java, Del II”
    Lær at skrive en datakanalklasse, og opret derefter et simpelt eksempelprogram, der illustrerer en virkelig implementering af klassen.
  • ” synkronisering af tråde i Java”
    tidligere Java-teamudvikler Chuck McManis leder dig gennem et simpelt eksempel, der illustrerer, hvordan du synkroniserer tråde for at sikre pålidelig og forudsigelig appletadfærd.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.