<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblog.rebex.cz/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Problems presenting features of interest</title><link>http://weblog.rebex.cz/blogs/vbarta/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.2)</generator><item><title>ANTLR v základech softwarové komponenty</title><link>http://weblog.rebex.cz/blogs/vbarta/archive/2008/01/18/antlr-v-z-kladech-softwarov-komponenty.aspx</link><pubDate>Fri, 18 Jan 2008 12:17:00 GMT</pubDate><guid isPermaLink="false">456b44c7-fdf6-4664-b66b-585568c60ca2:2858</guid><dc:creator>vbarta</dc:creator><slash:comments>0</slash:comments><comments>http://weblog.rebex.cz/blogs/vbarta/comments/2858.aspx</comments><wfw:commentRss>http://weblog.rebex.cz/blogs/vbarta/commentrss.aspx?PostID=2858</wfw:commentRss><description>&lt;p&gt;Před pár měsíci jsem se tu

&lt;a href="http://weblog.rebex.cz/blogs/vbarta/archive/2007/09/01/antlr-aneb-jak-neb-t-jelen.aspx"&gt;šířil&lt;/a&gt;

o generátoru parserů &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt;

a jeho použití při tvorbě front-endu transformujícího SQL do formátu vyžadovaného různými databázovými backendy
(teoreticky je SQL standartizovaný jazyk, ovšem v praxi vidí prodejci databází příliš mnoho výhod
v &lt;a href="http://en.wikipedia.org/wiki/Vendor_lock-in"&gt;produktové diferenciaci&lt;/a&gt;,
než aby standartizovali úplně všechno). Předchozí post se omezil na obecný přehled
a první dojmy, ale jelikož jsem od doby jeho napsání zmiňovanou komponentu nejen úspěšně
dokončil, ale dokonce ukecal zákazníka aby ji uvolnil jako Open Source, mám příležitost
vrátit se k tématu podrobněji.&lt;/p&gt;

&lt;p&gt;Komponenta se jmenuje 
&lt;a href="http://macroscope.sourceforge.net/"&gt;MacroScope&lt;/a&gt;, a zvenčí se tváří 
jako víceméně obyčejný

&lt;a href="http://msdn2.microsoft.com/en-us/library/s7ee2dwt%28VS.71%29.aspx"&gt;datový provider&lt;/a&gt;.

Interně ovšem nepracuje přímo s databází, nýbrž

&lt;a href="http://en.wikipedia.org/wiki/Delegation_pattern"&gt;deleguje&lt;/a&gt; na 

"opravdového" providera, a při té příležitosti přepisuje SQL specifikované aplikací tak,
aby mu vnitřní provider rozumněl. Úpravy SQL jsou specifikovány nad jeho gramatikou
("Oracle nezná SELECT TOP, ale zato má funkci ROWNUM, pomocí které se dá zkonstruovat
tentýž výsledek"), takže pro jejich implementaci je prakticky nezbytné SQL parsovat
- a tam právě přišel ke slovu ANTLR.&lt;/p&gt;

&lt;p&gt;Pro parsování SQL se ANTLR rozhodně osvědčil - už proto že je to úloha dost běžná,
aby ji už někdo 

&lt;a href="http://www.antlr.org/grammar/1062280680642/MS_SQL_SELECT.html"&gt;skoro udělal&lt;/a&gt;

(pravda, pro starou verzi ANTLR, pouze SELECT a pouze pro MS SQL Server - MacroScope
podporuje i Oracle a na zvláštní přání publika dokonce MS Access - ale pořád mnohem
lepší než vynalézat kolo). Další velká výhoda formální gramatiky je dokumentační:
podporovaná varianta SQL je přesně to co specifikuje soubor MacroScope.g.
Popsat tu variantu slovně je fakticky dost obtížné - je to podmnožina definic INSERT,
SELECT, UPDATE a DELETE v SQL 92, s přidanými nekompatibilními konstrukcemi
z&amp;nbsp;podporovaných backendů, takže když člověka zajímají detaily, řekněme jak napsat
datum, je formální definice nezastupitelná:&lt;/p&gt;
&lt;pre&gt;MAccessDateTime :
	'#' Digit Digit Digit Digit '-'
		Digit Digit '-' Digit Digit ' '
		Digit Digit ':' Digit Digit ':' Digit Digit
		'#'
	;

Iso8601DateTime :
	Digit Digit Digit Digit '-'
		Digit Digit '-' Digit Digit ( 't' | ' ' )
		Digit Digit ':' Digit Digit ':' Digit Digit
	;
&lt;/pre&gt;

&lt;p&gt;A je to jasné... Nad lexikálními pravidly buduje MacroScope 

&lt;a href="http://en.wikipedia.org/wiki/Object_model"&gt;objektový model&lt;/a&gt;,

tj. např. pro to datum&lt;/p&gt;

&lt;pre&gt;educationalSimplification returns [ INode value ] :
	// subset of an MS Access-specific format
	| MAccessDateTime {
		$value = new LiteralDateTime($MAccessDateTime.text);
	}
	// subset of ISO 8601 recommended for SQL Server 2005
	| Iso8601DateTime {
		$value = new LiteralDateTime($Iso8601DateTime.text);
	}
	;
&lt;/pre&gt;

&lt;p&gt;INode je základní interface definující protokol společný pro
všechny podstromy SQL, od konstant až po kompletní příkaz. Protokol je
to velmi prostý:&lt;/p&gt;

&lt;pre&gt;    public interface INode
    {
        INode Clone();

        void Traverse(IVisitor visitor);
    }
}
&lt;/pre&gt;

