【问题标题】:GCC Preprocessor how to replace #define with empty lineGCC预处理器如何用空行替换#define
【发布时间】:2020-06-17 10:34:58
【问题描述】:

我正在尝试将 GCC 预处理器与 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 保留 cmets。

是否可以用空行替换预处理指令的所有行?

【问题讨论】:

    标签: javascript gcc c-preprocessor preprocessor preprocessor-directive


    【解决方案1】:

    跑步

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

    反对(3 行)

    #define ASDF 'asdf'
    
    var asdf = ASDF
    

    产量(1 行)

    var asdf = 'asdf'
    

    因此,并非所有请求的行都是空的,而是它们被完全删除了。也许这符合你的目的?使用-traditional-cpp,有一堆空行,但不知道它们来自哪里...添加-v 以查看gcc 发出了哪些子命令打印:

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

    附录1:为了保存cmets,添加-C

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

    我需要-nostdinc,否则 gcc 会包含/usr/include/stdc-predef.h。但是空行仍然被删除。

    【讨论】:

    • 谢谢,但是我想在原始源和输出之间保持行号相同。这样如果输出中的 JS 代码有任何错误,行号应该与原始文件中的行号匹配。 (我会用这个更新问题。)如果没有参数-traditional-cpp,它会删除所有空行并删除所有额外的空格。
    • 我在问题中的示例中添加了示例注释。 cmets 应该保留,因为它们可以是多行 cmets,如果它们被删除,行号将不匹配,因此 cmets 也应该保留。
    • @gregn3 : 我添加了-C 保留 cmets 的注释。
    • 我创建了一个 Perl 脚本来创建预处理器的中间输入,这将产生正确的输出。我已将其发布在下面。这是一个正在进行的工作,但我想分享它。
    • 我找到了原始命令 (/usr/bin/cpp -P -undef -Wundef -std=c99 -nostdinc -Wtrigraphs -fdollars-in-identifiers -C) here,但仅保留行号是不够的。
    【解决方案2】:

    我创建了一个 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 扩展名。

    生成文件

    %.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 $_'`
    

    【讨论】:

      猜你喜欢
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多