Vytvořte interpret v Javě-implementujte execution engine

pro ty z vás, kteří se k nám právě připojili, v mém sloupci „Java in Depth“ za posledních pár měsíců jsem diskutoval o tom, jak by se dalo stavět interpret v Javě. V prvním sloupci tlumočníka jsme se zabývali některými žádoucími atributy tlumočníka; ve druhém sloupci jsme diskutovali jak o analýze, tak o rozvržení balíčku třídy pro implementaci tlumočníka. V tomto sloupci se podíváme na spuštění interpretu a třídy podpory nezbytné k dosažení tohoto cíle. Nakonec tu sérii zabalím diskusí o tom, jak lze tlumočníka zapojit do jiných tříd Java, čímž se zvýší jejich schopnosti.

přezkoumání příslušných bitů

dovolte mi začít načrtnutím toho, co jsme dosud pokryli, a poukázat na ty části návrhu, které budou při diskusi o režimu provádění důležitější. Podrobnější popis těchto tříd naleznete v mých předchozích sloupcích nebo odkazech na zdrojový kód, které jsou v sekci

zdroje

níže.

v implementaci tlumočníka existují tři základní třídy, Program, Statement a Expression. Následující text ukazuje, jak jsou tyto tři příbuzné:

Program

tato třída Program slepuje komponenty parsování a provádění analyzátoru. Tato třída definuje dvě hlavní metody, load a run. Metoda load čte příkazy ze vstupního proudu a analyzuje je do kolekce příkazů, metoda run iteruje přes kolekci a provádí každou z příkazů. Třída Program také poskytuje sbírku proměnných pro program používat, stejně jako zásobník pro ukládání dat.

příkaz

třída Statement obsahuje jeden analyzovaný příkaz. Tato třída je ve skutečnosti subklasifikována do určitého typu příkazu (PRINT, GOTO, IF atd.), Ale všechny příkazy obsahují metodu execute, která je volána k provedení příkazu v kontextu instance třídy Program.

výraz

třída Expression obsahuje strom analýzy výrazu. Během provádění se metoda value používá k vyhodnocení výrazu a vrácení jeho hodnoty. Stejně jako Statement je třída Expression primárně navržena tak, aby byla podtříděna specifickými typy výrazů.

všechny tyto třídy pracují společně a tvoří základ tlumočníka. Třída Program současně zapouzdřuje operaci analýzy a provádění, zatímco třídy Statement a Expression zapouzdřují skutečné výpočetní koncepty jazyka, který jsme implementovali. Pro tyto tři články o budování tlumočníků byl ukázkový jazyk základní.

možnosti pro výpočet

v interpretu jsou dvě spustitelné třídy,

Statement

a

Expression

. Nejprve se podívejme na

Expression

instance Expression jsou vytvořeny metodou expression ve třídě ParseExpression. Třída ParseExpression implementuje Parser výrazů v tomto interpretu. Tato třída je peer třídy ParseStatement, která používá metodu statement k analýze základních příkazů. Instance Expression mají interní type, který identifikuje, jaký operátor instance představuje, a dvě metody, value a stringValue, které vracejí vypočtenou hodnotu výrazu. Navíc, když je vytvořena instance výrazu, jsou nominálně dány dva parametry představující levou a pravou stranu operace výrazu. Zobrazeno ve zdrojové podobě, první část výrazu je následující:

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

jak můžete vidět v kódu výše, existují proměnné instance, Typ operátora s názvem oper a dvě poloviny operace v arg1 a arg2 a pak některé konstanty pro definování různých typů. Také existují dva konstruktory, které jsou používány výrazem parser; ty vytvářejí nový výraz ze dvou výrazů. Jejich zdroj je uveden níže:

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

první Konstruktor vytváří libovolný výrazový objekt a druhý Konstruktor vytváří výrazový objekt „unary“ – například unary minus. Jedna věc, kterou je třeba poznamenat, je, že pokud existuje pouze jeden argument, arg2 se používá k uložení jeho hodnoty.