&lt;p&gt;Veškeré transformace, včetně transformace stromu na řetězec, dělají

&lt;a href="http://en.wikipedia.org/wiki/Visitor_pattern"&gt;Návštěvníci&lt;/a&gt;.
Technicky by visitor mohl dělat i&amp;nbsp;to klonování, ale rozhodl jsem se že
než být purista, napíšu to radši srozumitelně. Testy na živých programátorech
bylo zjištěno, že výsledný model je v zásadě použitelný pro automatizované
úpravy SQL (typicky přidávání podmínek - je mnohem čistší, srozumitelnější
a bezpečnější přidat objekt než hledat v řetězci "WHERE"), akorát je dost
velký a uživatelé ne vždy vědí kterou třídu instancializovat - ale to už nemá
s&amp;nbsp;ANTLR moc společného...

&lt;/p&gt;&lt;p&gt;Samozřejmě

&lt;a href="http://en.wikipedia.org/wiki/TANSTAAFL"&gt;neexistuje jídlo zdarma&lt;/a&gt; a 
generátor kódu přináší kromě výhod i komplikace. Například takový build
funguje pro jednoduché projekty úplně automaticky z&amp;nbsp;IDE Visual Studia, ale
s&amp;nbsp;generováním kódu moc nepočítá. Visual Studio má 

&lt;a href="http://msdn2.microsoft.com/en-us/library/42x5kfw4%28VS.80%29.aspx"&gt;jakési háky&lt;/a&gt;,

ale logiku dodatečných kroků bych stejně musel programovat ručně v&amp;nbsp;nějakém
dalším jazyce, "podporované" .BAT soubory používat nebudu a

&lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt; nové uživatele zarazí IMHO méně
než řekněme 

&lt;a href="http://aspn.activestate.com/ASPN/Downloads/ActivePerl/"&gt;Perl&lt;/a&gt;. 

Kromě toho jsem stejně chtěl integrovat i unit testy používající

&lt;a href="http://www.nunit.org/index.php"&gt;NUnit&lt;/a&gt;, takže build komponenty dělá NAnt.

Na druhé straně pro ruční práci s projektem (tj. hlavně debugování) má IDE Visual
Studia své výhody, takže jsem se ho pokusil do buildu zahrnout: na nejvyšší
úrovní je build kontrolován ručně psaným skriptem, ale všechny ostatní buildovací
skripty jsou generované pomocí XSLT (NAnt na to má 

&lt;a href="http://nant.sourceforge.net/release/latest/help/tasks/style.html"&gt;příkaz&lt;/a&gt;)

z projektových souborů Visual Studia. Transformace bohužel není dost obecná
aby se dala beze změn používat i&amp;nbsp;v&amp;nbsp;dalších projektech - vždycky se najde
nějaký speciální případ, který je třeba hardcodovat - nicméně v rámci jednoho
projektu je celkem stabilní. Tato organizace umožňuje používat IDE Visual Studia
pro veškerý vývoj (včetně přidávání souborů do projektu) kromě změn gramatiky
a spouštění unit testů. Celkem se osvědčila - největší nevýhodou je že po přidání
souboru musím před spuštěním NAntu uložit projekt - a rozhodně ji zkusím
i&amp;nbsp;při dalších příležitostech.&lt;/p&gt;
 
&lt;p&gt;Jak už jsem se zmiňoval v předchozím postu, ANTLR je živý projekt, bouřlivě se vyvíjí 
a není vždycky možné izolovat MacroScope od jeho nekompatibilních změn, jakkoli
by to bylo žádoucí. Pro překlad existujících zdrojáků není ANTLR nezbytný
(generovaný kód a binární verze ANTLR runtimu jsou součástí distribuce), ale jakékoli
změny gramatiky vyžadují jeho instalaci - na Windows 

&lt;a href="http://www.antlr.org/download.html"&gt;není automatická&lt;/a&gt;, ale na

druhé straně na aplikaci v Javě to není tak hrozné. Co se cílové platformy týče,
MacroScope jsem zkoušel na XP a Vistě, které celkem žádné problémy nedělaly. 
Pro frontend k mnoha databázím Windows CE asi není až tak zajímavou platformou, ale
viděl jsem projekt na PDA, ve kterém by se ANTLR uplatnil, konkrétně pro parsování
konfigurace obsahující jakési vzorečky. Takové projekty by ovšem vyžadovaly
otestování a možná i úpravy ANTLR runtimu pro .NET CF, a jeho rekompilace z nových
zdrojáků by skoro určitě nefungovala s ANTLR 3.01, což je poslední release ANTLR.
Zdrojáky pro C# bohužel nejsou jeho součástí - nějak se u nich zrovna měnil
maintainer, a identifikovat použitelnou verzi v repozitáři by byla pěkná otrava -
takže na drastické úpravy asi bude lepší počkat na ANTLR 3.1, jehož release
se&amp;nbsp;očekává každým dnem. Podle toho co jsem z nové verze viděl, určitě bude obsahovat
mnoho 

&lt;a href="http://en.wikipedia.org/wiki/May_you_live_in_interesting_times"&gt;zajímavých&lt;/a&gt;

