285 lines
9.9 KiB
Plaintext
285 lines
9.9 KiB
Plaintext
/******************************************************************************
|
|
*
|
|
*
|
|
*
|
|
* Copyright (C) 1997-2015 by Dimitri van Heesch.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation under the terms of the GNU General Public License is hereby
|
|
* granted. No representations are made about the suitability of this software
|
|
* for any purpose. It is provided "as is" without express or implied warranty.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* Documents produced by analyze are derivative works derived from the
|
|
* input used in their production; they are not affected by this license.
|
|
*
|
|
*/
|
|
/*! \page preprocessing Preprocessing
|
|
|
|
Source files that are used as input to analyze can be parsed by analyze's
|
|
built-in C-preprocessor.
|
|
|
|
By default analyze does only partial preprocessing. That is, it
|
|
evaluates conditional compilation statements (like \c \#if) and
|
|
evaluates macro definitions, but it does not perform macro expansion.
|
|
|
|
So if you have the following code fragment
|
|
\verbatim
|
|
#define VERSION 200
|
|
#define CONST_STRING const char *
|
|
|
|
#if VERSION >= 200
|
|
static CONST_STRING version = "2.xx";
|
|
#else
|
|
static CONST_STRING version = "1.xx";
|
|
#endif
|
|
\endverbatim
|
|
|
|
Then by default analyze will feed the following to its parser:
|
|
|
|
\verbatim
|
|
#define VERSION
|
|
#define CONST_STRING
|
|
|
|
static CONST_STRING version = "2.xx";
|
|
\endverbatim
|
|
|
|
You can disable all preprocessing by setting
|
|
\ref cfg_enable_preprocessing "ENABLE_PREPROCESSING" to \c
|
|
NO in the configuration file. In the case above analyze will then read
|
|
both statements, i.e.:
|
|
|
|
\verbatim
|
|
static CONST_STRING version = "2.xx";
|
|
static CONST_STRING version = "1.xx";
|
|
\endverbatim
|
|
|
|
In case you want to expand the \c CONST_STRING macro, you should set the
|
|
\ref cfg_macro_expansion "MACRO_EXPANSION" tag in the configuration file
|
|
to \c YES. Then the result after preprocessing becomes:
|
|
|
|
\verbatim
|
|
#define VERSION
|
|
#define CONST_STRING
|
|
|
|
static const char * version = "2.xx";
|
|
\endverbatim
|
|
|
|
Note that analyze will now expand \e all macro definitions
|
|
(recursively if needed). This is often too much. Therefore, analyze also
|
|
allows you to expand only those defines that you explicitly
|
|
specify. For this you have to set the
|
|
\ref cfg_expand_only_predef "EXPAND_ONLY_PREDEF" tag to \c YES
|
|
and specify the macro definitions after
|
|
the \ref cfg_predefined "PREDEFINED" or
|
|
\ref cfg_expand_as_defined "EXPAND_AS_DEFINED" tag.
|
|
|
|
A typically example where some help from the preprocessor is needed is
|
|
when dealing with the language extension from Microsoft: \c __declspec. The same goes
|
|
for GNU's \c __attribute__ extension. Here is an example function.
|
|
|
|
\verbatim
|
|
extern "C" void __declspec(dllexport) ErrorMsg( String aMessage,...);
|
|
\endverbatim
|
|
|
|
When nothing is done, analyze will be confused and see \c __declspec as
|
|
some sort of function. To help analyze one typically uses the following
|
|
preprocessor settings:
|
|
|
|
\verbatim
|
|
ENABLE_PREPROCESSING = YES
|
|
MACRO_EXPANSION = YES
|
|
EXPAND_ONLY_PREDEF = YES
|
|
PREDEFINED = __declspec(x)=
|
|
\endverbatim
|
|
|
|
This will make sure the \c __declspec(dllexport) is removed before analyze
|
|
parses the source code.
|
|
|
|
Similar settings can be used for removing \c __attribute__ expressions from the input:
|
|
|
|
\verbatim
|
|
ENABLE_PREPROCESSING = YES
|
|
MACRO_EXPANSION = YES
|
|
EXPAND_ONLY_PREDEF = YES
|
|
PREDEFINED = __attribute__(x)=
|
|
\endverbatim
|
|
|
|
For a more complex example, suppose you have the following obfuscated
|
|
code fragment of an abstract base class called \c IUnknown:
|
|
|
|
\verbatim
|
|
/*! A reference to an IID */
|
|
#ifdef __cplusplus
|
|
#define REFIID const IID &
|
|
#else
|
|
#define REFIID const IID *
|
|
#endif
|
|
|
|
|
|
/*! The IUnknown interface */
|
|
DECLARE_INTERFACE(IUnknown)
|
|
{
|
|
STDMETHOD(HRESULT,QueryInterface) (THIS_ REFIID iid, void **ppv) PURE;
|
|
STDMETHOD(ULONG,AddRef) (THIS) PURE;
|
|
STDMETHOD(ULONG,Release) (THIS) PURE;
|
|
};
|
|
\endverbatim
|
|
|
|
without macro expansion analyze will get confused, but we may not want to
|
|
expand the \c REFIID macro, because it is documented and the user that reads
|
|
the documentation should use it when implementing the interface.
|
|
|
|
By setting the following in the configuration file:
|
|
|
|
\verbatim
|
|
ENABLE_PREPROCESSING = YES
|
|
MACRO_EXPANSION = YES
|
|
EXPAND_ONLY_PREDEF = YES
|
|
PREDEFINED = "DECLARE_INTERFACE(name)=class name" \
|
|
"STDMETHOD(result,name)=virtual result name" \
|
|
"PURE= = 0" \
|
|
THIS_= \
|
|
THIS= \
|
|
__cplusplus
|
|
\endverbatim
|
|
|
|
we can make sure that the proper result is fed to analyze's parser:
|
|
\verbatim
|
|
/*! A reference to an IID */
|
|
#define REFIID
|
|
|
|
/*! The IUnknown interface */
|
|
class IUnknown
|
|
{
|
|
virtual HRESULT QueryInterface ( REFIID iid, void **ppv) = 0;
|
|
virtual ULONG AddRef () = 0;
|
|
virtual ULONG Release () = 0;
|
|
};
|
|
\endverbatim
|
|
|
|
Note that the \ref cfg_predefined "PREDEFINED" tag accepts function
|
|
like macro definitions
|
|
(like \c DECLARE_INTERFACE ), normal macro
|
|
substitutions (like \c PURE and \c THIS) and plain
|
|
defines (like \c __cplusplus).
|
|
|
|
Note also that preprocessor definitions that are normally defined
|
|
automatically by the preprocessor (like \c __cplusplus), have to be defined
|
|
by hand with analyze's parser (this is done because these defines
|
|
are often platform/compiler specific).
|
|
|
|
In some cases you may want to substitute a macro name or function by
|
|
something else without exposing the result to further macro substitution.
|
|
You can do this but using the <code>:=</code> operator instead of
|
|
<code>=</code>
|
|
|
|
As an example suppose we have the following piece of code:
|
|
\verbatim
|
|
#define QList QListT
|
|
class QListT
|
|
{
|
|
};
|
|
\endverbatim
|
|
|
|
Then the only way to get analyze interpret this as a class definition
|
|
for class \c QList is to define:
|
|
\verbatim
|
|
PREDEFINED = QListT:=QList
|
|
\endverbatim
|
|
|
|
Here is an example provided by Valter Minute and Reyes Ponce that helps
|
|
analyze to wade through the boilerplate code in Microsoft's ATL \& MFC
|
|
libraries:
|
|
|
|
\verbatim
|
|
PREDEFINED = "DECLARE_INTERFACE(name)=class name" \
|
|
"STDMETHOD(result,name)=virtual result name" \
|
|
"PURE= = 0" \
|
|
THIS_= \
|
|
THIS= \
|
|
DECLARE_REGISTRY_RESOURCEID=// \
|
|
DECLARE_PROTECT_FINAL_CONSTRUCT=// \
|
|
"DECLARE_AGGREGATABLE(Class)= " \
|
|
"DECLARE_REGISTRY_RESOURCEID(Id)= " \
|
|
DECLARE_MESSAGE_MAP= \
|
|
BEGIN_MESSAGE_MAP=/* \
|
|
END_MESSAGE_MAP=*/// \
|
|
BEGIN_COM_MAP=/* \
|
|
END_COM_MAP=*/// \
|
|
BEGIN_PROP_MAP=/* \
|
|
END_PROP_MAP=*/// \
|
|
BEGIN_MSG_MAP=/* \
|
|
END_MSG_MAP=*/// \
|
|
BEGIN_PROPERTY_MAP=/* \
|
|
END_PROPERTY_MAP=*/// \
|
|
BEGIN_OBJECT_MAP=/* \
|
|
END_OBJECT_MAP()=*/// \
|
|
DECLARE_VIEW_STATUS=// \
|
|
"STDMETHOD(a)=HRESULT a" \
|
|
"ATL_NO_VTABLE= " \
|
|
"__declspec(a)= " \
|
|
BEGIN_CONNECTION_POINT_MAP=/* \
|
|
END_CONNECTION_POINT_MAP=*/// \
|
|
"DECLARE_DYNAMIC(class)= " \
|
|
"IMPLEMENT_DYNAMIC(class1, class2)= " \
|
|
"DECLARE_DYNCREATE(class)= " \
|
|
"IMPLEMENT_DYNCREATE(class1, class2)= " \
|
|
"IMPLEMENT_SERIAL(class1, class2, class3)= " \
|
|
"DECLARE_MESSAGE_MAP()= " \
|
|
TRY=try \
|
|
"CATCH_ALL(e)= catch(...)" \
|
|
END_CATCH_ALL= \
|
|
"THROW_LAST()= throw"\
|
|
"RUNTIME_CLASS(class)=class" \
|
|
"MAKEINTRESOURCE(nId)=nId" \
|
|
"IMPLEMENT_REGISTER(v, w, x, y, z)= " \
|
|
"ASSERT(x)=assert(x)" \
|
|
"ASSERT_VALID(x)=assert(x)" \
|
|
"TRACE0(x)=printf(x)" \
|
|
"OS_ERR(A,B)={ #A, B }" \
|
|
__cplusplus \
|
|
"DECLARE_OLECREATE(class)= " \
|
|
"BEGIN_DISPATCH_MAP(class1, class2)= " \
|
|
"BEGIN_INTERFACE_MAP(class1, class2)= " \
|
|
"INTERFACE_PART(class, id, name)= " \
|
|
"END_INTERFACE_MAP()=" \
|
|
"DISP_FUNCTION(class, name, function, result, id)=" \
|
|
"END_DISPATCH_MAP()=" \
|
|
"IMPLEMENT_OLECREATE2(class, name, id1, id2, id3, id4,\
|
|
id5, id6, id7, id8, id9, id10, id11)="
|
|
\endverbatim
|
|
|
|
As you can see analyze's preprocessor is quite powerful, but if you want
|
|
even more flexibility you can always write an input filter and specify it
|
|
after the \ref cfg_input_filter "INPUT_FILTER" tag or
|
|
the \ref cfg_filter_patterns "FILTER_PATTERNS" tag
|
|
(or the \ref cfg_filter_source_patterns "FILTER_SOURCE_PATTERNS" tag).<br>
|
|
If you are unsure what the effect of the filter will be
|
|
you can run analyze as follows: `analyze -d filteroutput`.
|
|
|
|
If you are unsure what the effect of analyze's preprocessing will be
|
|
you can run analyze as follows:
|
|
\verbatim
|
|
analyze -d Preprocessor
|
|
\endverbatim
|
|
or when the line numbers are not wanted:
|
|
\verbatim
|
|
analyze -d Preprocessor -d NoLineno
|
|
\endverbatim
|
|
This will instruct analyze to dump the input sources to standard output after
|
|
preprocessing has been done (Hint: set <code>QUIET = YES</code> and
|
|
<code>WARNINGS = NO</code> in the configuration file to disable any other
|
|
output).
|
|
|
|
Note preprocessing is not done for all languages. Preprocessing is enabled for files
|
|
that use the "C" scanner (with the exception of 'java', 'd' and 'php'), Fortran files
|
|
(only in case the extension contains at least one upper case character) and vhdl files.
|
|
|
|
\htmlonly
|
|
Go to the <a href="autolink.html">next</a> section or return to the
|
|
<a href="index.html">index</a>.
|
|
\endhtmlonly
|
|
|
|
*/
|