How to check GCC preprocessor on specific lines in source code

Is there a way to reset the entire current preprocessor at some point in the source file? Or another way to check for changes in preprocessor directives between two points in the source file?

I did not find anything here . Here is an example to give an idea:

#define FOO

#pragma message "defines before whatever.h"
#pragma please_dump_all_defines
#include <whatever.h>
#pragma message "defines after whatever.h"
#pragma please_dump_all_defines

// rest of the file

A method of obtaining information will work differently, for example, with gcc -E, given that the FOOabove can affect what is precisely determined by the included file, and can track several #define/ #undefetc.

+4
source share
2 answers

, GCC , , -dCHARS, CHARS, , .

, :

foo.c

#define B 1
#define C 2
#pragma message Begin
#include "bar.h"
#pragma message End
#undef B
#undef C
#define B 4
#define C 5 

bar.h

#ifndef BAR_H
#define BAR_H

#undef B
#undef C
#ifdef A
#define B 2
#define C 3
#endif

#endif

:

cpp -dD foo.c

-dD #define|#undef . 500 , :

# 1 "<command-line>" 2
# 1 "foo.c"
#define B 1
#define C 2

# 3 "foo.c"
#pragma message Begin
# 3 "foo.c"

# 1 "bar.h" 1

#define BAR_H 

#undef B
#undef C
# 5 "foo.c" 2

# 5 "foo.c"
#pragma message End
# 5 "foo.c"

#undef B
#undef C
#define B 4
#define C 5

:

cpp -dD -DA foo.c

( ):

# 1 "<command-line>" 2
# 1 "foo.c"
#define B 1
#define C 2

# 3 "foo.c"
#pragma message Begin
# 3 "foo.c"

# 1 "bar.h" 1

#define BAR_H 

#undef B
#undef C

#define B 2     //<- New with -DA
#define C 3     //<- New with -DA
# 5 "foo.c" 2

# 5 "foo.c"
#pragma message End
# 5 "foo.c"

#undef B
#undef C
#define B 4
#define C 5

script:

  • 1) #define|#undef, , #pragma message Begin, .
  • 2) 1) #pragma message End.
  • 3) /.

, , ( ) , script ( ):

macrodiff.py

#!/usr/bin/python

import sys, argparse, os, string, re, subprocess, shlex
from subprocess import call, CalledProcessError

class macro_directive:
    def __init__(self,directive = None,name = None,definition = None):
        self.__directive = directive
        self.__name = name
        self.__definition = definition
    def __eq__(self,other):
        return  self.__name == other.__name and \
                self.__directive == other.__directive and \
                self.__definition == other.__definition
    def __neq__(self,other):
        return not __eq__(self,other)
    @property
    def empty(self):
        return not self.__directive
    @property
    def directive(self):
        return self.__directive
    @property
    def name(self):
        return self.__name
    @property
    def definition(self):
        return self.__definition

    @property
    def desc(self):
        desc = self.__directive + ' ' + self.__name
        if self.__definition:
            desc += ' '
            desc += self.__definition
        return desc

    @staticmethod
    def read(line):
        match = re.match('^\s*#\s*(define|undef)\s+(\w+) \s*(.*)$',line)
        if match:
            directive = match.group(1)
            name = match.group(2)
            if directive == 'define':
                return macro_directive(directive,name,match.group(3))
            else:
                return macro_directive(directive,name)
        else:
            return macro_directive()
    @staticmethod
    def make_dict(lines):
        d = {}
        for line in lines:
            md = macro_directive.read(line);
            if not md.empty:
                d[md.name] = md
        return d


def find_marker(lines,marker):
    for i, line in enumerate(lines):
        if line.find(marker) == 0:
            return i;
    return -1

def split_by_marker(lines,marker):
    mark_i = find_marker(lines,marker)
    if mark_i != -1:
        return [lines[:mark_i],lines[mark_i:]]
    return [[],lines]

parser = argparse.ArgumentParser(
    prog="macrodiff",
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description='Extract changes in simple preprocessor macro values between' +
        ' two marked points in a C/C++ translation unit. ' +
        'Function-like macros are not supported')
