%strict
%token ID INT INTEGER
%syntactic token HEX
%right '='
%left '+'
%{
use base 'DebugTail';
my %st;
%}
%tree bypass alias
%%
stmt:
decl <* ';'> expr <%name EXPS + ';'>
{
$_[2]->{st} = { %st };
$_[2];
}
;
decl:
INT ID <+ ','>
{
$st{$_->{attr}} = 1 for $_[2]->children();
}
;
expr:
%name ID
$ID
{
my $parser = shift;
my $hexflag = $parser->{HEXFLAG};
if ($hexflag and !exists($st{$ID}) and $ID =~ m{^([A-F0-9]+$)}) {
Parse::Eyapp::Node->new('NUM', sub { $_[0]->{attr} = hex($ID) });
}
else {
Parse::Eyapp::Node->new('ID', sub { $_[0]->{attr} = $ID });
}
}
| %name NUM
INTEGER
| %name HEX
HEX '(' { $_[0]->{HEXFLAG} = 1; } $expr { $_[0]->{HEXFLAG} = 0 } ')'
{ $expr }
| %name ASSIGN
id '=' expr
| %name PLUS
expr '+' expr
;
id : ID
;
%%
# Context-dependant lexer
__PACKAGE__->lexer( sub {
my $parser = shift;
for (${$parser->input}) { # contextualize
m{\G\s*(\#.*)?}gc;
m{\G(HEX\b|INT\b)}igc and return (uc($1), $1);
m{(\G\d+)}gc and return ('INTEGER', $parser->{HEXFLAG}? hex($1) : $1);
return ('ID', $1) if m{\G([a-zA-Z_]\w*)}gc;
m{\G(.)}gc and return ($1, $1);
return('',undef);
}
}
);
*TERMINAL::info = *NUM::info = *ID::info = sub {
$_[0]->{attr}
};
__PACKAGE__->main unless caller();
=head1 SYNOPSIS
Compile it with:
eyapp -b '' Tieins.eyp
Run it with:
./Tieins.pm -t -f inputforsemanticinfo.txt
try also:
./Tieins.pm -t -f inputforsemanticinfo2.txt
=head1 THIS EXAMPLE
In this "Calc"-like example we have a language with a special construct C<hex
(hex-expr)>. After the keyword C<hex> comes an C<expression> in parentheses in
which all integers are hexadecimal. In particular, strings in C</[A-F0-9]+/>
like C<A1B> must be treated as an hex integer unless they were previously
declared.
=head1 SEE ALSO
=over 2
=item * File C<SemanticInfoInTokens.eyp>
=item * L<http://www.gnu.org/software/bison/manual/html_mono/bison.html#Lexical-Tie_002dins>
=item * L<http://en.wikipedia.org/wiki/The_lexer_hack>
=item * L<http://eli.thegreenplace.net/2007/11/24/the-context-sensitivity-of-cs-grammar/>
=back