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