metoda, která se nejčastěji používá ve třídě Expression, je value, která je definována následovně:

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

můžete vidět, že každý objekt výrazu představuje n-tici sestávající z operátora a jednoho nebo dvou argumentů. Zábavná část návrhu expression execution engine tímto způsobem je, že když konstruujete tuto sadu výrazových n-tic na základě objektu Expression, můžete vypočítat hodnotu výrazu pouhým vyvoláním metody value. Metoda value rekurzivně vyvolá metodu value dvou argumentů, které tvoří tento výraz, použije na ně operaci a vrátí výsledek. Tento návrh byl použit tak, aby výrazy byly snadno pochopitelné.

aby byla struktura třídy čistá, jsou všechny výpočetní jednotky-od konstant po trigonometrické funkce-podtřídy Expression. Tato myšlenka, ukradená nestydatě z Lispu, zcela zapouzdřuje pojem „způsobení“ hodnocení, ze skutečné implementace “ jak “ k tomuto hodnocení dochází. Abychom ukázali, jak je tento princip uplatňován, musíme se podívat pouze na některé specializované podtřídy Expression.

konstanty v mé verzi BASIC, kterou jsem pojmenoval COCOA, jsou reprezentovány třídou ConstantExpression, která podtřídy Expression a jednoduše uloží číselnou hodnotu do hodnoty člena. Zdrojový kód ConstantExpression je koncepčně uveden níže. Říkám „koncepčně“, protože jsem se rozhodl spojit to, co by bylo StringConstantExpression a NumericConstantExpression do jedné třídy. Třída real tedy obsahuje konstruktor pro vytvoření konstanty s řetězcovým argumentem a pro vrácení její hodnoty jako řetězce. Následující kód ukazuje, jak třída ConstantExpression zpracovává Číselné konstanty.

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

výše uvedený kód nahrazuje složitější konstruktory Expression jednoduchým ukládáním proměnné instance; metoda value je jednoduše nahrazena návratem uložené hodnoty.

je pravda, že můžete kódovat třídu Expression tak, aby ve svých konstruktorech přijala konstantu, která by vám ušetřila třídu. Nicméně, jedna výhoda navrhování Expression způsob, jakým mám, je, že kód v Expression zůstává maximálně obecný. Zjistil jsem, že tento styl kódování mi pomáhá eliminovat složitost zvláštních případů, a tak když jsem „hotový“ s kódem Expression, mohu přejít k dalším aspektům výrazů, aniž bych znovu a znovu opakoval základní třídu. Výhoda je jasnější, když se ponoříme do jiné podtřídy Expression s názvem FunctionExpression.

ve třídě FunctionExpression existovaly dva konstrukční požadavky, které jsem cítil, že by měly být splněny, aby byl tlumočník flexibilní. První bylo implementovat standardní základní funkce; druhým bylo zapouzdřit analýzu argumentů funkcí do stejné třídy, která tyto funkce implementovala. Druhý požadavek, parsování, byl motivován touhou učinit toto základní rozšiřitelné vytvořením dalších knihoven funkcí, které by mohly být předány analyzátoru jako podtřídy FunctionExpression. Dále by tyto předané třídy mohly být analyzátorem použity ke zvýšení počtu funkcí dostupných pro program uživatele.

třída FunctionExpression je pouze mírně komplikovanější než ConstantExpression a je uvedena v kondenzované formě níže:

 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 }

výše uvedený zdroj ukazuje, jak je implementována metoda value. Proměnná oper se znovu používá k udržení identity funkce a výrazové objekty odkazované arg1 a arg2 se používají jako argumenty pro samotné funkce. Nakonec existuje velké prohlášení o přepínači, které odešle požadavek. Jedním zajímavým aspektem je, že metoda value zachycuje potenciální aritmetické výjimky a převádí je na instance BASICRuntimeError. Parsovací kód v FunctionExpression je uveden níže, opět kondenzovaný, aby se ušetřilo místo. (Pamatujte, že veškerý zdrojový kód je k dispozici pomocí odkazů v sekci Zdroje.)

 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 }

