Překladač a obfuskátor ECMAScriptu Jan Pobříslo - semestrální práce PJP Zadání Zadáním semestrální práce je překladač pro ECMAScript (v. 262) z jazyka rozšířeného o třídní dědění (ECMAScript používá dědění prototypové). Dalším požadavkem na překladač je co nejkratší výstupní kód, s možným nahrazením jmen identifikátorů. Implementace Obecně Semestrální práce implementuje univerzální tokenizer založený na stavovém automatu. Jsou implementovány následující automaty: lex js: Tokenizer dle standartu ECMA-262. lex rules: Tokenizer pro specifikaci syntaktických pravidel. Semestrální práce implementuje univerzální LL(1) překladač pro definovanou gramatiku s automatickým generátorem rezkurzivního sestupu a podporou sémantických pravidel. Syntaktická pravidla mohou být zadána přímo jako objekty pythonu nebo pomocí speciálního jazyka pro zadávání syntaktických pravidel včetně sémantiky. Jazyk pro syntaktická pravidla Jazyk používá běžnou formu zápisu syntaktických pravidel: Start -> Element1 Element2 Každé syntaktické pravidlo je ukončeno středníkem a za ním může následovat libovolný počet sémantických pravidel. 1
Sémantika Pravidla se zapisují ve formě přiřazení: $Element1.atribut1 = $Element2.atribut2 $Element1.atribut1 = "python expression" Identifikátorem pro element může být název elementu, pokud je v pravidle jedinečný, např. $StringLiterar, nebo celé číslo určené pozicí v pravidle. $0 je nejlevější expandovaný terminál / neterminál / výstupní symbol. Pro výstup pravidla je určen speciální identifikátor proměnné $$ Elementy Jednotlivé elementy syntaktických pravidel mohou být zapsány pomocí speciální syntaxe pro zjednodušení sémantických pravidel. (Element) Výstupní element. V okamžiku když se výstupní element dostnane na vrchol zásobníku, je vypsán pomocí funkce syntactical.analyser.output(). <Element> Rozpíše element jako bez závorek a výsledek je jako v předchozím případě poslán na výstup. [Element] Rozpíše element jako bez závorek a výsledek je nastaven jako návratová hodnota pravidla. Každý element který obsahuje nealfanumerické znaky musí být uzavřen do uvozovek, např. <")">. Zvýraznění syntaxe Vytvořil jsem soubor s jednoduchým zvýrazněním syntaxe pro editor vim: rules.vim. Pravděpodobně nejjednoduší způsob jak zvýraznění nainstalovat je zkopírovat ho do složky ~/.vim/syntax/ a poté přidat následující řádek do souboru ~/.vim/filetype.vim: au BufNewFile,BufRead *.rules setf rules Implementace Parser pro syntaktická pravidla jsem vytvořil syntaxi v pythonu a pro ověrění i v nově vytvořeném jazyce. V jazyce pro syntaktycká pravidla má téměř poloviční počet řádek a je podstatně přehlednější. Implementace v jazyce pro syntaktická pravidla (soubor rules_test.rules): Rules ->; Rules -> <Rule> Rules; Rule -> Identifier "->" RuleNext ";" Semantic; $$ = "(r0,r2,r4)" 2
RuleNext ->; $$ = "[]" RuleNext -> RuleIdentifier RuleNext; $$ = "[r0]+r1" RuleIdentifier -> IdentifierExpression; $$ = "(r0, normal )" RuleIdentifier -> "(" IdentifierExpression ")"; $$ = "(r1, out )" RuleIdentifier -> "<" IdentifierExpression ">"; $$ = "(r1, print )" RuleIdentifier -> "[" IdentifierExpression "]"; $$ = "(r1, return )" IdentifierExpression -> [Identifier]; IdentifierExpression -> [Expression]; Semantic ->; $$ = "[]" Semantic -> LeftVariableField "=" VariableFieldOrExp Semantic; $$ = "[(r0,r2)]+r3" LeftVariableField -> LeftVariable [Field]; $Field.var = $LeftVariable LeftVariable -> [ReturnVariable]; LeftVariable -> [Variable]; Field ->; $$ = "(var,none)" Field -> "." Identifier; $$ = "(var,r1)" VariableFieldOrExp -> Variable [Field]; $Field.var = $Variable VariableFieldOrExp -> [Expression]; Variable -> [IndexVariable]; Variable -> [NameVariable]; Program podporuje automatické generování diagramů pro pravidla, viz soubor generate_dot.py. Zde je diagram pravidel a neterminálů pro jazyk syntaktických pravidel: 3
ECMAScript Parser je řešen dle specifikace ECMA-262. Vynechání ze specifikace Ze specifikace jsem vypustil množinový operátor in, jelikož kvůli konstruktu for ( Left- HandSideExpression in Expression ) Statement by byla nutná duplicita většiny pravidel ve variantě bez tohoto operátoru. Viz poznámka v sekci 11.4 Relational Operators specifikace ECMAScriptu. Dále specifikace určuje automatické doplňování středníků, viz 7.9.1 Rules of Automatic Semicolon Insertion. Tyto pravilda jsou poměrně koplexní a nad rámec semestrální práce. Funkce Semestrální práce má dvě rozdílné funkcionality: 4
překlad tříd: program jsx překlad jmen identifikátorů: program jsreplace Obě funkcionality jsou poměrně základní. Hlubší analýza jmen identifikátorů by byla poměrně náročná kvůli dynamické povaze jazyka. Třídnímu dědění nyní chybí definice konstruktorů, které z časových důvodů nejsem schopen implementovat. Závěr Funkcionalita překladače je poměrně omezená, ale díky jazyku pro specifikaci syntaktických pravidel je poměrně lehce rozšířitelná. 5