Asm-Preproc
view release on metacpan or search on metacpan
lib/Asm/Preproc.pm view on Meta::CPAN
return $1;
}
}
shift @input; # end of input
}
};
$self->_push_iter($iter, "-");
}
#------------------------------------------------------------------------------
# prepare the object to read the given iterator and file name
sub _push_iter {
my($self, $iter, $file) = @_;
# new file in the stack
push @{$self->_stack}, Asm::Preproc::File->new($iter, $file);
}
#------------------------------------------------------------------------------
=head2 getline
Returns the next line from the input, after doing all the pre-processing.
The line is returned as a L<Asm::Preproc::Line|Asm::Preproc::Line> object
containing the actual text, and the file and line number where the text
was found.
Returns C<undef> at the end of the input.
=cut
#------------------------------------------------------------------------------
# return next line as a Asm::Preproc::Line object
sub getline {
my($self) = @_;
while (1) {
return undef unless @{$self->_stack}; # no more files
my $top = $self->_stack->[TOP];
# read line
my $text = $top->iter->();
if (! defined $text) { # file finished, read next
pop @{$self->_stack};
next;
}
# inc line number, save it to use as the line_nr of a multi-line
# continuation
my $line_nr = $top->line_nr( $top->line_nr + $top->line_inc );
# while line ends in \\, remove all blanks before it and \r \n after
# the line contains at most one \n, due to include_list() iterator
while ($text =~ s/ \s* \\ [\r\n]* \z / /x) {
my $next = $top->iter->();
$top->line_nr( $top->line_nr + $top->line_inc );
defined($next) or last; # no more input, ignore last \\
$text .= $next;
}
# normalize eol
$text =~ s/ \s* \z /\n/x; # any ending blanks replaced by \n
# line to be returned, is used in %include below
my $line = Asm::Preproc::Line->new($text, $top->file, $line_nr);
# check for pre-processor directives
if ($text =~ /^ \s* [\#\%] /gcix) {
if ($text =~ / \G line /gcix) {
# %line n+m file
# #line n "file"
if ($text =~ / \G \s+ (\d+) /gcix) { # line_nr
$top->line_nr( $1 );
if ($text =~ / \G \+ (\d+) /gcix) { # optional line_inc
$top->line_inc( $1 );
}
else {
$top->line_inc( 1 );
}
if ($text =~ / \G \s+ \"? ([^\"\s]+) \"? /gcix) { # file
$top->file( $1 );
}
# next line in nr+inc
$top->line_nr( $top->line_nr - $top->line_inc );
next; # get next line
}
}
elsif ($text =~ / \G include /gcix) {
# %include <file>
# #include 'file'
# %include "file"
# #include file
if ($text =~ / \G \s+ (?: \< ([^\>]+) \> |
\' ([^\']+) \' |
\" ([^\"]+) \" |
(\S+)
) /gcix) {
my $file = $1 || $2 || $3 || $4;
$self->include($file, $line);
next; # get next line
}
else {
$line->error("%include expects a file name\n");
}
}
else {
# ignore other unknown directives
next; # get next line
}
}
else {
# TODO: macro expansion
}
# return complete line
return $line;
}
}
( run in 1.417 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )