1 grammar t022scopes; 2 3 options { 4 language=JavaScript; 5 } 6 7 /* global scopes */ 8 9 scope aScope { 10 names 11 } 12 13 a 14 scope aScope; 15 : {$aScope::names = [];} ID* 16 ; 17 18 19 /* rule scopes, from the book, final beta, p.147 */ 20 21 b[v] 22 scope {x} 23 : {$b::x = v;} b2 24 ; 25 26 b2 27 : b3 28 ; 29 30 b3 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 38 c returns [res] 39 scope { 40 symbols 41 } 42 @init { 43 $c::symbols = {}; 44 } 45 : '{' c1* c2+ '}' 46 { $res = $c::symbols; } 47 ; 48 49 c1 50 : 'int' ID {$c::symbols[$ID.text] = true;} ';' 51 ; 52 53 c2 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 64 d returns [res] 65 scope { 66 symbols 67 } 68 @init { 69 $d::symbols = {}; 70 } 71 : '{' d1* d2* '}' 72 { $res = $d::symbols; } 73 ; 74 75 d1 76 : 'int' ID {$d::symbols[$ID.text] = true;} ';' 77 ; 78 79 d2 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 98 e returns [res] 99 scope { 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 112 f returns [res] 113 scope { 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 */ 125 ID : ('a'..'z')+ 126 ; 127 128 NUM : ('0'..'9')+ 129 ; 130 131 WS : (' '|'\n'|'\r')+ {$channel=HIDDEN;} 132 ; 133