změn.&lt;/p&gt;&lt;img src="http://weblog.rebex.cz/aggbug.aspx?PostID=2858" width="1" height="1"&gt;</description></item><item><title>ANTLR aneb jak nebýt jelen</title><link>http://weblog.rebex.cz/blogs/vbarta/archive/2007/09/01/antlr-aneb-jak-neb-t-jelen.aspx</link><pubDate>Sat, 01 Sep 2007 08:22:00 GMT</pubDate><guid isPermaLink="false">456b44c7-fdf6-4664-b66b-585568c60ca2:2377</guid><dc:creator>vbarta</dc:creator><slash:comments>1</slash:comments><comments>http://weblog.rebex.cz/blogs/vbarta/comments/2377.aspx</comments><wfw:commentRss>http://weblog.rebex.cz/blogs/vbarta/commentrss.aspx?PostID=2377</wfw:commentRss><description>&lt;p&gt;Dělal jsem teď v C# jakési úpravy SQL vyžadující jeho
    parsování, a zadavatel navrhl použít

      &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt;.

      Osobně mám po několika pokusech 

      s &lt;a href="http://www.gnu.org/software/bison/manual/"&gt;Bisonem&lt;/a&gt;

      ke generátorům kódu vztah stále neujasněný. Programovat na vyšší
      úrovni je jistě fajn, ale když má pak člověk v gramatice chybu -
      což se mi stává s&amp;nbsp;nepříjemnou pravidelností - komplikují
      extra úrovně abstrakce debugování a generátor, netriviální
      program třetí strany, je spolehlivým zdrojem opravdu
      netriviálních problémů. Musím nicméně uznat, že od dřevních dob

      &lt;a href="http://dinosaur.compilertools.net/yacc/index.html"&gt;jaků&lt;/a&gt;

      a bizonů udělala parsovací technologie podstatný pokrok a ANTLR
      je nástroj rozhodně mocný.

    &lt;/p&gt;&lt;p&gt;Pokrok má samozřejmě i své stinné stránky. Jak se ANTLR
    bouřlivě vyvíjí - nová velká verze 3.0 byla uvolněna letos
    v&amp;nbsp;květnu - dokumentace se poněkud opozdila (s důležitou
    vyjímkou tištěné

      &lt;a href="http://www.pragmaticprogrammer.com/title/tpantlr/"&gt;Definitivní Reference&lt;/a&gt;,

      jejíž užitečnost, nekoupiv, nemohu posoudit), a i&amp;nbsp;bez
      dokumentace je vidět, že ANTLR není

      &lt;a href="http://www.antlr.org:8080/pipermail/antlr-interest/2007-July/022058.html"&gt;bez&lt;/a&gt;

      &lt;a href="http://www.antlr.org:8080/pipermail/antlr-interest/2007-August/023129.html"&gt;kazu&lt;/a&gt;...

      Jiné mé stížnosti do mailing listu se setkaly z hrobovým tichem,
      takže nelze vyloučit, že problém byl mezi mou klávesnicí a
      židlí, ale obecně i&amp;nbsp;autor soudí, že netrpělivě očekávaná
      verze 3.1, napsaná v ANTRL 3.x - verze 3.0 je ještě pořád v
      ANTLR 2 - bude pro některé gramatiky generovat maličko jiné
      jazyky než 3.0.

    &lt;/p&gt;&lt;p&gt;Co se těch gramatik týče, ANTLR na rozdíl od YACCu derivuje
    pravidla zleva, jako typický ručně psaný rekurzivní parser, takže
    pravidla pro ANTLR nesmějí být zleva rekurzivní. Pro YACC běžné
    konstrukce jako

&lt;/p&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;item_list&lt;br&gt;	: item&lt;br&gt;        | item_list ',' item&lt;br&gt;        ;&lt;br&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;expr&lt;br&gt;	: expr '+' subexpr&lt;br&gt;	| subexpr&lt;br&gt;	;&lt;br&gt;&lt;br&gt;&lt;br&gt;subexpr&lt;br&gt;	: subexpr '*' term&lt;br&gt;	| term&lt;br&gt;	;&lt;br&gt;&lt;br&gt;term&lt;br&gt;	: '(' expr ')'&lt;br&gt;	| id&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;&lt;td span="2"&gt;jsou v ANTLRu ilegální a je nutné je přepsat na&lt;/td&gt;&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;item_list&lt;br&gt;	: item ( ',' item )*&lt;br&gt;        ;&lt;br&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;expr&lt;br&gt;	: subexpr ( '+' subexpr )*&lt;br&gt;	;&lt;br&gt;&lt;br&gt;&lt;br&gt;subexpr&lt;br&gt;	: term ( '*' term )*&lt;br&gt;	;&lt;br&gt;&lt;br&gt;term&lt;br&gt;	: '(' expr ')'&lt;br&gt;	| id&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

    &lt;p&gt;Syntax opakování - ANTLR má ()*, ()+ i
    ()?, přičemž znak za závorkou má stejný význam jako
    kvantifikátor regulárního výrazu - je ještě celkem mechanická
    změna. Hlubší problém představují gramatiky parsovatelné YACCem

      (&lt;a href="http://en.wikipedia.org/wiki/LALR"&gt;LALR&lt;/a&gt;,

      pro akademicky orientované čtenáře), které nelze parsovat shora
      dolů s žádným konečným lookaheadem (jsou mimo

      &lt;a href="http://en.wikipedia.org/wiki/LL_parser"&gt;LL(k)&lt;/a&gt;).

      Takové gramatiky nejsou nijak vyjímečné - LR parsery, redukující
      vstup zdola nahoru, jsou silnější než LL v tom smyslu, že mohou
      udržovat stav zahrnující více pravidel pro dlouhý úsek vstupu,
      dokud ho jednoznačný token nerozsekne.

    &lt;/p&gt;&lt;p&gt;ANTLR toto omezení řeší tzv. 

      &lt;a href="http://www.antlr.org/blog/antlr3/lookahead.tml"&gt;syntaktickými predikáty&lt;/a&gt;,

      což je z mého primitivního pohledu prostě syntax pro parsování
      metodou pokusu a omylu. Např. jedno z pravidel (gramatiky

      &lt;a href="http://www.antlr.org/grammar/1062280680642/MS_SQL_SELECT.html"&gt;původně pro ANTLR 2.7.2&lt;/a&gt;)

      parsování podmínek v SQL je

