190 likes | 402 Views
Interpreter (design pattern). Bc. Martin Petru ňa 30 .10.2012 SAI. Interpreter zo života. Máme jazyk: h u d b a Jeho reprezentáciu: n o t y A niekoho, kto ho interpretuje : h u d o b n í k. Definícia.
E N D
Interpreter (design pattern) Bc. Martin Petruňa 30.10.2012 SAI
Interpreter zoživota • Máme jazyk: • h u d b a • Jeho reprezentáciu: • n o t y • A niekoho, kto ho • interpretuje: • h u d o b n í k
Definícia • Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language (podľa GoF). • Predstavuje spôsob výpočtu ohodnotenia (interpretácie) na základe reprezentácie konkrétnej inštancie z jazyka. Nestará sa o konštrukciu. • Radíme ho k behaviorálnymnávrhovým vzorom (podľa GoF).
Motivácia • Trieda problémov sa opakovane vyskytuje v jednoduchej a dobre popísateľnej doméne. • Ak doménu charakterizujem jazykom, potom môžem tieto problémy (slová jazyka) riešiť pomocou nejakého interpretačného „stroja“. • Teda namapujemdoménu na jazyk, jazyk na gramatiku a gramatiku na hierarchickú štruktúru objektov.
Účastníci • AbstractExpression – deklaruje metódu interpret(), ktorá je spoločná pre všetky uzly(objekty) abstraktného syntaktického stromu. • TerminalExpression – reprezentuje terminálne symboly v gramatike, samostatná inštancia pre každý terminálny symbol vstupu. • NonterminalExpression – reprezentuje neterminály(pravidlá) v gramatike. Pre každé pravidlo samostatný typ: • reprezentuje pravidlo R::=R1R2…RNgramatiky • udržuje AbstractExpression pre každý symbol R1R2…RN
Účastníci • Context– udržuje globálne informácie pre celý Interpreter. • Client – disponuje abstraktným syntaktickým stromom, ktorý reprezentuje slovo z jazyka definovaného príslušnou gramatikou. Uzly tohto stromu sú tvorené inštanciami TerminalExpressiona NonterminalExpression. Client je ten, kto volá metódu interpret().
Príklad z knihy DesignPatterns: ElementsofReusableObject-Oriented Software (K.Zhang) Příklad: gramatika regulárního výrazu: • expression ::= literal | alternation | sequence | repetition | '(' expression ')' • alternation ::= expression '|' expression • sequence ::= expression '&' expression • repetition ::= expression '*' • literal ::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }*
Schéma inštancie návrhového vzoru Pozor na smer šípky – definuje typ a zoznam argumentov – objektov.
Príklad inštancie syntaktického stromu • Reprezentáciaregexu: • raining& ( dog | cats)* • expression ::= literal | alternation | sequence | repetition | '(' expression ')' • alternation::= expression '|' expression • sequence ::= expression '&' expression • repetition::= expression '*' • literal::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }*
Príklad - Boolovské výrazy • BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp | '(' BooleanExp ')' • AndExp ::= BooleanExp 'and' BooleanExp • OrExp ::= BooleanExp 'or' BooleanExp • NotExp ::= 'not' BooleanExp • Constant ::= 'true' | 'false' • VariableExp ::= 'A' | 'B' | ... | 'X' | 'Y' | 'Z' Spoločný interface pre všetky triedy definujúce korektný boolean výraz. class BooleanExp { public: BooleanExp(); virtual ~BooleanExp(); virtual bool Evaluate(Context&) = 0; virtual BooleanExp* Replace(const char*, BooleanExp&) = 0; virtual BooleanExp* Copy() const = 0; }; Kontext popisuje ohodnotenie premenných – elementárnych výrokov. class Context { public: bool Lookup(const char*) const; void Assign(VariableExp*, bool); };
Príklad - Boolovské výrazy class VariableExp : public BooleanExp { public: VariableExp(const char*); virtual ~VariableExp(); virtual bool Evaluate(Context&); virtual BooleanExp* Replace(const char*, BooleanExp&); virtual BooleanExp* Copy() const; private: char* _name; }; VariableExp::VariableExp (const char* name) { _name = strdup(name); } boolVariableExp::Evaluate (Context& aContext) { return aContext.Lookup(_name); } BooleanExp* VariableExp::Copy () const { return new VariableExp(_name); } BooleanExp* VariableExp::Replace (const char* name, BooleanExp& exp) { if (strcmp(name, _name) == 0) return exp.Copy(); else return new VariableExp(_name); } Typ reprezentujúci terminálny výraz – premennú. Premenná je identifikovaná menom. Metóda evaluate v úlohe metódy „interpret“ využíva globálnu informáciu z kontextu
Príklad - Boolovské výrazy class AndExp : public BooleanExp { public: AndExp(BooleanExp*, BooleanExp*); virtual ~ AndExp(); virtual bool Evaluate(Context&); virtual BooleanExp* Replace(const char*, BooleanExp&); virtual BooleanExp* Copy() const; private: BooleanExp* _operand1; BooleanExp* _operand2; }; AndExp::AndExp (BooleanExp* op1, BooleanExp* op2) { _operand1 = op1; _operand2 = op2; } boolAndExp::Evaluate (Context& aContext) { return_operand1->Evaluate(aContext) &&_operand2->Evaluate(aContext); } BooleanExp* AndExp::Copy () const { returnnew AndExp(_operand1->Copy(), _operand2->Copy()); } BooleanExp* AndExp::Replace (const char* name, BooleanExp& exp) { returnnew AndExp( _operand1->Replace(name, exp), _operand2->Replace(name, exp) ); } Typ reprezentujúci neterminálny výraz – „pravidlo pre AND“. Obe „symboly“ z pravidla AND typu BooleanExp Interpretácia objektu tohto typu spočíva v logickom súčine interpretácií oboch synov.
Príklad - Boolovské výrazy BooleanExp* expression; Context context; VariableExp* x = new VariableExp("X"); VariableExp* y = new VariableExp("Y"); expression = new OrExp( new AndExp(new Constant(true), x), new AndExp(y, new NotExp(x)) ); context.Assign(x, false); context.Assign(y, true); bool result = expression->Evaluate(context); Vytvorenie reprezentácie výrazu: (true AND x)OR(y AND NOT(x)) Vytvoreniekontextu pre interpretáciu výrazu – zadefinovanie ohodnotenia premenných. VariableExp* z = new VariableExp("Z"); NotExpnot_z(z); BooleanExp* replacement = expression->Replace("Y", not_z); context.Assign(z, true); result = replacement->Evaluate(context); Môžeme previesť interpretáciu celého „slova“. Potom môžeme napr. zmeniť kontext, a zopakovať. Alebo môžeme zmeniť reprezentáciu, a opäť vyhodnotiť.
Vzťahy k iným vzorom • Composite – Abstraktný syntaxovýstrom je realizácia návrhového vzoru Composite. • Flyweight – Pomocou Flyweight je možné realizovať zdieľanie terminálnych uzlov v rámci stromu. • Iterator – Prechádzanie stromom je možné realizovať pomocou Iterátora (Kurzor typu Uzol). • Visitor – sa využije vtedy, ak je potreba „parametrizovať“ interpretáciu.
Iné poznámky • Vhodné pre jednoduché gramatiky, v opačnom prípade je objektový graf neprehľadný a ťažkopádny. • Efektívne interpretéry typicky najprv prevádzajú stromovú štruktúru do efektívnejšie spracovateľnej štruktúry. • Výhody: • Ľahko rozširovateľná gramatika • Relatívne ľahko možno pridať nové formy interpretácie
Príklady využitie v Jave • Parsery v org.hibernate.hql.classic.* • Node v org.w3c.dom.* • javax.el.ELResolver (JSF) • java.text.Normalizer • java.text.Format • java.util.regex.Pattern