Я создал сценарий Perl для создания промежуточного файла, который создает и обеспечивает правильное количество пустых строк, так что после запуска препроцессора выходные данные будут иметь то же количество строк и совпадающих номеров строк, что и вход.
Это черновая версия, в которой есть некоторые незавершенные / неиспользованные части, но она уже решает основную проблему в приведенном выше вопросе и может быть полезна другим в той же ситуации. Пока я тестировал только минимально.
Я использую его с Makefile, пример выложен ниже.
keep_preprocessor_emptylines.pl
#!/usr/bin/perl
# example usage of PPEXTRALINES:
#
# #define SOMEFUNC__PPEXTRALINES_4_ \
# function hello () \
# { \
# console.log ('hello world') \
# }
#
# # the above will be replaced with a single line
# SOMEFUNC__PPEXTRALINES_4_
#
#
# expecting the input filename on a line by itself preceding the input lines
my $input_filename;
my $multiline_sig = '__PPEXTRALINES_(\d+)_';
my $ensure_n_empty_lines_follow = 0;
my $line_num = -1 -1; # -1 gives the correct line numbers in the error message below... intended 0 here originally
# the second -1 is for the input filename that precedes the input
while (<STDIN>)
{
$line_num++;
if ($line_num == -1)
{
$input_filename = $_;
chomp $input_filename;
next;
}
my $is_empty_line = ($_ =~ /^\s*$/gm);
if ($ensure_n_empty_lines_follow > 0)
{
if (!$is_empty_line)
{
chomp;
my $n = $ensure_n_empty_lines_follow;
my $es = $n == 1 ? '' : 's';
print STDERR '(' . __FILE__ . "): \"$input_filename\": error on line $line_num: expected $n empty line$es here, but found non-empty line\nline: \"$_\"\n";
exit -1
}
else
{
# ok ,remove this empty line, because it will be replaced by the contents of the preceding macro
$ensure_n_empty_lines_follow--;
next;
}
}
#my $is_directiveline = ($_ =~ /^\s*([#!][ \t]{1,}?([A-z]{2,})[\s]{1,}?([A-z]{2,}[\s]{1,}?)?)([\\(]?[^\s\\)]{1,}[\\)]?)?/);
my $is_directiveline = ($_ =~ /^\s*[#!][ \t]*([A-z]{2,})\s+([A-z0-9_]{2,})\b/);
my $directive_name = $1;
my $second_word = $2;
my $has_multiline_sig = ($_ =~ /$multiline_sig/);
my $n_extra_lines = int ($1);
if ($has_multiline_sig)
{
if ($is_directiveline)
{
my $is_the_definition = (($directive_name eq 'define') && ($second_word =~ /$multiline_sig/));
if ($is_the_definition)
{
# insert that number of lines + 1 above it
print ("\n" x ($n_extra_lines + 1));
}
else
{
# otherwise it might be used in another macro, we should ignore it there
# print one empty line above it, since it's a macro line
print ("\n");
}
}
else
{ # is a usage
# ensure at least ($n_extra_lines + 1) empty lines follow it.
# fail with error if not.
# then remove those empty lines, so they will be replaced by the macro's contents
# this seems unnecessary, only would be needed if the macro expands to multiple lines, which the example above doesn't
# uncomment the below line to enable ensuring enough empty lines follow the macro
# might need to create a new special name for these
# the current PPEXTRALINES one only supports a multiple-line definition, but single line expansion
#$ensure_n_empty_lines_follow = $n_extra_lines + 1;
}
}
elsif ($is_directiveline)
{ # other macro line
# print one empty line above it
print ("\n");
}
print $_;
}
Makefile обрабатывает все файлы с расширением .P. js и преобразует их в файлы . js, запустив на нем промежуточный скрипт и препроцессор. Промежуточные файлы создаются временно с расширением .Pke. js.
Makefile
%.js : %.P.js
echo "$<" | cat - "$<" | ./keep_preprocessor_emptylines.pl > "$(patsubst %.P.js,%.Pke.js,$<)"
/usr/bin/cpp -P -undef -Wundef -std=c99 -nostdinc -Wtrigraphs -fdollars-in-identifiers -traditional-cpp -E -C "$(patsubst %.P.js,%.Pke.js,$<)" -o "$@"
rm "$(patsubst %.P.js,%.Pke.js,$<)"
Я вызываю Makefile с этим команда, может быть, она может быть добавлена в сам Makefile, но у меня все равно работает:
make `ls -1 *.P.js | perl -ne '$_ =~ s/\.P\.js$/\.js/; print $_'`