Všimněte si, že tento kód využívá skutečnosti, že analyzátor výrazu v ParseStatement již zjistil, že se dívá na výraz a prošel identitou výrazu jako parametr ty. Tento analyzátor pak stačí najít pouze úvodní závorku a závěrečné závorky, které obsahují argument(y). Ale podívejte se pozorně: v řádcích #9 až #18 parser umožňuje, aby některé funkce neměly žádné argumenty(v tomto případě RND a FRE). To demonstruje flexibilitu poskytovanou tím, že funkce subparser zabudován do této třídy, spíše než nutit všechny funkce, aby odpovídaly nějaké předdefinované šablony. Vzhledem k typu funkce v parametru ty příkaz switch vybere větev, která může analyzovat argumenty potřebné pro tuto funkci, ať už jde o řetězce,čísla, jiné výrazy atd.

další aspekty: řetězce a pole

dvě další části základního jazyka jsou implementovány tlumočníkem COCOA: řetězce a pole. Podívejme se nejprve na implementaci řetězců.

pro implementaci řetězců jako proměnných byla třída Expression upravena tak, aby zahrnovala pojem „string“ výrazů. Tato modifikace měla podobu dvou dodatků: isString a stringValue. Zdroj těchto dvou nových metod je uveden níže.

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

je zřejmé, že pro základní program není příliš užitečné získat hodnotu řetězce základního výrazu(což je vždy číselný nebo booleovský výraz). Z nedostatku užitečnosti můžete usoudit, že tyto metody pak nepatřily do Expression a místo toho patřily do podtřídy Expression. Vložením těchto dvou metod do základní třídy však lze všechny objekty Expression otestovat, zda se ve skutečnosti jedná o řetězce.

dalším návrhovým přístupem je vrátit číselné hodnoty jako řetězce pomocí objektu StringBuffer pro generování hodnoty. Například stejný kód by mohl být přepsán jako:

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

a pokud je použit výše uvedený kód, můžete vyloučit použití isString, protože každý výraz může vrátit hodnotu řetězce. Dále můžete upravit metodu value a pokusit se vrátit číslo, pokud výraz vyhodnotí řetězec spuštěním pomocí metody valueOf java.lang.Double. V mnoha jazycích, jako je Perl, TCL a REXX, se tento druh amorfního psaní používá k velké výhodě. Oba přístupy jsou platné a měli byste se rozhodnout na základě návrhu tlumočníka. V BASIC musí interpret vrátit chybu, když je řetězec přiřazen číselné proměnné, proto jsem zvolil první přístup (vrácení chyby).

pokud jde o pole, existují různé způsoby, jak můžete navrhnout svůj jazyk tak, aby je interpretoval. C používá hranaté závorky kolem prvků pole k rozlišení indexových odkazů pole od odkazů na funkce, které mají závorky kolem jejich argumentů. Návrháři jazyků PRO BASIC se však rozhodli použít závorky jak pro funkce, tak pro pole, takže když analyzátor vidí text NAME(V1, V2), může to být volání funkce nebo odkaz na pole.

