1grammar t022scopes; 2 3options { 4 language=JavaScript; 5} 6 7/* global scopes */ 8 9scope aScope { 10names 11} 12 13a 14scope aScope; 15 : {$aScope::names = [];} ID* 16 ; 17 18 19/* rule scopes, from the book, final beta, p.147 */ 20 21b[v] 22scope {x} 23 : {$b::x = v;} b2 24 ; 25 26b2 27 : b3 28 ; 29 30b3 31 : {$b::x}?=> ID // only visible, if b was called with True 32 | NUM 33 ; 34 35 36/* rule scopes, from the book, final beta, p.148 */ 37 38c returns [res] 39scope { 40 symbols 41} 42@init { 43 $c::symbols = {}; 44} 45 : '{' c1* c2+ '}' 46 { $res = $c::symbols; } 47 ; 48 49c1 50 : 'int' ID {$c::symbols[$ID.text] = true;} ';' 51 ; 52 53c2 54 : ID '=' NUM ';' 55 { 56 if (! $c::symbols[$ID.text]) { 57 throw new Error($ID.text); 58 } 59 } 60 ; 61 62/* recursive rule scopes, from the book, final beta, p.150 */ 63 64d returns [res] 65scope { 66 symbols 67} 68@init { 69 $d::symbols = {}; 70} 71 : '{' d1* d2* '}' 72 { $res = $d::symbols; } 73 ; 74 75d1 76 : 'int' ID {$d::symbols[$ID.text] = true;} ';' 77 ; 78 79d2 80 : ID '=' NUM ';' 81 { 82 var i, isDefined; 83 for (i=$d.length-1, isDefined=false; i>=0; i--) { 84 if ($d[i]::symbols[$ID.text]) { 85 isDefined = true; 86 break; 87 } 88 } 89 if (!isDefined) { 90 throw new Error("undefined variable "+$ID.text); 91 } 92 } 93 | d 94 ; 95 96/* recursive rule scopes, access bottom-most scope */ 97 98e returns [res] 99scope { 100 a 101} 102@after { 103 $res = $e::a; 104} 105 : NUM { $e[0]::a = parseInt($NUM.text, 10); } 106 | '{' e '}' 107 ; 108 109 110/* recursive rule scopes, access with negative index */ 111 112f returns [res] 113scope { 114 a 115} 116@after { 117 $res = $f::a; 118} 119 : NUM { var len = $f.length-2; $f[len>=0 ? len : 0]::a = parseInt($NUM.text, 10); } 120 | '{' f '}' 121 ; 122 123 124/* tokens */ 125ID : ('a'..'z')+ 126 ; 127 128NUM : ('0'..'9')+ 129 ; 130 131WS : (' '|'\n'|'\r')+ {$channel=HIDDEN;} 132 ; 133