G CC Препроцессор как заменить #define пустой строкой - PullRequest
0 голосов
/ 04 марта 2020

Я пытаюсь использовать препроцессор G CC с исходным кодом Javascript.

Я хотел бы сохранить одинаковые номера строк между исходным источником и выходом. Так что, если в выводе кода JS есть какие-либо ошибки, номера строк должны совпадать с номерами строк в исходном файле.

Я бы хотел получить следующий вывод из этого ввода:

Line 1 // comment
Line 2 #define ASDF 'asdf'
Line 3
Line 4 var asdf = ASDF

Вывод:

Line 1 // comment
Line 2 
Line 3 
Line 4 var asdf = 'asdf'

Как мне достичь вышеуказанного?

До сих пор я пробовал:

/usr/bin/cpp -P -undef -Wundef -std=c99 -nostdinc -Wtrigraphs -fdollars-in-identifiers -traditional-cpp -E -C $INFILE -o $OUTFILE

-traditional-cpp сохраняет пробелы, а -E сохраняет комментарии.

Можно ли заменить все строки директивами препроцессора на пустые строки?

Ответы [ 2 ]

1 голос
/ 05 марта 2020

Запуск

gcc -xc file.c -E -P -o file.txt

против (3 строки)

#define ASDF 'asdf'

var asdf = ASDF

выходов (1 строка)

var asdf = 'asdf'

Таким образом, не все запрошенные строки пусты , но они были удалены полностью. Может быть, это соответствует вашей цели? С -traditional-cpp, есть куча пустых строк, не знаю, откуда они берутся, хотя ... Добавление -v, чтобы увидеть, какие подкоманды выдают gcc print:

.../cc1 -E -quiet -v -P -o file.txt <irrelevant-options>

Приложение 1: Чтобы сохранить комментарии, добавьте -C

cpp file.c -E -P -C -nostdinc

Мне нужен -nostdinc, потому что в противном случае g cc будет включать /usr/include/stdc-predef.h. Однако пустые строки все еще удаляются.

0 голосов
/ 06 марта 2020

Я создал сценарий 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 $_'`
...