&lt;/p&gt;&lt;pre&gt;subSearchCondition&lt;br&gt;      :&lt;br&gt;	( NOT )? (&lt;br&gt;		(bracketedSearchCondition) =&amp;gt;&lt;br&gt;			bracketedSearchCondition&lt;br&gt;		| predicate&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;

    v próze "když se vstup dá parsovat jako ozávorkovaná podmínka, je
    to ozávorkovaná podmínka, jinak to musí být predikát". Mimochodem
    token NOT je token, protože začíná velkým písmenem. ANTLR generuje
    separátní lexer a parser, ale oba ze stejné gramatiky - pravidla
    pro lexer a pro parser jsou syntakticky rozlišena velikostí jejich
    prvního písmena.

    &lt;p&gt;V jistém smyslu jednodušším příkladem syntaktického predikátu
    je parsování tradiční konstrukce if then else,

      &lt;a href="http://en.wikipedia.org/wiki/Dangling_else"&gt;známé svou nejednoznačností:&lt;/a&gt;

      else následující po několika vnořených if může
      technicky patřit ke kterémukoli z nich, a jazyky
      s&amp;nbsp;if musí pro rozhodnutí tohoto případu
      specifikovat nějaké extra pravidlo, typicky že každé
      else patří k nejbližšímu kandidátovi. V syntaxi ANTLR
      (z tutorialu

      &lt;a href="http://javadude.com/articles/antlrtut/"&gt;původně pro ANTLR 2.7.2&lt;/a&gt;):

&lt;/p&gt;&lt;pre&gt;ifStatement&lt;br&gt;	: 'if' '(' expression&lt;br&gt;		')' statement&lt;br&gt;			( ( 'else' ) =&amp;gt; 'else' statement )?&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;

     Někteří lidé prý vidí, že tato konstrukce má správnou semantiku -
     a my ostatní si to můžeme otestovat...

    &lt;p&gt;Pro ladění gramatik existuje sofistikované GUI,

    &lt;a href="http://www.antlr.org/works/index.html"&gt;ANTLRWorks&lt;/a&gt;,

    které má ovšem z mého hlediska zásadní nevýhodu: podporuje pouze
    Javu, rodnou platformu ANTLR. Pro celkový projekt to není až
    takový problém - javovská třída generátoru se dá spustit z
    příkazové řádky, začlenění generovaného kódu do spustitelného
    programu je popsáno v online dokumentaci a build se dá
    automatizovat pro &lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt;,
    ale interaktivní debugger se do takového postroje cpe špatně,
    takže většinu gramatik jsem testoval přidáním akcí a spuštěním
    testovacího programu.

&lt;/p&gt;&lt;pre&gt;ifStatement&lt;br&gt;@init { string curExpr = null; }&lt;br&gt;	: 'if' '(' e = expression {&lt;br&gt;			curExpr = $e.returnValue;&lt;br&gt;		} ')' statement {&lt;br&gt;			Console.WriteLine("then of {0}", curExpr);&lt;br&gt;		} ( ( 'else' ) =&amp;gt; 'else' statement {&lt;br&gt;			Console.WriteLine("else of {0}", curExpr);&lt;br&gt;		} )?&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;

    &lt;p&gt;Akce jsou psány zhruba v tom programovacím jazyce, který ANTLR
    generuje - kromě Javy je podporováno i C#, C
    a další. Kód akce není zkopírován do výstupu generátoru
    zcela beze změn, nýbrž je interpretován jako šablona pro knihovnu

      &lt;a href="http://www.stringtemplate.org/"&gt;StringTemplate&lt;/a&gt;,

      která ho integruje s generovaným parserem, tj. hlavně nahrazuje
      jména začínající '$' skutečnými vnitřními proměnnými
      parseru. Blok @init je užitečný pro lokální deklarace:
      ANTLR ho umisťuje na začátek funkce implementující specifikované
      pravidlo a garantuje, že se v průběhu parsování odpovídající
      části vstupu vykoná právě jednou - což pro kód akcí přirozeně
      neplatí.

    &lt;/p&gt;&lt;p&gt;V&amp;nbsp;příkladu nahoře je proměnná e automaticky
    deklarována jako lokální proměnná metody ifStatement,
    s&amp;nbsp;typem vraceným metodou expression. Generované
    metody defaultně nevracejí nic co bych chtěl zpracovávat (buď
    void, nebo interní typy, podle stylu gramatiky), ale je
    možné přidat specifické hodnoty - např. expression
    použitá výše má deklarovaný atribut returnValue, který se
    nastavuje v jejích akcích:

&lt;/p&gt;&lt;pre&gt;expression returns [ string returnValue ]&lt;br&gt;	: Number { $returnValue = $Number.text; }&lt;br&gt;	| Identifier { $returnValue = $Identifier.text; }&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;

    &lt;p&gt;Pravidla lexeru takto dekorovat nelze - vracejí vždy instanci
    třídy Token, mezi jejíž standardní atributy patří zejména
    text (v C#; Java má metody getText() a
    setText()).

    &lt;/p&gt;&lt;p&gt;Semantické rozdíly lexeru a parseru jsou vůbec mnohem
    podstatnější, než by naivní uživatel mohl soudit z jejich
    analogické syntaxe. Patrně nejzásadnějším je, že pravidla lexeru
    nemají hierarchii - kdykoli lexer rozezná na vstupu token, zahrne
    do něj co nejvíc znaků a je mu jedno, je-li výsledek z hlediska
    parseru platný nebo ne. V jednoduchých případech - např. pro
    tokeny '&amp;lt;', '&amp;lt;=' a '=' - je nejdelší možný token správně, ale
    často je nutné nastavit ho ručně v akci, např.

&lt;/p&gt;&lt;pre&gt;fragment&lt;br&gt;Digit : '0'..'9' ;&lt;br&gt;&lt;br&gt;fragment&lt;br&gt;Integer :;&lt;br&gt;&lt;br&gt;fragment&lt;br&gt;Real :;&lt;br&gt;&lt;br&gt;Number :&lt;br&gt;	'.' { $type = '.'; } ( (Digit)+ { $type = Real; } )?&lt;br&gt;	| (Digit)+ { $type = Integer; } ( '.' (Digit)* { $type = Real; } )?&lt;br&gt;	;&lt;br&gt;&lt;/pre&gt;
    
    Fragmenty jsou tokeny používané pouze v definici jiných tokenů -
    jinými slovy lexer je nikdy nerozeznává.

    &lt;p&gt;A to je snad všechno, co člověk potřebuje, aby mohl ze
    vstupního kódu udělat tradiční

      &lt;a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt;

      - byť samozřejmě zdaleka ne všechno co ANTLR umí. Jen namátkou, má 

      &lt;a href="http://www.antlr.org/blog/antlr3/hoisting.tml"&gt;semantické predikáty&lt;/a&gt;,

      &lt;a href="http://www.antlr.org/wiki/display/ANTLR3/Attribute+and+Dynamic+Scopes"&gt;stav sdílený mezi pravidly&lt;/a&gt;,

      &lt;a href="http://www.antlr.org/article/1100569809276/use.tree.grammars.tml"&gt;dvoudimenzionální parsování stromovými gramatikami&lt;/a&gt;

      a spoustu dalších vymožeností, jejichž systematický popis zabral
      knihu - kdybych s ním měl začít znova, nehledal bych dokumentaci
      po blozích, ale šel bych ke 

      &lt;a href="http://parr-research.com/%7Eparrt/"&gt;kováři&lt;/a&gt;

      a investoval padesát dolarů do primárního zdroje...

  
&lt;/p&gt;&lt;img src="http://weblog.rebex.cz/aggbug.aspx?PostID=2377" width="1" height="1"&gt;</description></item><item><title>Tygr v českém rybníce</title><link>http://weblog.rebex.cz/blogs/vbarta/archive/2007/07/02/tygr-v-esk-m-rybn-ce.aspx</link><pubDate>Mon, 02 Jul 2007 18:08:00 GMT</pubDate><guid isPermaLink="false">456b44c7-fdf6-4664-b66b-585568c60ca2:2089</guid><dc:creator>vbarta</dc:creator><slash:comments>0</slash:comments><comments>http://weblog.rebex.cz/blogs/vbarta/comments/2089.aspx</comments><wfw:commentRss>http://weblog.rebex.cz/blogs/vbarta/commentrss.aspx?PostID=2089</wfw:commentRss><description>
&lt;p&gt;Pro vyhledávání na českém internetu už léta používám
    
      &lt;a href="http://www.seznam.cz/"&gt;českou jedničku&lt;/a&gt;,
      nicméně poslední dobou nelze přehlédnout, že se o náš rybníček
      zajímá i jistý světový vyhledávač, a tak jsem začal přemýšlet,
      nestačil-li by všem mým dotazům
      &lt;a href="http://www.google.com/"&gt;jeden&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
    &lt;img src="http://www.mangrove.cz/rebex/tigerDM2805_468x472.jpg"&gt;
Obrázek z &lt;a href="http://www.dailymail.co.uk/pages/live/articles/news/worldnews.html?ct=5&amp;amp;icc=picbox&amp;amp;icl=TabModule&amp;amp;ico=Homepage&amp;amp;in_article_id=458282&amp;amp;in_page_id=1811"&gt;Daily Mail&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Problém samozřejmě je, že jakkoli existují i tygři, kterým by
    se ryby (úplně jedno jak dravé) měly ve vlastním zájmu vyhnout, ne
    všem velkým šelmám voda vyhovuje. Méně metaforicky, je pro dotazy
    v češtině lepší používat vyhledávač obecný, nebo specializovaný? 
    Na takovou otázku pochopitelně existuje řada odpovědí (včetně
    "42"); níže je pouze jeden skromný pokus konkretizovat ji pro mé
    potřeby a tím pádem v jistém smyslu částečně možná i zodpovědět.
    &lt;/p&gt;

&lt;p&gt;Pro začátek budeme potřebovat nějakou množinu dotazů, kterou
    předhodíme testovaným vyhledávačům. Nejjednodušší mi připadalo
    (poté co jsem prozkoumal několik slepých uliček - celý tento popis
    je &lt;em&gt;velmi&lt;/em&gt; souhrnný) získat jí z "našeptávače",
    navrhujícího populární dotazy začínající specifikovanými
    písmeny. Aby to bylo spravedlivé, nevezmeme našeptávač žádného z
    porovnávaných vyhledávačů (taky bysme mohli vzít oba, ale to je
    víc práce), ale nějaký jiný (&lt;a href="http://www.centrum.cz/"&gt;co se
    nabízí&lt;/a&gt;) a zeptáme se ho, jaké dotazy navrhuje pro všechna
    písmena abecedy.
    &lt;/p&gt;

&lt;table&gt;

&lt;tr&gt;&lt;th&gt;autorita&lt;/th&gt;&lt;th&gt;počet dotazů&lt;/th&gt;&lt;/tr&gt;
	
&lt;tr&gt;
&lt;td&gt;centrum.cz&lt;/td&gt;

&lt;td&gt;479&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;


    To bude tak akorát počet pro malý experiment, a je to množina s
    &lt;em&gt;fascinujícím&lt;/em&gt; rozsahem (upřímně řečeno pro mé potřeby až
    příliš velkým - neumím si představit že bych hledal řekněme
    "operní árie dante" - ale já stejně česky moc nevyhledávám, takže
    se spokojím s populárním výběrem).&lt;/p&gt;&lt;p&gt;
      Získat HTML stránky s odpověďmi na zpracovávané dotazy není tak
      těžké - většinu technických detailů můžeme vynechat. Google se
      trochu cukal, ale stačilo mu podstrčit

      &lt;a href="http://en.wikipedia.org/wiki/Referrer"&gt;Referer&lt;/a&gt; a
      &lt;a href="http://en.wikipedia.org/wiki/User_agent"&gt;User Agent&lt;/a&gt;,

      aby se s mým klientem začal bavit - ani nevím jestli se mě
      snažil přesvědčit abych používal

      &lt;a href="http://code.google.com/apis/"&gt;Google API&lt;/a&gt; a nebo to
      mají prostě špatně naprogramované. Co se týče API,

      &lt;a href="http://vyvojari.seznam.cz/api/"&gt;má ho i Seznam&lt;/a&gt;, ale
      zjevně ne pro obecné dotazy, a i kdyby oba vyhledávače měly API
      vyhovující mým nápadům, určitě nebudou stejná. Nebudeme se párat
      s hledáním vchodu pro dodavatele a použijeme brutální sílu.

    &lt;/p&gt;&lt;p&gt;
      Na výsledcích dotazů nás zajímají hlavně linky. Dostat z HTML
      hodnoty atributu href elementu a je opět
      standardní úloha, ale problém je, že ne všechny linky jsou pro
      nás zajímavé. Rozeznat interní linky (do téže domény) je snadné,
      ale pak jsou tam inzeráty, které chceme taky ignorovat - naším
      cílem je zjistit kdo má lepší vyhledávač, ne kdo má víc
      inzerentů. Stránky každého vyhledávače mají nicméně docela
      pravidelnou strukturu, takže v&amp;nbsp;zásadě je možné

      &lt;a href="http://en.wikipedia.org/wiki/Web_scraping"&gt;napsat skript&lt;/a&gt;,

      který vybere pouze "opravdové" linky (s přijatelným počtem
      chyb). Knihovna interpretující seznamy linků dokonce ani nemusí
      být specifická pro pouze jeden vyhledávač - abych se přiznal,
      nejdůležitější motivací tohoto projektu bylo, že jsem si jednu
      takovou napsal a chtěl ji vyzkoušet. Je veřejně přístupná, ale
      v&amp;nbsp;tomto textu ji nebudu rozvádět - jsme koneckonců na blogu
      o&amp;nbsp;.NET, takže pouze poznamenám, že by koneckonců bylo
      docela dobře možné napsat ji třeba v C#... :-)

    &lt;/p&gt;&lt;p&gt;
      Řekněme tedy že máme linky odpovídající jednotlivým dotazům jak
      na Google, tak na Seznam:

      &lt;/p&gt;&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;autorita&lt;/th&gt;&lt;th&gt;počet linků&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;google.cz&lt;/td&gt;&lt;td&gt;4762&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;seznam.cz&lt;/td&gt;&lt;td&gt;4672&lt;/td&gt;&lt;/tr&gt;
      &lt;/table&gt;

    &lt;p&gt;
      A dál? No, pro začátek můžeme zjistit, jsou-li stejné. Zběžný
      pohled nás přesvědčí, že nejsou úplně stejné (kdyby byly, dal
      bych se do hledání chyby v mém programu), takže se budeme muset
      rozhodnout, jak vypadá "skoro stejný" výsledek a vůbec jak
      kvantifikovat podobnost. Po zralé úvaze (a hodu mincí) jsem se
      rozhodl porovnávat nikoli celá URL, ale pouze jejich hosty -
      jestli Seznam a Google doporučují pro tentýž dotaz různé
      příspěvky v jednom blogu, je to vpodstatě totéž...

      &lt;/p&gt;&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;autorita&lt;/th&gt;&lt;th&gt;počet různých hostů&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;google.cz&lt;/td&gt;&lt;td&gt;2886&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;seznam.cz&lt;/td&gt;&lt;td&gt;3313&lt;/td&gt;&lt;/tr&gt;
      &lt;/table&gt;&lt;p&gt;

    ...a pořád to nevypadá nijak zvlášť zajímavě (že má Google víc
    linků na hosta než Seznam je nejspíš artefakt toho, že jsem se
    dotazoval jen na první stránku - Google na ní má košatější
    stromy)...

    &lt;/p&gt;&lt;p&gt;
      Zajímavější je, že většina hostů je jiná pro Seznam než pro
      Google - společných je jich pouze 508, tj. v zhruba jeden host
      na dotaz. A samozřejmě se nemusíme ptát pouze na průměr, ale
      můžeme se podívat na jednotlivé dotazy:

    &lt;/p&gt;&lt;ol&gt;&lt;li&gt;Doporučují někdy Google a Seznam úplně stejnou množinu hostů?
      &lt;/li&gt;&lt;li&gt;Doporučují někdy překrývající se množiny?
      &lt;/li&gt;&lt;li&gt;Existují dotazy, na které Google a Seznam odpovídají zcela jinak?
    &lt;/li&gt;&lt;/ol&gt;

    Na první otázku je odpověď negativní - maximální shoda je 6 hostů
    (z maximálně 10 na první stránce) na jeden dotaz. Interpretoval
    bych to tak, že Internet je prostě plný šuntu, a i když ho
    vyhledávače spoustu odfiltrují, pořád ho ve výsledcích dost
    zbývá. Četnost dalších možností je v tabulce:

      &lt;table&gt;
	&lt;tr&gt;&lt;th&gt;výsledek&lt;/th&gt;&lt;th&gt;počet dotazů&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;částečná shoda&lt;/td&gt;&lt;td&gt;419&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;úplně jinde&lt;/td&gt;&lt;td&gt;60&lt;/td&gt;&lt;/tr&gt;
      &lt;/table&gt;

    &lt;p&gt;
      Google a Seznam vidí ten samý český rybníček dost jinak, aby
      bylo možné, že jeden z nich ho vidí líp - ale který? I kdybych
      chtěl ručně zkontrolovat statisticky významný zlomek těch linků
      (jako že mě to ani nehne), kvalitu linků na (např.) "účesy pro
      polodlouhé vlasy" obávám se neposoudím...

    &lt;/p&gt;&lt;p&gt;
      Dáme hlasovat. Zeptáme se jiných vyhledávačů (Centra a

      &lt;a href="http://www.atlas.cz/"&gt;ještě jednoho&lt;/a&gt;) a zjistíme, na
      kterých dotazech se shodnou (na 197). Hosty společné těmto
      dotazům prohlásíme za konsensuální realitu a spočteme, kolikrát
      se do ní Seznam a Google trefí:

      &lt;/p&gt;&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;autorita&lt;/th&gt;&lt;th&gt;počet úspěchů&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;google.cz&lt;/td&gt;&lt;td&gt;138&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;seznam.cz&lt;/td&gt;&lt;td&gt;125&lt;/td&gt;&lt;/tr&gt;
      &lt;/table&gt;

    No, moc výrazný rozdíl to není... Co takhle podívat se jen na ty
    dotazy, na kterých se Seznam s Googlem vůbec neshodnou?

      &lt;table&gt;
	&lt;tr&gt;&lt;th&gt;autorita&lt;/th&gt;&lt;th&gt;počet úspěchů&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;google.cz&lt;/td&gt;&lt;td&gt;11&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;seznam.cz&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;
      &lt;/table&gt;

    To už je relativně větší rozdíl, ovšem dostáváme se nepříjemně
    blízko k nule... Možná jsou ty vyhledávače přece jen všechny na
    jedno brdo...

  
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://weblog.rebex.cz/aggbug.aspx?PostID=2089" width="1" height="1"&gt;</description></item><item><title>Co je to jméno...</title><link>http://weblog.rebex.cz/blogs/vbarta/archive/2004/05/10/304.aspx</link><pubDate>Mon, 10 May 2004 18:38:00 GMT</pubDate><guid isPermaLink="false">456b44c7-fdf6-4664-b66b-585568c60ca2:304</guid><dc:creator>vbarta</dc:creator><slash:comments>0</slash:comments><comments>http://weblog.rebex.cz/blogs/vbarta/comments/304.aspx</comments><wfw:commentRss>http://weblog.rebex.cz/blogs/vbarta/commentrss.aspx?PostID=304</wfw:commentRss><description>...nikoli tedy růže, ale jméno &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemtextencodingclasstopic.asp"&gt;System.Text.Encoding&lt;/a&gt;. Instance této třídy mají ne méně než čtyři jména: &lt;tt&gt;BodyName&lt;/tt&gt;, &lt;tt&gt;EncodingName&lt;/tt&gt;, &lt;tt&gt;HeaderName&lt;/tt&gt; a &lt;tt&gt;WebName&lt;/tt&gt; (a to nepočítám &lt;tt&gt;CodePage&lt;/tt&gt;), jejichž dokumentace se v zásadě omezuje na příklady: "If this encoding is equivalent to UTF8Encoding, this property returns "utf-8"," jak pro &lt;tt&gt;BodyName&lt;/tt&gt;, tak &lt;tt&gt;HeaderName&lt;/tt&gt; - ale cožpak &lt;a href="http://www.mhonarc.org/~ehood/MIME/"&gt;MIME RFC&lt;/a&gt; nespecifikují &lt;em&gt;tatáž&lt;/em&gt; jména pro hlavičky a těla? ISO kódování (aspoň těch pár běžných, co jsem zkoušel - ISO-8859-{1,2,4,5} a pár dalších, které můj systém podporuje) mají naštěstí &lt;tt&gt;BodyName&lt;/tt&gt; stejné jako &lt;tt&gt;HeaderName&lt;/tt&gt; - a jelikož &lt;tt&gt;WebName&lt;/tt&gt; (jediné jméno podporované .NET CF) je taky to samé, zdá se, že klienti .NETu vystačí s jedním kanonickým jménem - když vědí, které vybrat...&lt;img src="http://weblog.rebex.cz/aggbug.aspx?PostID=304" width="1" height="1"&gt;</description></item><item><title>Web Services vs. přístupová práva</title><link>http://weblog.rebex.cz/blogs/vbarta/archive/2004/03/15/282.aspx</link><pubDate>Mon, 15 Mar 2004 22:48:00 GMT</pubDate><guid isPermaLink="false">456b44c7-fdf6-4664-b66b-585568c60ca2:282</guid><dc:creator>vbarta</dc:creator><slash:comments>0</slash:comments><comments>http://weblog.rebex.cz/blogs/vbarta/comments/282.aspx</comments><wfw:commentRss>http://weblog.rebex.cz/blogs/vbarta/commentrss.aspx?PostID=282</wfw:commentRss><description>&lt;p&gt;&lt;a href="http://weblog.rebex.cz/vbarta/posts/191.aspx"&gt;.NET security&lt;/a&gt; se
mě nějak nechce pustit - tentokrát v kontextu Web Services...&lt;/p&gt;

&lt;p&gt;Píšu servis, který zprostředkuje přístup k databázi
&lt;a href="http://www.microsoft.com/exchange/"&gt;Exchange serveru&lt;/a&gt;, a píšu
ho v C# - je to můj první Web Service, a tato RPC architektura i programovací
jazyk jsou koneckonců vyvíjené společně, takže by se neměly nijak tlouct.
Neměly...&lt;/p&gt;

&lt;p&gt;Můj Web Service implicitně běží jako Network Service, což kupodivu
&lt;em&gt;není&lt;/em&gt; "user name" (přinejmenším
&lt;a href="http://logging.apache.org/log4net/"&gt;log4net&lt;/a&gt; tvrdí, že
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecurityprincipaliidentityclassnametopic.asp"&gt;Principal.Identity.Name&lt;/a&gt;
je v tomto kontextu prázdný řetězec),
nýbrž
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconprincipalidentityobjects.asp"&gt;Windows Identity&lt;/a&gt;
&lt;tt&gt;NT AUTHORITY\NETWORK SERVICE&lt;/tt&gt;. Proč je tak složité
získat
&lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0312862075/102-0807004-9307305?v=glance"&gt;pravé jméno&lt;/a&gt;? :-)&lt;/p&gt;

&lt;p&gt;Network Service může ledacos, ale jednou z věcí, které nezvládá, je otevření
Exchange mailboxu. Network Service nejspíš žádný mailbox nemá (což je jen dobře -
těžko od tohoto účtu očekávat, že si bude číst poštu), jenže selhává, i když se pokusí
otevřít mailbox někoho jiného (a kdyby jen selhával - ani si nestěžuje). 
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdoex_collaboration_data_objects.asp"&gt;CDO&lt;/a&gt;
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdo_idatasource_open.asp"&gt;IDataSource.Open&lt;/a&gt;
sice &lt;em&gt;má&lt;/em&gt; parametry pro uživatelské jméno a heslo, ale ať jsem tam cpal cokoli,
k ničemu to nevedlo...&lt;/p&gt;

&lt;p&gt;Takže jsem se rozhodl sestoupit z výšin .NETu a 
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemSecurityPrincipalWindowsIdentityClassImpersonateTopic.asp"&gt;impersonovat&lt;/a&gt;.
To zafungovalo lépe - dokázal jsem se přihlásit jako administrátor. Jako jiný uživatel ale bohužel nikoli :-(
- volám-li
&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/logonuser.asp"&gt;LogonUser&lt;/a&gt;
s parametrem &lt;tt&gt;LOGON32_LOGON_INTERACTIVE&lt;/tt&gt;, vysvětlí mi server, že obyčejní
uživatelé nemají na interaktivní přihlášení nárok, zatímco použiju-li
&lt;tt&gt;LOGON32_LOGON_NETWORK&lt;/tt&gt;, dozvím se od .NETu, že vzdálení uživatelé nemají
co natahovat dynamické knihovny:&lt;/p&gt;

&lt;pre&gt;
System.IO.FileLoadException: Access is denied: 'ADODB'.
&lt;/pre&gt;

&lt;p&gt;Člověk by očekával, že tyto dvě operace se dají provést odděleně, pod různými účty - ale
dosud je mi to nepovedlo...&lt;/p&gt;
&lt;img src="http://weblog.rebex.cz/aggbug.aspx?PostID=282" width="1" height="1"&gt;</description></item></channel></rss>