blob: 15e50d6d222b636df0fbaae82d0492e8250b865e [file] [log] [blame]
grammar t022scopes;
options {
language=JavaScript;
}
/* global scopes */
scope aScope {
names
}
a
scope aScope;
: {$aScope::names = [];} ID*
;
/* rule scopes, from the book, final beta, p.147 */
b[v]
scope {x}
: {$b::x = v;} b2
;
b2
: b3
;
b3
: {$b::x}?=> ID // only visible, if b was called with True
| NUM
;
/* rule scopes, from the book, final beta, p.148 */
c returns [res]
scope {
symbols
}
@init {
$c::symbols = {};
}
: '{' c1* c2+ '}'
{ $res = $c::symbols; }
;
c1
: 'int' ID {$c::symbols[$ID.text] = true;} ';'
;
c2
: ID '=' NUM ';'
{
if (! $c::symbols[$ID.text]) {
throw new Error($ID.text);
}
}
;
/* recursive rule scopes, from the book, final beta, p.150 */
d returns [res]
scope {
symbols
}
@init {
$d::symbols = {};
}
: '{' d1* d2* '}'
{ $res = $d::symbols; }
;
d1
: 'int' ID {$d::symbols[$ID.text] = true;} ';'
;
d2
: ID '=' NUM ';'
{
var i, isDefined;
for (i=$d.length-1, isDefined=false; i>=0; i--) {
if ($d[i]::symbols[$ID.text]) {
isDefined = true;
break;
}
}
if (!isDefined) {
throw new Error("undefined variable "+$ID.text);
}
}
| d
;
/* recursive rule scopes, access bottom-most scope */
e returns [res]
scope {
a
}
@after {
$res = $e::a;
}
: NUM { $e[0]::a = parseInt($NUM.text, 10); }
| '{' e '}'
;
/* recursive rule scopes, access with negative index */
f returns [res]
scope {
a
}
@after {
$res = $f::a;
}
: NUM { var len = $f.length-2; $f[len>=0 ? len : 0]::a = parseInt($NUM.text, 10); }
| '{' f '}'
;
/* tokens */
ID : ('a'..'z')+
;
NUM : ('0'..'9')+
;
WS : (' '|'\n'|'\r')+ {$channel=HIDDEN;}
;