lexikální analyzátor rozlišuje mezi tokeny, které jsou následovány závorkami, nejprve za předpokladu, že se jedná o funkce a testování. Pak se uvidí, zda se jedná o klíčová slova nebo proměnné. Právě toto rozhodnutí brání vašemu programu definovat proměnnou s názvem “ SIN.“Jakákoli proměnná, jejíž název odpovídá názvu funkce, by byla lexikálním analyzátorem vrácena jako token funkce. Druhým trikem, který lexikální analyzátor používá, je zkontrolovat, zda název proměnné bezprostředně následuje `(‚. Pokud ano, analyzátor předpokládá, že se jedná o odkaz na pole. Analyzováním v lexikálním analyzátoru odstraníme řetězec ‚MYARRAY ( 2 ) ‚ z interpretace jako platné pole (všimněte si mezery mezi názvem proměnné a otevřenou závorkou).

poslední trik pro implementaci polí je ve třídě Variable. Tato třída se používá pro instanci proměnné, a jak jsem diskutoval ve sloupci minulého měsíce, jedná se o podtřídu Token. Má však také některé stroje na podporu polí a to je to, co ukážu níže:

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;

výše uvedený kód zobrazuje proměnné instance spojené s proměnnou, jako ve třídě ConstantExpression. Člověk musí učinit volbu o počtu tříd, které mají být použity ve srovnání se složitostí třídy. Jednou z možností návrhu může být vytvoření třídy Variable, která obsahuje pouze skalární proměnné, a přidání podtřídy ArrayVariable, která se bude zabývat složitostí polí. Rozhodl jsem se je kombinovat a přeměňovat skalární proměnné v podstatě na pole délky 1.

pokud si přečtete výše uvedený kód, uvidíte indexy pole a multiplikátory. Jsou to proto, že multidimenzionální pole v BASIC jsou implementována pomocí jediného lineárního pole Java. Lineární index do pole Java se vypočítá ručně pomocí prvků multiplikačního pole. Indexy použité v základním programu jsou zkontrolovány z hlediska platnosti jejich porovnáním s maximálním legálním indexem v poli ndx indexů.

například základní pole se třemi rozměry 10, 10 a 8 by mělo hodnoty 10, 10 a 8 uložené v ndx. To umožňuje hodnotiteli výrazu otestovat stav „index mimo hranice“ porovnáním čísla použitého v základním programu s maximálním právním číslem, které je nyní uloženo v ndx. Multiplikační pole v našem příkladu by obsahovalo hodnoty 1, 10 a 100. Tyto konstanty představují čísla, která se používají k mapování ze SPECIFIKACE indexu vícerozměrného pole do SPECIFIKACE indexu lineárního pole. Skutečná rovnice je:

Java Index = Index1 + Index2 * maximální velikost Index1 + Index3 * (MaxSize Index1 * MaxSizeIndex 2)

následující pole Java ve třídě Variable je uvedeno níže.

 Expression expns;

pole expns se používá k řešení polí, která jsou zapsána jako “ A(10*B, i).“V takovém případě jsou indexy spíše výrazy než konstanty, takže odkaz musí obsahovat ukazatele na ty výrazy, které jsou hodnoceny v době běhu. Konečně je tu tento docela ošklivě vypadající kus kódu, který vypočítává index v závislosti na tom, co bylo v programu předáno. Tato soukromá metoda je uvedena níže.

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

při pohledu na výše uvedený kód si všimnete, že kód nejprve zkontroluje, zda byl při odkazování na pole použit správný počet indexů, a poté, že každý index byl v zákonném rozsahu pro tento index. Pokud je zjištěna chyba, je interpretovi vyvolána výjimka. Metody numValue a stringValue vrací hodnotu z proměnné jako číslo nebo řetězec. Tyto dvě metody jsou uvedeny níže.

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

existují další metody pro nastavení hodnoty proměnné, které zde nejsou zobrazeny.

tím, že skryje velkou část složitosti toho, jak je každý kus implementován, když konečně přijde čas na provedení základního programu, je Java kód poměrně přímočarý.

spuštění kódu

kód pro interpretaci základních příkazů a jejich provedení je obsažen v

run

metoda

Program

třídy. Kód pro tuto metodu je uveden níže a já jím projdu, abych poukázal na zajímavé části.

 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 }

výše uvedený kód ukazuje, že metoda runInputStream a OutputStream pro použití jako „konzole“ pro provádějící program. V řádku 3 je objekt výčtu e nastaven na sadu příkazů ze sbírky s názvem stmts. Pro tuto kolekci jsem použil variaci na binární vyhledávací strom nazvaný „červeno-černý“ strom. (Další informace o binárních vyhledávacích stromech naleznete v mém předchozím sloupci o vytváření generických sbírek.)Poté jsou vytvořeny další dvě kolekce-jedna pomocí Stack a druhá pomocí Vector. Zásobník se používá jako zásobník v jakémkoli počítači, ale vektor se používá výslovně pro datové příkazy v základním programu. Konečná kolekce je další červeno-černý strom, který obsahuje odkazy na proměnné definované základním programem. Tento strom je tabulka symbolů, kterou program používá při provádění.

po inicializaci se nastaví vstupní a výstupní toky a pokud e není null, začneme shromažďováním všech deklarovaných dat. To se provádí tak, jak je uvedeno v následujícím kódu.

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

výše uvedená smyčka se jednoduše podívá na všechny příkazy a všechna data, která najde, se poté provedou. Provedení každého datového příkazu vloží hodnoty deklarované tímto příkazem do vektoru datového úložiště. Dále provedeme správný program, který se provádí pomocí tohoto dalšího kódu:

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

jak můžete vidět ve výše uvedeném kódu, prvním krokem je opětovná inicializace e. dalším krokem je načtení prvního příkazu do proměnné s a poté zadání spouštěcí smyčky. Existuje nějaký kód pro kontrolu čekajícího vstupu na vstupním proudu, který umožňuje přerušení průběhu programu zadáním do programu, a poté smyčka zkontroluje, zda příkaz, který má být proveden,bude příkazem dat. Pokud ano, smyčka přeskočí příkaz tak, jak byl již proveden. Je vyžadována spíše spletitá technika provádění všech datových příkazů jako první, protože BASIC umožňuje, aby se datové příkazy, které splňují přečtené příkazy, zobrazovaly kdekoli ve zdrojovém kódu. Pokud je trasování povoleno, vytiskne se stopový záznam a vyvolá se velmi nevýrazný příkaz s = s.execute(this, in, pout);. Krása spočívá v tom, že veškeré úsilí o zapouzdření základních konceptů do snadno pochopitelných tříd činí konečný kód triviální. Pokud to není triviální, možná máte tušení, že by mohl existovat jiný způsob, jak rozdělit svůj design.

zabalení a další myšlenky

interpret byl navržen tak, aby mohl běžet jako vlákno, takže ve vašem programovém prostoru může současně běžet několik vláken COCOA interpreter. Dále s použitím rozšíření funkcí můžeme poskytnout prostředky, kterými mohou tato vlákna vzájemně komunikovat. Existoval program pro Apple II a později pro PC a Unix nazvaný C-robots, což byl systém interagujících „robotických“ entit, které byly naprogramovány pomocí jednoduchého základního derivačního jazyka. Hra poskytla mně a ostatním mnoho hodin zábavy, ale byla také vynikajícím způsobem, jak představit základní principy výpočtu mladším studentům (kteří se mylně domnívali, že jen hrají a neučí se). Subsystémy tlumočníků založené na Javě jsou mnohem výkonnější než jejich protějšky před Javou, protože jsou okamžitě k dispozici na jakékoli platformě Java. COCOA běžel na systémech Unix a Macintoshes ve stejný den, kdy jsem pracoval na počítači se systémem Windows 95. Zatímco Java je poražena nekompatibilitou v implementacích thread nebo window toolkit, to, co je často přehlíženo, je toto: spousta kódu “ prostě funguje.“

Chuck McManis je v současné době ředitelem systémového softwaru ve společnosti FreeGate Corp., start-up financovaný podnikem, který zkoumá příležitosti na internetovém trhu. Před nástupem do FreeGate byl Chuck členem skupiny Java. Připojil se ke skupině Java těsně po založení FirstPerson Inc. a byl členem skupiny portable OS group (skupina odpovědná za OSportion Java). Později, když byl FirstPerson rozpuštěn, zůstal se skupinou prostřednictvím vývoje alfa a betaverze platformy Java. První domovskou stránku „all Java“ vytvořil na internetu, když v květnu 1995 naprogramoval Javaversion domovské stránky slunce. On také vyvinul acryptographic knihovnu pro Javu a verze Java classloader, které by mohly obrazovky tříd na základě digitálních podpisů.Před nástupem do FirstPerson, Chuck pracoval v operačním systemsarea společnosti SunSoft, vývoj síťových aplikací, kde onthe Počáteční návrh NIS+. Taky, podívejte se na jeho domovskou stránku. : END_BIO

další informace o tomto tématu

  • zde jsou odkazy na zdrojové soubory uvedené výše:
    • Konstantexprese.java
    • Funkcevýraz.java
    • Program.java
    • prohlášení.java
    • StringExpression.java
    • proměnná.java
    • VariableExpression.Jáva
  • a tady je .ZIP soubor zdrojových souborů:
    indepth.zip
  • „Uncommon Lisp“ – interpret Lisp napsaný v Javě
    http://user03.blue.aol.com/thingtone/workshop/lisp.htm
  • netrexx tlumočník Mikea Cowlishawa napsaný v Javě
    http://www2.hursley.ibm.com/netrexx/
  • stará kopie základních FAQ USENET (stále obsahuje užitečné informace.)
    http://whitworth.me.ic.ac.uk/people/students/djbur/qbasic.htm
  • kakao, základní tlumočník napsaný v Javě
    http://www.mcmanis.com/~cmcmanis/java/javaworld/examples/BASIC.html
  • Chuckova stránka Java resources
    http://www.mcmanis.com/~cmcmanis/java/javaworld/
  • Tcl interpret napsaný v Javě
    http://www.cs.cornell.edu/home/ioi/Jacl/
  • :
  • „jak vytvořit interpret v Javě, část 2struktura“
    trik při sestavování tříd základů pro jednoduchý tlumočník.
  • „jak vytvořit tlumočníka v Javě, část 1základy“
    pro složité aplikace vyžadující skriptovací jazyk Může být Java použita k implementaci tlumočníka a přidání skriptovacích schopností do jakékoli Java aplikace.
  • „lexikální analýza, část 2buildovat aplikaci“
    jak používat objekt StreamTokenizer k implementaci interaktivní kalkulačky.
  • „lexikální analýza a JavaPart 1“
    Naučte se, jak převést text čitelný člověkem na strojově čitelná data pomocí tříd StringTokenizer a StreamTokenizer.
  • „opětovné použití kódu a objektově orientované systémy“
    použijte třídu pomocníků k vynucení dynamického chování.
  • „podpora kontejnerů pro objekty v Javě 1.0.2“
    uspořádání objektů je snadné, když je vložíte do kontejnerů. Tento článek vás provede návrhem a implementací kontejneru.
  • „základy nakladačů třídy Java“
    základy této klíčové komponenty architektury Java.
  • „nepoužívání garbage collection“
    minimalizujte mlácení haldy ve vašich programech Java.
  • „vlákna a applety a vizuální ovládací prvky“
    tato závěrečná část série zkoumá čtení více datových kanálů.
  • „použití komunikačních kanálů v appletech, Část 3“
    vyvinout techniky ve stylu Visual Basic pro návrh appletů-a převést teploty v procesu.
  • „synchronizace vláken v Javě, Část II“
    Naučte se psát třídu datových kanálů a poté vytvořte jednoduchý příklad aplikace, která ilustruje implementaci třídy v reálném světě.
  • „synchronizace vláken v Javě“
    bývalý vývojář týmu Java Chuck McManis vás provede jednoduchým příkladem, který ilustruje, jak synchronizovat vlákna, aby bylo zajištěno spolehlivé a předvídatelné chování appletu.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.