parser.add_argument('-s', '--start', metavar='STARTSTR',required=True,
    help='The initial macro values will be those in effect when the' +
        ' first line commencing with STARTSTR is read')
parser.add_argument('-e', '--end', metavar='ENDSTR',
    help='The final macro values will be those in effect when the first line' +
    ' commencing with ENDSTR is read, or if --end is not given then those' +
    ' in effect at end-of-file ')
parser.add_argument('--pp', default='cpp -dD',metavar='PP',
    help='PP is the preprocessor command to invoke. Default \'cpp -dD\'')
parser.add_argument('--ppflags',default='',metavar='PPFLAGS',
    help='PPFLAGS are additional options to be passed to PP')
parser.add_argument('infile',metavar='FILE',nargs=1,
    help='FILE is a C/C++ source file to be processed')

args = vars(parser.parse_args())
startstr = args['start'];
endstr = args['end'];
stdout = ''
command = args['pp'] + ' ' + args['ppflags'] + ' ' + args['infile'][0]

try:
    stdout = subprocess.check_output(shlex.split(command))
except CalledProcessError, e:
    sys.stderr.write( '***Error: Command \"' + command + '\" failed: \"' + \
        e.output + '\": ' + 'syscode = ' + str(e.returncode) + '\n')
    sys.exit(e.returncode)
lines = stdout.splitlines();
lines_before,lines_after = split_by_marker(lines,startstr);
if not lines_before:
    sys.stderr.write( '***Error: STARTSTR \"' + startstr + '\" not found\n')
    sys.exit(1)
if endstr:
    lines_after, ignore = split_by_marker(lines_after,endstr);
    if not lines_after:
        sys.stderr.write( '***Error: ENDSTR \"' + endstr + '\" not found\n')
        sys.exit(1)

directives_dict_before = macro_directive.make_dict(lines_before)
directives_dict_after = macro_directive.make_dict(lines_after)
intersection = \
    directives_dict_before.viewkeys() & directives_dict_after.viewkeys()

for key in intersection:
    before = directives_dict_before[key]
    after = directives_dict_after[key]
    if before != after:
        print 'BEFORE[' + before.desc + '] AFTER[' + after.desc +']'  

sys.exit(0)

$ ./macrodiff.py -h
usage: macrodiff [-h] -s STARTSTR [-e ENDSTR] [--pp PP] [--ppflags PPFLAGS]
                    FILE

Extract changes in simple preprocessor macro values between two marked points in a C/C++ translation unit. Function-like macros are not supported

positional arguments:
  FILE                  FILE is a C/C++ source file to be processed

optional arguments:
  -h, --help            show this help message and exit
  -s STARTSTR, --start STARTSTR
                        The initial macro values will be those in effect when
                        the first line commencing with STARTSTR is read
  -e ENDSTR, --end ENDSTR
                        The final macro values will be those in effect when
                        the first line commencing with ENDSTR is read, or if
                        --end is not given then those in effect at end-of-file
  --pp PP               PP is the preprocessor command to invoke. Default 'cpp
                        -dD'
  --ppflags PPFLAGS     PPFLAGS are additional options to be passed to PP

:

$ ./macrodiff.py -s='#pragma message Begin' -e='#pragma message End' foo.c

:

BEFORE[define C 2] AFTER[undef C]
BEFORE[define B 1] AFTER[undef B]

$ ./macrodiff.py -s='#pragma message Begin' -e='#pragma message End' --ppflags='-DA' foo.c

:

BEFORE[define C 2] AFTER[define C 3]
BEFORE[define B 1] AFTER[define B 2]

$ ./macrodiff.py -s='#pragma message Begin' --ppflags='-DA' foo.c

#pragma message Begin . :

BEFORE[define C 2] AFTER[define C 5]
BEFORE[define B 1] AFTER[define B 4]

, , , -C PPFLAGS. , .

.

+3

, - , Boost Wave.

, , libclang, .

, -, Boost Wave.

0

Source: https://habr.com/ru/post/1537653/


All Articles