Doxygen
Loading...
Searching...
No Matches
pre.l File Reference
#include <stdint.h>
#include "doxygen.h"
#include <stack>
#include <deque>
#include <algorithm>
#include <utility>
#include <mutex>
#include <thread>
#include <cstdio>
#include <cassert>
#include <cctype>
#include <cerrno>
#include "qcstring.h"
#include "containers.h"
#include "pre.h"
#include "constexp.h"
#include "define.h"
#include "message.h"
#include "util.h"
#include "defargs.h"
#include "debug.h"
#include "portable.h"
#include "arguments.h"
#include "entry.h"
#include "condparser.h"
#include "config.h"
#include "filedef.h"
#include "regex.h"
#include "fileinfo.h"
#include "trace.h"
#include "stringutil.h"
#include "doxygen_lex.h"
#include "pre.l.h"
Include dependency graph for pre.l:

Go to the source code of this file.

Classes

struct  preYY_CondCtx
struct  FileState
struct  PreIncludeInfo
class  DefineManager
 Class that manages the defines available while preprocessing files. More...
class  DefineManager::DefinesPerFile
 Local class used to hold the defines for a single file. More...
struct  preYY_state
struct  Preprocessor::Private

Macros

#define YY_TYPEDEF_YY_SCANNER_T
#define YY_NO_UNISTD_H   1
#define YY_INPUT(buf, result, max_size)
#define MAX_EXPANSION_DEPTH   50

Typedefs

typedef yyguts_t * yyscan_t
typedef std::map< std::string, DefineDefineMap
 A dictionary of managed Define objects.

Functions

static const char * stateToString (int state)
static QCString escapeAt (const QCString &text)
static QCString extractTrailingComment (const QCString &s)
static char resolveTrigraph (char c)
static void outputArray (yyscan_t yyscanner, const char *a, yy_size_t len)
static void outputString (yyscan_t yyscanner, const QCString &s)
static void outputChar (yyscan_t yyscanner, char c)
static void outputSpaces (yyscan_t yyscanner, char *s)
static void outputSpace (yyscan_t yyscanner, char c)
static void extraSpacing (yyscan_t yyscanner)
static QCString expandMacro (yyscan_t yyscanner, const QCString &name)
static QCString expandStandardMacro (yyscan_t yyscanner, const QCString &name)
static void readIncludeFile (yyscan_t yyscanner, const QCString &inc)
static void incrLevel (yyscan_t yyscanner)
static void decrLevel (yyscan_t yyscanner)
static void setCaseDone (yyscan_t yyscanner, bool value)
static bool otherCaseDone (yyscan_t yyscanner)
static bool computeExpression (yyscan_t yyscanner, const QCString &expr)
static void startCondSection (yyscan_t yyscanner, const QCString &sectId)
static void endCondSection (yyscan_t yyscanner)
static void addMacroDefinition (yyscan_t yyscanner)
static void addDefine (yyscan_t yyscanner)
static void setFileName (yyscan_t yyscanner, const QCString &name)
static int yyread (yyscan_t yyscanner, char *buf, int max_size)
static DefineisDefined (yyscan_t yyscanner, const QCString &name)
 Returns a reference to a Define object given its name or 0 if the Define does not exist.
static void determineBlockName (yyscan_t yyscanner)
static yy_size_t getFenceSize (char *txt, yy_size_t leng)
static const char * getLexerFILE ()
int yylex (yyscan_t yyscanner)
static std::unique_ptr< FileStatecheckAndOpenFile (yyscan_t yyscanner, const QCString &fileName, bool &alreadyProcessed)
static std::unique_ptr< FileStatefindFile (yyscan_t yyscanner, const QCString &fileName, bool localInclude, bool &alreadyProcessed)
static int getNextChar (yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos)
static int getCurrentChar (yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t pos)
static void unputChar (yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char c)
static bool expandExpression (yyscan_t yyscanner, QCString &expr, QCString *rest, int pos, int level)
static QCString stringize (const QCString &s)
static void processConcatOperators (QCString &expr)
static void returnCharToStream (yyscan_t yyscanner, char c)
static void addTillEndOfString (yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
static void addTillEndOfComment (yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
static void skipCommentMacroName (yyscan_t yyscanner, const QCString &expr, QCString *rest, int &cc, uint32_t &j, int &len)
static QCString expandVAOpt (const QCString &vaStr, bool hasOptionalArgs)
static bool replaceFunctionMacro (yyscan_t yyscanner, const QCString &expr, QCString *rest, int pos, int &len, const Define *def, QCString &result, int level)
static int getNextId (const QCString &expr, int p, int *l)
static void addSeparatorsIfNeeded (yyscan_t yyscanner, const QCString &expr, QCString &resultExpr, QCString &restExpr, int pos)
static const char * processUntilMatchingTerminator (const char *inputStr, QCString &result)
 Process string or character literal.
static QCString removeIdsAndMarkers (const QCString &s)
static QCString removeMarkers (const QCString &s)
static void forceEndCondSection (yyscan_t yyscanner)
static void initPredefined (yyscan_t yyscanner, const QCString &fileName)

Variables

static std::mutex g_debugMutex
static std::mutex g_globalDefineMutex
static std::mutex g_updateGlobals
static DefineManager g_defineManager

Macro Definition Documentation

◆ MAX_EXPANSION_DEPTH

#define MAX_EXPANSION_DEPTH   50

Definition at line 3083 of file pre.l.

Referenced by expandExpression().

◆ YY_INPUT

#define YY_INPUT ( buf,
result,
max_size )
Value:
result=yyread(yyscanner,buf,max_size);
static int yyread(yyscan_t yyscanner, char *buf, int max_size)

Definition at line 353 of file pre.l.

◆ YY_NO_UNISTD_H

#define YY_NO_UNISTD_H   1

Definition at line 66 of file pre.l.

◆ YY_TYPEDEF_YY_SCANNER_T

#define YY_TYPEDEF_YY_SCANNER_T

Definition at line 22 of file pre.l.

Typedef Documentation

◆ DefineMap

typedef std::map< std::string, Define > DefineMap

A dictionary of managed Define objects.

Definition at line 108 of file pre.l.

◆ yyscan_t

typedef yyguts_t* yyscan_t

Definition at line 24 of file pre.l.

Function Documentation

◆ addDefine()

void addDefine ( yyscan_t yyscanner)
static

Definition at line 3631 of file pre.l.

3632{
3633 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3634 Define def;
3635 def.name = state->defName;
3636 def.definition = state->defText.stripWhiteSpace();
3637 def.nargs = state->defArgs;
3638 def.fileName = state->fileName;
3639 def.fileDef = state->yyFileDef;
3640 def.lineNr = state->yyLineNr-state->yyMLines;
3641 def.columnNr = state->yyColNr;
3642 def.varArgs = state->defVarArgs;
3643 //printf("newDefine: %s %s file: %s\n",qPrint(def.name),qPrint(def.definition),
3644 // def.fileDef ? qPrint(def.fileDef->name()) : qPrint(def.fileName));
3645 //printf("newDefine: '%s'->'%s'\n",qPrint(def.name),qPrint(def.definition));
3646 if (!def.name.isEmpty() &&
3648 {
3649 def.isPredefined=true;
3650 def.expandAsDefined=true;
3651 }
3652 auto it = state->localDefines.find(def.name.str());
3653 if (it!=state->localDefines.end()) // redefine
3654 {
3655 state->localDefines.erase(it);
3656 }
3657 state->localDefines.emplace(def.name.str(),def);
A class representing a macro definition.
Definition define.h:31
int lineNr
Definition define.h:38
bool varArgs
Definition define.h:42
QCString fileName
Definition define.h:35
QCString name
Definition define.h:33
FileDef * fileDef
Definition define.h:37
bool isPredefined
Definition define.h:43
int columnNr
Definition define.h:39
QCString definition
Definition define.h:34
int nargs
Definition define.h:40
bool expandAsDefined
Definition define.h:45
static StringUnorderedSet expandAsDefinedSet
Definition doxygen.h:119
bool isEmpty() const
Returns true iff the string is empty.
Definition qcstring.h:161
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:258
const std::string & str() const
Definition qcstring.h:550
3658}

References Define::columnNr, Define::definition, Define::expandAsDefined, Doxygen::expandAsDefinedSet, Define::fileDef, Define::fileName, QCString::isEmpty(), Define::isPredefined, Define::lineNr, Define::name, Define::nargs, QCString::str(), QCString::stripWhiteSpace(), and Define::varArgs.

◆ addMacroDefinition()

void addMacroDefinition ( yyscan_t yyscanner)
static

Definition at line 3660 of file pre.l.

3661{
3662 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3663 if (state->skip) return; // do not add this define as it is inside a
3664 // conditional section (cond command) that is disabled.
3665
3666 Define define;
3667 define.fileName = state->fileName;
3668 define.lineNr = state->yyLineNr - state->yyMLines;
3669 define.columnNr = state->yyColNr;
3670 define.name = state->defName;
3671 define.args = state->defArgsStr;
3672 define.fileDef = state->inputFileDef;
QCString args
Definition define.h:36
3673
3674 QCString litText = state->defLitText;
3675 int l=litText.find('\n');
3676 if (l>0 && litText.left(l).stripWhiteSpace()=="\\")
3677 {
3678 // strip first line if it only contains a slash
3679 litText = litText.right(litText.length()-l-1);
3680 }
3681 else if (l>0)
3682 {
3683 // align the items on the first line with the items on the second line
3684 int k=l+1;
3685 const char *p=litText.data()+k;
3686 char c = 0;
3687 while ((c=*p++) && (c==' ' || c=='\t')) k++;
3688 litText=litText.mid(l+1,k-l-1)+litText.stripWhiteSpace();
3689 }
3690 QCString litTextStripped = state->defLitText.stripWhiteSpace();
3691 if (litTextStripped.contains('\n')>=1)
3692 {
3693 define.definition = litText;
3694 }
3695 else
3696 {
3697 define.definition = litTextStripped;
3698 }
3699 {
3700 state->macroDefinitions.push_back(define);
3701 }
This is an alternative implementation of QCString.
Definition qcstring.h:97
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:164
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:239
int find(char c, int index=0, bool cs=true) const
Definition qcstring.cpp:43
QCString right(size_t len) const
Definition qcstring.h:232
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:170
int contains(char c, bool cs=true) const
Definition qcstring.cpp:148
QCString left(size_t len) const
Definition qcstring.h:227
3702}

References Define::args, Define::columnNr, QCString::contains(), QCString::data(), Define::definition, Define::fileDef, Define::fileName, QCString::find(), QCString::left(), QCString::length(), Define::lineNr, QCString::mid(), Define::name, QCString::right(), and QCString::stripWhiteSpace().

◆ addSeparatorsIfNeeded()

void addSeparatorsIfNeeded ( yyscan_t yyscanner,
const QCString & expr,
QCString & resultExpr,
QCString & restExpr,
int pos )
static

Definition at line 3085 of file pre.l.

3086{
3087 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3088 if (!state->nospaces)
3089 {
3090 // peek back in the stream, for a colon character
3091 char ccPrev = pos==0 || (int)expr.length()<pos ? state->prevChar : expr.at(pos-1);
3092 QCString leftSpace = ccPrev!=':' && ccPrev!=' ' ? " " : "";
3093 int ccNext = 0;
3094 restExpr=restExpr.stripWhiteSpace();
3095 if (restExpr.isEmpty()) // peek ahead in the stream for non-whitespace
3096 {
3097 uint32_t j=(uint32_t)resultExpr.length();
3098 while ((ccNext=getNextChar(yyscanner,resultExpr,nullptr,j))!=EOF && ccNext==' ') { }
3099 if (ccNext != EOF) unputChar(yyscanner,resultExpr,nullptr,j,(char)ccNext);
3100 }
3101 else // take first char from remainder
3102 {
3103 ccNext=restExpr.at(0);
3104 }
3105 // don't add whitespace before a colon
3106 QCString rightSpace = ccNext!=':' && ccNext!=' ' ? " " : "";
3107 //printf("ccPrev='%c' ccNext='%c' p=%d expr=%zu restExpr='%s' left='%s' right='%s'\n",
3108 // ccPrev,ccNext,pos,expr.length(),qPrint(restExpr),qPrint(leftSpace),qPrint(rightSpace));
3109 resultExpr=leftSpace+resultExpr+rightSpace;
3110 }
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:591
static int getNextChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos)
Definition pre.l:4032
static void unputChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char c)
Definition pre.l:4078
3111}

References QCString::at(), getNextChar(), QCString::isEmpty(), QCString::length(), QCString::stripWhiteSpace(), and unputChar().

Referenced by expandExpression().

◆ addTillEndOfComment()

void addTillEndOfComment ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
uint32_t & pos,
char term,
QCString & arg )
inlinestatic

Definition at line 2660 of file pre.l.

2662{
2663 int cc;
2664 while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2665 {
2666 if (cc=='*' && getCurrentChar(yyscanner,expr,rest,pos)=='/')
2667 {
2668 arg+=(char)cc;
2669 cc = getNextChar(yyscanner,expr,rest,pos);
2670 return;
2671 }
2672 arg+=(char)cc;
2673 }
static int getCurrentChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t pos)
Definition pre.l:4055
2674}

References getCurrentChar(), getNextChar(), and term.

Referenced by replaceFunctionMacro().

◆ addTillEndOfString()

void addTillEndOfString ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
uint32_t & pos,
char term,
QCString & arg )
inlinestatic

Definition at line 2641 of file pre.l.

2643{
2644 int cc;
2645 while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2646 {
2647 if (cc=='\\')
2648 {
2649 arg+=(char)cc;
2650 cc=getNextChar(yyscanner,expr,rest,pos);
2651 }
2652 else if (cc==term)
2653 {
2654 return;
2655 }
2656 arg+=(char)cc;
2657 }
#define term(fmt,...)
Definition message.h:137
2658}

References getNextChar(), and term.

Referenced by replaceFunctionMacro().

◆ checkAndOpenFile()

std::unique_ptr< FileState > checkAndOpenFile ( yyscan_t yyscanner,
const QCString & fileName,
bool & alreadyProcessed )
static

Definition at line 2329 of file pre.l.

2330{
2331 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2332 alreadyProcessed = false;
2333 std::unique_ptr<FileState> fs;
2334 //printf("checkAndOpenFile(%s)\n",qPrint(fileName));
2335 FileInfo fi(fileName.str());
2336 if (fi.exists() && fi.isFile())
2337 {
2338 const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
2339 if (patternMatch(fi,exclPatterns)) return nullptr;
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
#define Config_getList(name)
Definition config.h:38
std::vector< std::string > StringVector
Definition containers.h:33
bool patternMatch(const FileInfo &fi, const StringVector &patList)
Definition util.cpp:5746
2340
2341 QCString absName = fi.absFilePath();
2342
2343 // global guard
2344 if (state->curlyCount==0) // not #include inside { ... }
2345 {
2346 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
2347 if (g_defineManager.alreadyProcessed(absName.str()))
2348 {
2349 alreadyProcessed = true;
2350 //printf(" already included 1\n");
2351 return 0; // already done
2352 }
2353 }
2354 // check include stack for absName
bool alreadyProcessed(const std::string &fileName) const
Definition pre.l:206
static std::mutex g_globalDefineMutex
Definition pre.l:233
static DefineManager g_defineManager
Definition pre.l:235
2355
2356 alreadyProcessed = std::any_of(
2357 state->includeStack.begin(),
2358 state->includeStack.end(),
2359 [absName](const std::unique_ptr<FileState> &lfs)
2360 { return lfs->fileName==absName; }
2361 );
2362
2363 if (alreadyProcessed)
2364 {
2365 //printf(" already included 2\n");
2366 return nullptr;
2367 }
2368 //printf("#include %s\n",qPrint(absName));
2369
2370 fs = std::make_unique<FileState>();
2371 if (!readInputFile(absName,fs->fileBuf))
2372 { // error
2373 //printf(" error reading\n");
2374 fs.reset();
2375 }
2376 else
2377 {
2378 addTerminalCharIfMissing(fs->fileBuf,'\n');
2379 fs->oldFileBuf = state->inputBuf;
2380 fs->oldFileBufPos = state->inputBufPos;
2381 }
2382 }
2383 return fs;
void addTerminalCharIfMissing(std::string &s, char c)
Definition stringutil.h:84
bool readInputFile(const QCString &fileName, std::string &contents, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition util.cpp:5592
2384}

References FileInfo::absFilePath(), addTerminalCharIfMissing(), DefineManager::alreadyProcessed(), Config_getList, FileInfo::exists(), g_defineManager, g_globalDefineMutex, FileInfo::isFile(), patternMatch(), readInputFile(), and QCString::str().

Referenced by findFile().

◆ computeExpression()

bool computeExpression ( yyscan_t yyscanner,
const QCString & expr )
static

compute the value of the expression in string expr. If needed the function may read additional characters from the input.

Definition at line 3569 of file pre.l.

3570{
3571 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3572 QCString e=expr;
3573 QCString ee=expr;
3574 ee = removeMarkers(ee);
3575 state->expanded.clear();
3576 expandExpression(yyscanner,e,nullptr,0,0);
3577 //printf("after expansion '%s'\n",qPrint(e));
3578 e = removeIdsAndMarkers(e);
3579 if (e.isEmpty()) return false;
3580 //printf("parsing '%s'\n",qPrint(e));
3581 return state->constExpParser.parse(state->fileName.data(),state->yyLineNr,e.str(),ee.str());
static bool expandExpression(yyscan_t yyscanner, QCString &expr, QCString *rest, int pos, int level)
Definition pre.l:3117
static QCString removeIdsAndMarkers(const QCString &s)
Definition pre.l:3303
static QCString removeMarkers(const QCString &s)
Definition pre.l:3498
3582}

References expandExpression(), QCString::isEmpty(), removeIdsAndMarkers(), removeMarkers(), and QCString::str().

◆ decrLevel()

void decrLevel ( yyscan_t yyscanner)
static

Definition at line 2287 of file pre.l.

2288{
2289 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2290 //printf("%s line %d: decrLevel %zu\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
2291 if (!state->levelGuard.empty())
2292 {
2293 state->levelGuard.pop();
2294 }
2295 else
2296 {
2297 if (state->condGuardErrorLine!=0)
2298 {
2299 warn(state->condGuardErrorFileName,state->condGuardErrorLine,"{}",state->condGuardErrorMessage);
2300 }
2301 else
2302 {
2303 warn(state->fileName,state->yyLineNr,"More #endif's than #if's found.");
2304 }
2305 }
#define warn(file, line, fmt,...)
Definition message.h:97
2306}

References warn.

◆ determineBlockName()

void determineBlockName ( yyscan_t yyscanner)
static

Definition at line 3752 of file pre.l.

3753{
3754 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3755 yyextra->fenceSize=0;
3756 char c=0;
3757 if (yytext[1]=='f' && ((c=yytext[2])=='[' || c=='{' || c=='(' || c=='$'))
3758 {
3759 switch (c)
3760 {
3761 case '[': yyextra->blockName="]"; break;
3762 case '{': yyextra->blockName="}"; break;
3763 case '(': yyextra->blockName=")"; break;
3764 case '$': yyextra->blockName="$"; break;
3765 default: break;
3766 }
3767 yyextra->blockName=yyextra->blockName.stripWhiteSpace();
3768 }
3769 else
3770 {
3771 QCString bn=QCString(&yytext[1]).stripWhiteSpace();
3772 if (bn=="startuml")
3773 {
3774 yyextra->blockName="uml";
3775 }
3776 else
3777 {
3778 int i = bn.find('{'); // for \code{.c}
3779 if (i!=-1) bn=bn.left(i).stripWhiteSpace();
3780 yyextra->blockName=bn;
3781 }
3782 }
3783}

References QCString::find(), QCString::left(), and QCString::stripWhiteSpace().

◆ endCondSection()

void endCondSection ( yyscan_t yyscanner)
static

Definition at line 3954 of file pre.l.

3955{
3956 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3957 if (state->condGuardCount>0 && state->condGuardErrorLine==0)
3958 {
3959 state->condGuardErrorLine = state->yyLineNr;
3960 state->condGuardErrorFileName = state->fileName;
3961 state->condGuardErrorMessage = "more #if's than #endif's in \\cond..\\endcond section";
3962 }
3963 else if (state->condGuardCount<0 && state->condGuardErrorLine==0)
3964 {
3965 state->condGuardErrorLine = state->yyLineNr;
3966 state->condGuardErrorFileName = state->fileName;
3967 state->condGuardErrorMessage = "more #endif's than #if's in \\cond..\\endcond section";
3968 }
3969 else // balanced again -> no error
3970 {
3971 state->condGuardErrorLine = 0;
3972 }
3973 if (state->condStack.empty())
3974 {
3975 warn(state->fileName,state->yyLineNr,"the \\endcond does not have a corresponding \\cond in this file");
3976 state->skip=false;
3977 }
3978 else
3979 {
3980 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3981 state->skip=ctx->skip;
3982 state->condStack.pop();
3983 }
3984 //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count());
3985}

References warn.

◆ escapeAt()

QCString escapeAt ( const QCString & text)
static

Definition at line 3997 of file pre.l.

3998{
3999 QCString result;
4000 if (!text.isEmpty())
4001 {
4002 char c = 0;
4003 const char *p=text.data();
4004 while ((c=*p++))
4005 {
4006 if (c=='@') result+="@@"; else result+=c;
4007 }
4008 }
4009 return result;
4010}

References QCString::data(), and QCString::isEmpty().

◆ expandExpression()

bool expandExpression ( yyscan_t yyscanner,
QCString & expr,
QCString * rest,
int pos,
int level )
static

performs recursive macro expansion on the string expr starting at position pos. May read additional characters from the input while re-scanning!

Definition at line 3117 of file pre.l.

3118{
3119 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3120 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3121 //printf(">expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos, level);
3122 if (expr.isEmpty())
3123 {
3124 //printf("<expandExpression: empty\n");
3125 return true;
3126 }
3127 if (state->expanded.find(expr.str())!=state->expanded.end() &&
3128 level>MAX_EXPANSION_DEPTH) // check for too deep recursive expansions
3129 {
3130 //printf("<expandExpression: already expanded expr='%s'\n",qPrint(expr));
3131 return false;
3132 }
3133 else
3134 {
3135 state->expanded.insert(expr.str());
3136 }
3137 QCString macroName;
3138 QCString expMacro;
3139 bool definedTest=false;
3140 int i=pos, l=0, p=0, len=0;
3141 int startPos = pos;
3142 int samePosCount=0;
3143 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
3144 {
3145 bool replaced=false;
3146 QCString resultExpr;
3147 macroName=expr.mid(p,l);
3148 //printf(" p=%d macroName=%s\n",p,qPrint(macroName));
3149 if (!(resultExpr = expandStandardMacro(yyscanner,macroName)).isEmpty())
3150 {
3151 QCString restExpr=expr.right(expr.length()-8-p);
3152 expr=expr.left(p)+resultExpr+restExpr;
3153 }
3154 else if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
3155 {
3156 if (state->expandedDict.find(macroName.str())==state->expandedDict.end()) // expand macro
3157 {
3158 bool expanded=false;
3159 Define *def=isDefined(yyscanner,macroName);
3160 // In case EXPAND_ONLY_PREDEF is enabled prevent expansion unless the macro was explicitly
3161 // predefined
3162 if (yyextra->expandOnlyPredef && def && !def->isPredefined) def=nullptr;
3163 if (macroName=="defined")
3164 {
3165 //printf("found defined inside macro definition '%s'\n",qPrint(expr.right(expr.length()-p)));
3166 definedTest=true;
3167 }
3168 else if (definedTest) // macro name was found after defined
3169 {
3170 if (def) expMacro = " 1 "; else expMacro = " 0 ";
3171 replaced=true;
3172 len=l;
3173 definedTest=false;
3174 }
3175 else if (def && def->nargs==-1) // simple macro
3176 {
3177 // substitute the definition of the macro
3178 expMacro=def->definition.stripWhiteSpace();
3179 //expMacro=def->definition.stripWhiteSpace();
3180 replaced=true;
3181 len=l;
3182 //printf("simple macro expansion='%s'->'%s'\n",qPrint(macroName),qPrint(expMacro));
3183 }
3184 else if (def && def->nargs>=0) // function macro
3185 {
3186 //printf(" >>>> call replaceFunctionMacro expr='%s'\n",qPrint(expr));
3187 replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro,level);
3188 //printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
3189 len+=l;
3190 }
#define MAX_EXPANSION_DEPTH
Definition pre.l:3083
static Define * isDefined(yyscan_t yyscanner, const QCString &name)
Returns a reference to a Define object given its name or 0 if the Define does not exist.
Definition pre.l:4102
static int getNextId(const QCString &expr, int p, int *l)
Definition pre.l:3029
static QCString expandStandardMacro(yyscan_t yyscanner, const QCString &name)
Definition pre.l:3602
static bool replaceFunctionMacro(yyscan_t yyscanner, const QCString &expr, QCString *rest, int pos, int &len, const Define *def, QCString &result, int level)
Definition pre.l:2760
3191
3192 if (replaced) // expand the macro and rescan the expression
3193 {
3194 //printf(" replacing '%s'->'%s'\n",qPrint(expr.mid(p,len)),qPrint(expMacro));
3195 resultExpr=expMacro;
3196 QCString restExpr=expr.right(expr.length()-len-p);
3197 addSeparatorsIfNeeded(yyscanner,expr,resultExpr,restExpr,p);
3198 processConcatOperators(resultExpr);
3199 //printf(" macroName=%s restExpr='%s' def->nonRecursive=%d\n",qPrint(macroName),qPrint(restExpr),def ? def->nonRecursive : false);
3200 if (def && !def->nonRecursive)
3201 {
3202 state->expandedDict.emplace(toStdString(macroName),def);
3203 expanded = expandExpression(yyscanner,resultExpr,&restExpr,0,level+1);
3204 state->expandedDict.erase(toStdString(macroName));
3205 }
3206 else if (def && def->nonRecursive)
3207 {
3208 expanded = true;
3209 }
3210 if (expanded)
3211 {
3212 //printf("expanded '%s' + '%s' + '%s'\n",qPrint(expr.left(p)),qPrint(resultExpr),qPrint(restExpr));
3213 expr=expr.left(p)+resultExpr+restExpr;
3214 i=p;
3215 }
3216 else
3217 {
3218 //printf("not expanded '%s' + @- '%s'\n",qPrint(expr.left(p)),qPrint(expr.right(expr.length()-p)));
3219 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3220 i=p+l+2;
3221 }
3222 }
3223 else // move to the next macro name
3224 {
3225 //printf(" moving to the next macro old i=%d new i=%d\n",i,p+l);
3226 i=p+l;
3227 }
3228 }
3229 else // move to the next macro name
3230 {
3231 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3232 //printf("macro already expanded, moving to the next macro expr=%s\n",qPrint(expr));
3233 i=p+l+2;
3234 //i=p+l;
3235 }
3236 // check for too many inplace expansions without making progress
3237 if (i==startPos)
3238 {
3239 samePosCount++;
3240 }
3241 else
3242 {
3243 startPos=i;
3244 samePosCount=0;
3245 }
3246 if (samePosCount>MAX_EXPANSION_DEPTH)
3247 {
3248 break;
3249 }
3250 }
3251 else // no re-scan marker found, skip the macro name
3252 {
3253 //printf("skipping marked macro\n");
3254 i=p+l;
3255 }
3256 }
3257 //printf("<expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos,level);
3258 return true;
bool nonRecursive
Definition define.h:44
static void addSeparatorsIfNeeded(yyscan_t yyscanner, const QCString &expr, QCString &resultExpr, QCString &restExpr, int pos)
Definition pre.l:3085
static void processConcatOperators(QCString &expr)
Definition pre.l:2588
std::string toStdString(const QCString &s)
Definition qcstring.h:700
3259}

References addSeparatorsIfNeeded(), QCString::at(), Define::definition, expandExpression(), expandStandardMacro(), getNextId(), isDefined(), QCString::isEmpty(), Define::isPredefined, QCString::left(), QCString::length(), MAX_EXPANSION_DEPTH, QCString::mid(), Define::nargs, Define::nonRecursive, processConcatOperators(), replaceFunctionMacro(), QCString::right(), QCString::str(), QCString::stripWhiteSpace(), and toStdString().

Referenced by computeExpression(), expandExpression(), expandMacro(), and replaceFunctionMacro().

◆ expandMacro()

QCString expandMacro ( yyscan_t yyscanner,
const QCString & name )
static

expands the macro definition in name If needed the function may read additional characters from the input

Definition at line 3588 of file pre.l.

3589{
3590 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3591 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3592 state->prevChar = yyscanner->yytext_r > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ? *(yyscanner->yytext_r-1) : 0;
3593 QCString n=name;
3594 state->expanded.clear();
3595 expandExpression(yyscanner,n,nullptr,0,0);
3596 n=removeMarkers(n);
3597 state->prevChar=0;
3598 //printf("expandMacro '%s'->'%s'\n",qPrint(name),qPrint(n));
3599 return n;
void clear()
Definition qcstring.h:180
3600}

References QCString::clear(), expandExpression(), and removeMarkers().

◆ expandStandardMacro()

QCString expandStandardMacro ( yyscan_t yyscanner,
const QCString & name )
static

Definition at line 3602 of file pre.l.

3603{
3604 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3605 QCString resultExpr;
3606 if (name == "__LINE__")
3607 {
3608 return QCString().setNum(yyextra->yyLineNr);
3609 }
3610 else if (name == "__FILE__")
3611 {
3612 resultExpr = "\"";
3613 resultExpr += yyextra->fileName;
3614 resultExpr += "\"";
3615 }
3616 else if (name == "__DATE__")
3617 {
3618 resultExpr = "\"";
3619 resultExpr += __DATE__;
3620 resultExpr += "\"";
3621 }
3622 else if (name == "__TIME__")
3623 {
3624 resultExpr = "\"";
3625 resultExpr += __TIME__;
3626 resultExpr += "\"";
3627 }
3628 return resultExpr;
QCString & setNum(short n)
Definition qcstring.h:457
3629}

References QCString::setNum().

Referenced by expandExpression().

◆ expandVAOpt()

QCString expandVAOpt ( const QCString & vaStr,
bool hasOptionalArgs )
static

Definition at line 2708 of file pre.l.

2709{
2710 //printf("expandVAOpt(vaStr=%s,hasOptionalArgs=%d)\n",qPrint(vaStr),hasOptionalArgs);
2711 QCString result;
2712 int vo=0, vp=0;
2713 result.clear();
2714 int vl = static_cast<int>(vaStr.length());
2715 while ((vo = vaStr.find("__VA_OPT__(",vp))!=-1)
2716 {
2717 bool hasHash = vo>0 && vaStr.at(vo-1)=='#';
2718 if (hasHash)
2719 {
2720 result+=vaStr.mid(vp,vo-vp-1); // don't copy #
2721 result+="\"";
2722 }
2723 else
2724 {
2725 result+=vaStr.mid(vp,vo-vp);
2726 }
2727 int ve=vo+11; // skip over '__VA_OPT__(' part
2728 int bc=1;
2729 while (bc>0 && ve<vl)
2730 {
2731 if (vaStr[ve]==')') bc--;
2732 else if (vaStr[ve]=='(') bc++;
2733 ve++;
2734 }
2735 // ve points to end of __VA_OPT__(....)
2736 if (bc==0 && hasOptionalArgs)
2737 {
2738 QCString voStr = vaStr.mid(vo+11,ve-vo-12);
2739 //printf("vo=%d ve=%d voStr=%s\n",vo,ve,qPrint(voStr));
2740 result+=voStr; // take 'x' from __VA_OPT__(x)
2741 }
2742 if (hasHash)
2743 {
2744 result+="\"";
2745 }
2746 vp=ve;
2747 }
2748 result+=vaStr.mid(vp);
2749 //printf("vaStr='%s'\n -> '%s'\n",qPrint(vaStr),qPrint(result));
2750 return result;
2751}

References QCString::at(), QCString::clear(), QCString::find(), QCString::length(), and QCString::mid().

Referenced by replaceFunctionMacro().

◆ extractTrailingComment()

QCString extractTrailingComment ( const QCString & s)
static

Definition at line 2460 of file pre.l.

2461{
2462 if (s.isEmpty()) return "";
2463 int i=(int)s.length()-1;
2464 while (i>=0)
2465 {
2466 char c=s[i];
2467 switch (c)
2468 {
2469 case '/':
2470 {
2471 i--;
2472 if (i>=0 && s[i]=='*') // end of a comment block
2473 {
2474 i--;
2475 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
2476 if (i==0)
2477 {
2478 i++;
2479 }
2480 // only /*!< ... */ or /**< ... */ are treated as a comment for the macro name,
2481 // otherwise the comment is treated as part of the macro definition
2482 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
2483 }
2484 else
2485 {
2486 return "";
2487 }
2488 }
2489 break;
2490 // whitespace or line-continuation
2491 case ' ':
2492 case '\t':
2493 case '\r':
2494 case '\n':
2495 case '\\':
2496 break;
2497 default:
2498 return "";
2499 }
2500 i--;
2501 }
2502 return "";
2503}

References QCString::isEmpty(), and QCString::length().

◆ extraSpacing()

void extraSpacing ( yyscan_t yyscanner)
inlinestatic

Definition at line 3739 of file pre.l.

3740{
3741 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3742 if (!yyextra->defContinue) return;
3743 for (int i=0; i< (int)yyleng; i++)
3744 {
3745 if (yytext[i] == '\t')
3746 yyextra->defExtraSpacing+='\t';
3747 else
3748 yyextra->defExtraSpacing+=' ';
3749 }
3750}

◆ findFile()

std::unique_ptr< FileState > findFile ( yyscan_t yyscanner,
const QCString & fileName,
bool localInclude,
bool & alreadyProcessed )
static

Definition at line 2386 of file pre.l.

2387{
2388 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2389 //printf("** findFile(%s,%d) state->fileName=%s\n",qPrint(fileName),localInclude,qPrint(state->fileName));
2390 if (Portable::isAbsolutePath(fileName))
2391 {
2392 auto fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed);
2393 if (fs)
2394 {
2395 setFileName(yyscanner,fileName);
2396 state->yyLineNr=1;
2397 return fs;
2398 }
2399 else if (alreadyProcessed)
2400 {
2401 return nullptr;
2402 }
2403 }
2404 if (localInclude && !state->fileName.isEmpty())
2405 {
2406 FileInfo fi(state->fileName.str());
2407 if (fi.exists())
2408 {
2409 QCString absName = QCString(fi.dirPath(true))+"/"+fileName;
2410 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2411 if (fs)
2412 {
2413 setFileName(yyscanner,absName);
2414 state->yyLineNr=1;
2415 return fs;
2416 }
2417 else if (alreadyProcessed)
2418 {
2419 return nullptr;
2420 }
2421 }
2422 }
2423 if (state->pathList.empty())
2424 {
2425 return nullptr;
2426 }
2427 for (auto path : state->pathList)
2428 {
2429 QCString absName = path+"/"+fileName;
2430 //printf(" Looking for %s in %s\n",fileName,qPrint(path));
2431 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2432 if (fs)
2433 {
2434 setFileName(yyscanner,absName);
2435 state->yyLineNr=1;
2436 //printf(" -> found it\n");
2437 return fs;
2438 }
2439 else if (alreadyProcessed)
2440 {
2441 return nullptr;
2442 }
2443 }
2444 bool ambig = false;
2446 if (fd && !ambig) // fallback in case the file is uniquely named in the input, use that one
2447 {
2448 auto fs = checkAndOpenFile(yyscanner,fd->absFilePath(),alreadyProcessed);
2449 if (fs)
2450 {
2451 setFileName(yyscanner,fd->absFilePath());
2452 state->yyLineNr=1;
2453 //printf(" -> found it\n");
2454 return fs;
2455 }
2456 }
2457 return nullptr;
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:104
A model of a file symbol.
Definition filedef.h:99
virtual QCString absFilePath() const =0
bool isAbsolutePath(const QCString &fileName)
Definition portable.cpp:497
static void setFileName(yyscan_t yyscanner, const QCString &name)
Definition pre.l:2259
static std::unique_ptr< FileState > checkAndOpenFile(yyscan_t yyscanner, const QCString &fileName, bool &alreadyProcessed)
Definition pre.l:2329
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:2919
2458}

References FileDef::absFilePath(), checkAndOpenFile(), FileInfo::dirPath(), FileInfo::exists(), findFileDef(), Doxygen::inputNameLinkedMap, Portable::isAbsolutePath(), and setFileName().

Referenced by readIncludeFile().

◆ forceEndCondSection()

void forceEndCondSection ( yyscan_t yyscanner)
static

Definition at line 3987 of file pre.l.

3988{
3989 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3990 while (!state->condStack.empty())
3991 {
3992 state->condStack.pop();
3993 }
3994 state->skip=false;
3995}

Referenced by Preprocessor::processFile().

◆ getCurrentChar()

int getCurrentChar ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
uint32_t pos )
static

Definition at line 4055 of file pre.l.

4056{
4057 //printf("getCurrentChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
4058 if (pos<expr.length())
4059 {
4060 //printf("%c=expr()\n",expr.at(pos));
4061 return expr.at(pos);
4062 }
4063 else if (rest && !rest->isEmpty())
4064 {
4065 int cc=rest->at(0);
4066 //printf("%c=rest\n",cc);
4067 return cc;
4068 }
4069 else
4070 {
4071 int cc=yyinput(yyscanner);
4072 returnCharToStream(yyscanner,(char)cc);
4073 //printf("%c=yyinput()\n",cc);
4074 return cc;
4075 }
static void returnCharToStream(yyscan_t yyscanner, char c)
Definition pre.l:2635
4076}

References QCString::at(), QCString::isEmpty(), QCString::length(), and returnCharToStream().

Referenced by addTillEndOfComment(), replaceFunctionMacro(), and skipCommentMacroName().

◆ getFenceSize()

yy_size_t getFenceSize ( char * txt,
yy_size_t leng )
static

Definition at line 2248 of file pre.l.

2249{
2250 yy_size_t fenceSize = 0;
2251 for (size_t i = 0; i < leng; i++)
2252 {
2253 if (txt[i] != ' ' && txt[i] != '*' && txt[i] != '\t') break;
2254 fenceSize++;
2255 }
2256 return leng-fenceSize;
2257}

◆ getLexerFILE()

const char * getLexerFILE ( )
inlinestatic

Definition at line 356 of file pre.l.

356{return __FILE__;}

◆ getNextChar()

int getNextChar ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
uint32_t & pos )
static

Definition at line 4032 of file pre.l.

4033{
4034 //printf("getNextChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
4035 if (pos<expr.length())
4036 {
4037 //printf(" expr()='%c'\n",expr.at(pos));
4038 return expr.at(pos++);
4039 }
4040 else if (rest && !rest->isEmpty())
4041 {
4042 int cc=rest->at(0);
4043 *rest=rest->right(rest->length()-1);
4044 //printf(" rest='%c'\n",cc);
4045 return cc;
4046 }
4047 else
4048 {
4049 int cc=yyinput(yyscanner);
4050 //printf(" yyinput()='%c' %d\n",cc,EOF);
4051 return cc;
4052 }
4053}

References QCString::at(), QCString::isEmpty(), QCString::length(), and QCString::right().

Referenced by addSeparatorsIfNeeded(), addTillEndOfComment(), addTillEndOfString(), replaceFunctionMacro(), and skipCommentMacroName().

◆ getNextId()

int getNextId ( const QCString & expr,
int p,
int * l )
static

returns the next identifier in string expr by starting at position p. The position of the identifier is returned (or -1 if nothing is found) and l is its length. Any quoted strings are skipping during the search.

Definition at line 3029 of file pre.l.

3030{
3031 int n;
3032 while (p<(int)expr.length())
3033 {
3034 char c=expr.at(p++);
3035 if (isdigit(c)) // skip number
3036 {
3037 while (p<(int)expr.length() && isId(expr.at(p))) p++;
3038 }
3039 else if (isalpha(c) || c=='_') // read id
3040 {
3041 n=p-1;
3042 while (p<(int)expr.length() && isId(expr.at(p))) p++;
3043 *l=p-n;
3044 return n;
3045 }
3046 else if (c=='"') // skip string
3047 {
3048 char ppc=0,pc=c;
3049 if (p<(int)expr.length()) c=expr.at(p);
3050 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
3051 // continue as long as no " is found, but ignoring \", but not \\"
3052 {
3053 ppc=pc;
3054 pc=c;
3055 c=expr.at(p);
3056 p++;
3057 }
3058 if (p<(int)expr.length()) ++p; // skip closing quote
3059 }
3060 else if (c=='/') // skip C Comment
3061 {
3062 //printf("Found C comment at p=%d\n",p);
3063 char pc=c;
3064 if (p<(int)expr.length())
3065 {
3066 c=expr.at(p);
3067 if (c=='*') // Start of C comment
3068 {
3069 p++;
3070 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
3071 {
3072 pc=c;
3073 c=expr.at(p++);
3074 }
3075 }
3076 }
3077 //printf("Found end of C comment at p=%d\n",p);
3078 }
3079 }
3080 return -1;
bool isId(int c)
Definition util.h:257
3081}

References QCString::at(), isId(), and QCString::length().

Referenced by expandExpression().

◆ incrLevel()

void incrLevel ( yyscan_t yyscanner)
static

Definition at line 2280 of file pre.l.

2281{
2282 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2283 state->levelGuard.push(false);
2284 //printf("%s line %d: incrLevel %zu\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
2285}

◆ initPredefined()

void initPredefined ( yyscan_t yyscanner,
const QCString & fileName )
static

Definition at line 4131 of file pre.l.

4132{
4133 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
4134
4135 // add predefined macros
4136 const StringVector &predefList = Config_getList(PREDEFINED);
4137 for (const auto &ds : predefList)
4138 {
4139 size_t i_equals=ds.find('=');
4140 size_t i_obrace=ds.find('(');
4141 size_t i_cbrace=ds.find(')');
4142 bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
4143
4144 if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
4145 {
4146 continue; // no define name
4147 }
4148
4149 if (i_obrace<i_equals && i_cbrace<i_equals &&
4150 i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
4151 i_obrace<i_cbrace
4152 ) // predefined function macro definition
4153 {
4154 static const reg::Ex reId(R"(\a\w*)");
4155 std::map<std::string,int> argMap;
4156 std::string args = ds.substr(i_obrace+1,i_cbrace-i_obrace-1); // part between ( and )
4157 bool hasVarArgs = args.find("...")!=std::string::npos;
4158 //printf("predefined function macro '%s'\n",qPrint(ds));
4159 int count = 0;
4160 reg::Iterator arg_it(args,reId,0);
4161 reg::Iterator arg_end;
4162 // gather the formal arguments in a dictionary
4163 for (; arg_it!=arg_end; ++arg_it)
4164 {
4165 argMap.emplace(arg_it->str(),count++);
4166 }
4167 if (hasVarArgs) // add the variable argument if present
4168 {
4169 argMap.emplace("__VA_ARGS__",count++);
4170 }
Class representing a regular expression.
Definition regex.h:39
Class to iterate through matches.
Definition regex.h:236
4171
4172 // strip definition part
4173 std::string definition;
4174 std::string in=ds.substr(i_equals+1);
4175 reg::Iterator re_it(in,reId);
4176 reg::Iterator re_end;
4177 size_t i=0;
4178 // substitute all occurrences of formal arguments by their
4179 // corresponding markers
4180 for (; re_it!=re_end; ++re_it)
4181 {
4182 const auto &match = *re_it;
4183 size_t pi = match.position();
4184 size_t l = match.length();
4185 if (pi>i) definition+=in.substr(i,pi-i);
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:858
4186
4187 auto it = argMap.find(match.str());
4188 if (it!=argMap.end())
4189 {
4190 int argIndex = it->second;
4191 QCString marker;
4192 marker.sprintf(" @%d ",argIndex);
4193 definition+=marker.str();
4194 }
4195 else
4196 {
4197 definition+=match.str();
4198 }
4199 i=pi+l;
4200 }
4201 definition+=in.substr(i);
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
4202
4203 // add define definition to the dictionary of defines for this file
4204 std::string dname = ds.substr(0,i_obrace);
4205 if (!dname.empty())
4206 {
4207 Define def;
4208 def.name = dname;
4209 def.definition = definition;
4210 def.nargs = count;
4211 def.isPredefined = true;
4212 def.nonRecursive = nonRecursive;
4213 def.fileDef = state->yyFileDef;
4214 def.fileName = fileName;
4215 def.varArgs = hasVarArgs;
4216 state->contextDefines.emplace(def.name.str(),def);
4217
4218 //printf("#define '%s' '%s' #nargs=%d hasVarArgs=%d\n",
4219 // qPrint(def.name),qPrint(def.definition),def.nargs,def.varArgs);
4220 }
4221 }
4222 else if (!ds.empty()) // predefined non-function macro definition
4223 {
4224 //printf("predefined normal macro '%s'\n",qPrint(ds));
4225 Define def;
4226 if (i_equals==std::string::npos) // simple define without argument
4227 {
4228 def.name = ds;
4229 def.definition = "1"; // substitute occurrences by 1 (true)
4230 }
4231 else // simple define with argument
4232 {
4233 int ine=static_cast<int>(i_equals) - (nonRecursive ? 1 : 0);
4234 def.name = ds.substr(0,ine);
4235 def.definition = ds.substr(i_equals+1);
4236 }
4237 if (!def.name.isEmpty())
4238 {
4239 def.nargs = -1;
4240 def.isPredefined = true;
4241 def.nonRecursive = nonRecursive;
4242 def.fileDef = state->yyFileDef;
4243 def.fileName = fileName;
4244 state->contextDefines.emplace(def.name.str(),def);
4245 }
4246 }
4247 }
4248}

References Config_getList, Define::definition, Define::fileDef, Define::fileName, QCString::isEmpty(), Define::isPredefined, Define::name, Define::nargs, Define::nonRecursive, QCString::sprintf(), QCString::str(), reg::Match::str(), and Define::varArgs.

Referenced by Preprocessor::processFile().

◆ isDefined()

Define * isDefined ( yyscan_t yyscanner,
const QCString & name )
static

Returns a reference to a Define object given its name or 0 if the Define does not exist.

Definition at line 4102 of file pre.l.

4103{
4104 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
4105
4106 bool undef = false;
4107 auto findDefine = [&undef,&name](DefineMap &map)
4108 {
4109 Define *d=nullptr;
4110 auto it = map.find(name.str());
4111 if (it!=map.end())
4112 {
4113 d = &it->second;
4114 if (d->undef)
4115 {
4116 undef=true;
4117 d=nullptr;
4118 }
4119 }
4120 return d;
4121 };
bool undef
Definition define.h:41
std::map< std::string, Define > DefineMap
A dictionary of managed Define objects.
Definition pre.l:108
4122
4123 Define *def = findDefine(state->localDefines);
4124 if (def==nullptr && !undef)
4125 {
4126 def = findDefine(state->contextDefines);
4127 }
4128 return def;
4129}

References QCString::str(), and Define::undef.

Referenced by expandExpression().

◆ otherCaseDone()

bool otherCaseDone ( yyscan_t yyscanner)
static

Definition at line 2308 of file pre.l.

2309{
2310 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2311 if (state->levelGuard.empty())
2312 {
2313 warn(state->fileName,state->yyLineNr,"Found an #else without a preceding #if.");
2314 return true;
2315 }
2316 else
2317 {
2318 return state->levelGuard.top();
2319 }
2320}

References warn.

◆ outputArray()

void outputArray ( yyscan_t yyscanner,
const char * a,
yy_size_t len )
inlinestatic

Definition at line 3710 of file pre.l.

3711{
3712 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3713 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=std::string_view(a,len);
3714}

◆ outputChar()

void outputChar ( yyscan_t yyscanner,
char c )
inlinestatic

Definition at line 3704 of file pre.l.

3705{
3706 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3707 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=c;
3708}

Referenced by outputSpace(), and outputSpaces().

◆ outputSpace()

void outputSpace ( yyscan_t yyscanner,
char c )
inlinestatic

Definition at line 3722 of file pre.l.

3723{
3724 if (c=='\t') outputChar(yyscanner,'\t');
3725 else outputChar(yyscanner,' ');
static void outputChar(yyscan_t yyscanner, char c)
Definition pre.l:3704
3726}

References outputChar().

◆ outputSpaces()

void outputSpaces ( yyscan_t yyscanner,
char * s )
inlinestatic

Definition at line 3728 of file pre.l.

3729{
3730 const char *p=s;
3731 char c = 0;
3732 while ((c=*p++))
3733 {
3734 if (c=='\t') outputChar(yyscanner,'\t');
3735 else outputChar(yyscanner,' ');
3736 }
3737}

References outputChar().

◆ outputString()

void outputString ( yyscan_t yyscanner,
const QCString & s )
inlinestatic

Definition at line 3716 of file pre.l.

3717{
3718 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3719 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=a.str();
3720}

References QCString::str().

Referenced by readIncludeFile().

◆ processConcatOperators()

void processConcatOperators ( QCString & expr)
static

Execute all ## operators in expr. If the macro name before or after the operator contains a no-rescan marker (-) then this is removed (before the concatenated macro name may be expanded again.

Definition at line 2588 of file pre.l.

2589{
2590 if (expr.isEmpty()) return;
2591 //printf("processConcatOperators: in='%s'\n",qPrint(expr));
2592 std::string e = expr.str();
2593 static const reg::Ex r(R"(\s*##\s*)");
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
2595
2596 size_t i=0;
2597 for (;;)
2598 {
2599 reg::Iterator it(e,r,i);
2600 if (it!=end)
2601 {
2602 const auto &match = *it;
2603 size_t n = match.position();
2604 size_t l = match.length();
2605 //printf("Match: '%s'\n",qPrint(expr.mid(i)));
2606 if (n+l+1<e.length() && e[static_cast<int>(n+l)]=='@' && expr[static_cast<int>(n+l+1)]=='-')
2607 {
2608 // remove no-rescan marker after ID
2609 l+=2;
2610 }
2611 //printf("found '%s'\n",qPrint(expr.mid(n,l)));
2612 // remove the ## operator and the surrounding whitespace
2613 e=e.substr(0,n)+e.substr(n+l);
2614 int k=static_cast<int>(n)-1;
2615 while (k>=0 && isId(e[k])) k--;
2616 if (k>0 && e[k]=='-' && e[k-1]=='@')
2617 {
2618 // remove no-rescan marker before ID
2619 e=e.substr(0,k-1)+e.substr(k+1);
2620 n-=2;
2621 }
2622 i=n;
2623 }
2624 else
2625 {
2626 break;
2627 }
2628 }
2629
2630 expr = e;
2631
2632 //printf("processConcatOperators: out='%s'\n",qPrint(expr));
2633}

References end(), QCString::isEmpty(), isId(), and QCString::str().

Referenced by expandExpression().

◆ processUntilMatchingTerminator()

const char * processUntilMatchingTerminator ( const char * inputStr,
QCString & result )
static

Process string or character literal.

inputStr should point to the start of a string or character literal. the routine will return a pointer to just after the end of the literal the character making up the literal will be added to result.

Definition at line 3267 of file pre.l.

3268{
3269 if (inputStr==nullptr) return inputStr;
3270 char term = *inputStr; // capture start character of the literal
3271 if (term!='\'' && term!='"') return inputStr; // not a valid literal
3272 char c=term;
3273 // output start character
3274 result+=c;
3275 inputStr++;
3276 while ((c=*inputStr)) // while inside the literal
3277 {
3278 if (c==term) // found end marker of the literal
3279 {
3280 // output end character and stop
3281 result+=c;
3282 inputStr++;
3283 break;
3284 }
3285 else if (c=='\\') // escaped character, process next character
3286 // as well without checking for end marker.
3287 {
3288 result+=c;
3289 inputStr++;
3290 c=*inputStr;
3291 if (c==0) break; // unexpected end of string after escape character
3292 }
3293 result+=c;
3294 inputStr++;
3295 }
3296 return inputStr;
3297}

References term.

Referenced by removeIdsAndMarkers(), and removeMarkers().

◆ readIncludeFile()

void readIncludeFile ( yyscan_t yyscanner,
const QCString & inc )
static

Definition at line 3785 of file pre.l.

3786{
3787 AUTO_TRACE("inc={}",inc);
3788 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3789 uint32_t i=0;
#define AUTO_TRACE(...)
Definition docnode.cpp:48
3790
3791 // find the start of the include file name
3792 while (i<inc.length() &&
3793 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
3794 ) i++;
3795 uint32_t s=i;
3796
3797 // was it a local include?
3798 bool localInclude = s>0 && inc.at(s-1)=='"';
3799
3800 // find the end of the include file name
3801 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
3802
3803 if (s<inc.length() && i>s) // valid include file name found
3804 {
3805 // extract include path+name
3806 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
3807 if (incFileName.endsWith(".exe") || incFileName.endsWith(".dll") || incFileName.endsWith(".tlb"))
3808 {
3809 // skip imported binary files (e.g. M$ type libraries)
3810 return;
3811 }
bool endsWith(const char *s) const
Definition qcstring.h:522
3812
3813 QCString oldFileName = state->fileName;
3814 FileDef *oldFileDef = state->yyFileDef;
3815 int oldLineNr = state->yyLineNr;
3816 //printf("Searching for '%s'\n",qPrint(incFileName));
3817
3818 QCString absIncFileName = determineAbsoluteIncludeName(state->fileName,incFileName);
QCString determineAbsoluteIncludeName(const QCString &curFile, const QCString &incFileName)
Definition util.cpp:3639
3819
3820 // findFile will overwrite state->yyFileDef if found
3821 std::unique_ptr<FileState> fs;
3822 bool alreadyProcessed = false;
3823 //printf("calling findFile(%s)\n",qPrint(incFileName));
3824 fs=findFile(yyscanner,absIncFileName,localInclude,alreadyProcessed); // see if the absolute include file can be found
3825 if (fs)
3826 {
3827 {
3828 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3829 g_defineManager.addInclude(oldFileName.str(),absIncFileName.str());
3830 }
void addInclude(const std::string &fromFileName, const std::string &toFileName)
Definition pre.l:172
static std::unique_ptr< FileState > findFile(yyscan_t yyscanner, const QCString &fileName, bool localInclude, bool &alreadyProcessed)
Definition pre.l:2386
3831
3832 //printf("Found include file!\n");
3834 {
3835 for (i=0;i<state->includeStack.size();i++)
3836 {
3838 }
3839 Debug::print(Debug::Preprocessor,0,"#include {}: parsing...\n",incFileName);
3840 }
@ Preprocessor
Definition debug.h:30
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:133
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:77
3841
3842 if (state->includeStack.empty() && oldFileDef)
3843 {
3844 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3845 if (ii==nullptr)
3846 {
3847 bool ambig = false;
3848 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3849 state->includeRelations.add(
3850 absIncFileName,
3851 oldFileDef,
3852 ambig ? nullptr : incFd,
3853 incFileName,
3854 localInclude,
3855 state->isImported
3856 );
3857 }
3858 }
3859
3860 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3861 fs->bufState = YY_CURRENT_BUFFER;
3862 fs->lineNr = oldLineNr;
3863 fs->fileName = oldFileName;
3864 fs->curlyCount = state->curlyCount;
3865 //state->curlyCount = 0; // don't reset counter, see issue #10997
3866 fs->lexRulesPart = state->lexRulesPart;
3867 fs->levelGuard = state->levelGuard;
3868 while (!state->levelGuard.empty()) state->levelGuard.pop();
3869 state->lexRulesPart = false;
3870 // push the state on the stack
3871 FileState *fs_ptr = fs.get();
3872 state->includeStack.push_back(std::move(fs));
3873 // set the scanner to the include file
3874
3875 // Deal with file changes due to
3876 // #include's within { .. } blocks
3877 QCString lineStr(state->fileName.length()+20, QCString::ExplicitSize);
3878 lineStr.sprintf("# 1 \"%s\" 1\n",qPrint(state->fileName));
3879 outputString(yyscanner,lineStr);
@ ExplicitSize
Definition qcstring.h:144
static void outputString(yyscan_t yyscanner, const QCString &s)
Definition pre.l:3716
const char * qPrint(const char *s)
Definition qcstring.h:685
3880
3881 AUTO_TRACE_ADD("Switching to include file {}",incFileName);
3882 state->expectGuard=true;
3883 state->inputBuf = &fs_ptr->fileBuf;
3884 state->inputBufPos=0;
3885 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
3886 }
3887 else
3888 {
3889 if (alreadyProcessed) // if this header was already process we can just copy the stored macros
3890 // in the local context
3891 {
3892 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3893 g_defineManager.addInclude(state->fileName.str(),absIncFileName.str());
3894 g_defineManager.retrieve(absIncFileName.str(),state->contextDefines);
3895 }
void retrieve(const std::string &fileName, DefineMap &toMap)
Definition pre.l:195
#define YY_BUF_SIZE
Definition commentcnv.l:19
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:49
std::string fileBuf
Definition pre.l:84
3896
3897 if (state->includeStack.empty() && oldFileDef)
3898 {
3899 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3900 if (ii==nullptr)
3901 {
3902 bool ambig = false;
3903 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3904 ii = state->includeRelations.add(absIncFileName,
3905 oldFileDef,
3906 ambig ? nullptr : incFd,
3907 incFileName,
3908 localInclude,
3909 state->isImported
3910 );
3911 }
3912 }
3913
3915 {
3916 for (i=0;i<state->includeStack.size();i++)
3917 {
3919 }
3920 if (alreadyProcessed)
3921 {
3922 Debug::print(Debug::Preprocessor,0,"#include {}: already processed! skipping...\n",incFileName);
3923 }
3924 else
3925 {
3926 Debug::print(Debug::Preprocessor,0,"#include {}: not found! skipping...\n",incFileName);
3927 }
3928 //printf("error: include file %s not found\n",yytext);
3929 }
3930 if (localInclude && !state->includeStack.empty() && state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... }
3931 {
3932 warn(state->fileName,state->yyLineNr,"include file {} not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName);
3933 }
3934 }
3935 }
3936}

References DefineManager::addInclude(), QCString::at(), AUTO_TRACE, AUTO_TRACE_ADD, determineAbsoluteIncludeName(), QCString::endsWith(), QCString::ExplicitSize, FileState::fileBuf, findFile(), findFileDef(), g_defineManager, g_globalDefineMutex, Doxygen::inputNameLinkedMap, Debug::isFlagSet(), QCString::length(), QCString::mid(), outputString(), Debug::Preprocessor, Debug::print(), qPrint(), DefineManager::retrieve(), QCString::sprintf(), QCString::str(), QCString::stripWhiteSpace(), warn, and YY_BUF_SIZE.

◆ removeIdsAndMarkers()

QCString removeIdsAndMarkers ( const QCString & s)
static

replaces all occurrences of @@ in s by @ and removes all occurrences of @E. All identifiers found are replaced by 0L

Definition at line 3303 of file pre.l.

3304{
3305 static const std::vector<std::string> signs = { "signed", "unsigned" };
3306 struct TypeInfo { std::string name; size_t size; };
3307 static const std::vector<TypeInfo> types = {
3308 { "short int", sizeof(short int) },
3309 { "long long int", sizeof(long long int) },
3310 { "long int", sizeof(long int) },
3311 { "long long", sizeof(long long) },
3312 { "long double", sizeof(long double) },
3313 { "int", sizeof(int) },
3314 { "short", sizeof(short) },
3315 { "bool", sizeof(bool) },
3316 { "long", sizeof(long) },
3317 { "char", sizeof(char) },
3318 { "float", sizeof(float) },
3319 { "double", sizeof(double) },
3320 };
3321
3322 // Check if string p starts with basic types ending with a ')', such as 'signed long)' or ' float )'
3323 // and return the pointer just past the ')' and the size of the type as a tuple.
3324 // If the pattern is not found the tuple (nullptr,0) is returned.
3325 auto process_cast_or_sizeof = [](const char *p) -> std::pair<const char *,size_t>
3326 {
3327 const char *q = p;
3328 while (*q==' ' || *q=='\t') q++;
3329 bool found=false;
3330 size_t size = sizeof(int); // '(signed)' or '(unsigned)' is an int type
3331 for (const auto &sgn : signs)
3332 {
3333 if (qstrncmp(q,sgn.c_str(),sgn.length())==0) { q+=sgn.length(); found=true; }
3334 }
3335 if (!found || *q==' ' || *q=='\t' || *q==')') // continue searching
3336 {
3337 while (*q==' ' || *q=='\t') q++;
3338 for (const auto &t : types)
3339 {
3340 if (qstrncmp(q,t.name.c_str(),t.name.length())==0)
3341 {
3342 q += t.name.length();
3343 size = t.size;
3344 break;
3345 }
3346 }
3347 while (*q==' ' || *q=='\t') q++;
3348 if (*q==')') return std::make_pair(++q,size);
3349 }
3350 return std::make_pair(nullptr,0);
3351 };
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition qcstring.h:69
3352
3353 //printf("removeIdsAndMarkers(%s)\n",qPrint(s));
3354 if (s.isEmpty()) return s;
3355 const char *p=s.data();
3356 bool inNum=false;
3357 QCString result;
3358 if (p)
3359 {
3360 char c = 0;
3361 while ((c=*p))
3362 {
3363 if (c=='(') // potential cast, ignore it
3364 {
3365 const char *q = process_cast_or_sizeof(p+1).first;
3366 //printf("potential cast:\nin: %s\nout: %s\n",p,q);
3367 if (q)
3368 {
3369 p=q;
3370 continue;
3371 }
3372 }
3373 else if (c=='s' && literal_at(p,"sizeof")) // sizeof(...)
3374 {
3375 const char *q = p+6;
3376 while (*q==' ' || *q=='\t') q++;
3377 if (*q=='(')
3378 {
3379 auto r = process_cast_or_sizeof(q+1);
3380 //printf("sizeof:\nin: %s\nout: %zu%s\n--> sizeof=%zu\n",p,r.second,r.first,r.second);
3381 if (r.first)
3382 {
3383 result+=QCString().setNum(r.second);
3384 p=r.first;
3385 continue;
3386 }
3387 }
3388 }
bool literal_at(const char *data, const char(&str)[N])
returns true iff data points to a substring that matches string literal str
Definition stringutil.h:98
3389
3390 if (c=='@') // replace @@ with @ and remove @E
3391 {
3392 if (*(p+1)=='@')
3393 {
3394 result+=c;
3395 }
3396 else if (*(p+1)=='E')
3397 {
3398 // skip
3399 }
3400 p+=2;
3401 }
3402 else if (isdigit(c)) // number
3403 {
3404 result+=c;
3405 p++;
3406 inNum=true;
3407 }
3408 else if (c=='\'') // quoted character
3409 {
3410 p = processUntilMatchingTerminator(p,result);
3411 }
3412 else if (c=='d' && !inNum) // identifier starting with a 'd'
3413 {
3414 if (literal_at(p,"defined ") || literal_at(p,"defined("))
3415 // defined keyword
3416 {
3417 p+=7; // skip defined
3418 }
3419 else
3420 {
3421 result+="0L";
3422 p++;
3423 while ((c=*p) && isId(c)) p++;
3424 }
3425 }
3426 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
3427 {
3428 result+="0L";
3429 p++;
3430 while ((c=*p) && isId(c)) p++;
3431 while ((c=*p) && isspace((uint8_t)c)) p++;
3432 if (*p=='(') // undefined function macro
3433 {
3434 p++;
3435 int count=1;
3436 while ((c=*p++))
3437 {
3438 if (c=='(') count++;
3439 else if (c==')')
3440 {
3441 count--;
3442 if (count==0) break;
3443 }
3444 else if (c=='/')
3445 {
3446 char pc=c;
3447 c=*++p;
3448 if (c=='*') // start of C comment
3449 {
3450 while (*p && !(pc=='*' && c=='/')) // search end of comment
3451 {
3452 pc=c;
3453 c=*++p;
3454 }
3455 p++;
3456 }
3457 }
3458 }
3459 }
3460 }
3461 else if (c=='/') // skip C comments
3462 {
3463 char pc=c;
3464 c=*++p;
3465 if (c=='*') // start of C comment
3466 {
3467 while (*p && !(pc=='*' && c=='/')) // search end of comment
3468 {
3469 pc=c;
3470 c=*++p;
3471 }
3472 p++;
3473 }
3474 else // oops, not comment but division
3475 {
3476 result+=pc;
3477 goto nextChar;
3478 }
3479 }
3480 else
3481 {
static const char * processUntilMatchingTerminator(const char *inputStr, QCString &result)
Process string or character literal.
Definition pre.l:3267
3482nextChar:
3483 result+=c;
3484 char lc=(char)tolower(c);
3485 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=false;
3486 p++;
3487 }
3488 }
3489 }
3490 //printf("removeIdsAndMarkers(%s)=%s\n",s,qPrint(result));
3491 return result;
3492}

References QCString::data(), QCString::isEmpty(), isId(), literal_at(), processUntilMatchingTerminator(), qstrncmp(), and QCString::setNum().

Referenced by computeExpression().

◆ removeMarkers()

QCString removeMarkers ( const QCString & s)
static

replaces all occurrences of @ in s by @

assumption:
s only contains pairs of @'s

Definition at line 3498 of file pre.l.

3499{
3500 if (s.isEmpty()) return s;
3501 const char *p=s.data();
3502 QCString result;
3503 if (p)
3504 {
3505 char c = 0;
3506 while ((c=*p))
3507 {
3508 switch(c)
3509 {
3510 case '@': // replace @@ with @
3511 {
3512 if (*(p+1)=='@')
3513 {
3514 result+=c;
3515 }
3516 p+=2;
3517 }
3518 break;
3519 case '/': // skip C comments
3520 {
3521 result+=c;
3522 char pc=c;
3523 c=*++p;
3524 if (c=='*') // start of C comment
3525 {
3526 while (*p && !(pc=='*' && c=='/')) // search end of comment
3527 {
3528 if (*p=='@' && *(p+1)=='@')
3529 {
3530 result+=c;
3531 p++;
3532 }
3533 else
3534 {
3535 result+=c;
3536 }
3537 pc=c;
3538 c=*++p;
3539 }
3540 if (*p)
3541 {
3542 result+=c;
3543 p++;
3544 }
3545 }
3546 }
3547 break;
3548 case '"': // skip string literals
3549 case '\'': // skip char literals
3550 p = processUntilMatchingTerminator(p,result);
3551 break;
3552 default:
3553 {
3554 result+=c;
3555 p++;
3556 }
3557 break;
3558 }
3559 }
3560 }
3561 //printf("RemoveMarkers(%s)=%s\n",s,qPrint(result));
3562 return result;
3563}

References QCString::data(), QCString::isEmpty(), and processUntilMatchingTerminator().

Referenced by computeExpression(), and expandMacro().

◆ replaceFunctionMacro()

bool replaceFunctionMacro ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
int pos,
int & len,
const Define * def,
QCString & result,
int level )
static

replaces the function macro def whose argument list starts at pos in expression expr. Notice that this routine may scan beyond the expr string if needed. In that case the characters will be read from the input file. The replacement string will be returned in result and the length of the (unexpanded) argument list is stored in len.

Definition at line 2760 of file pre.l.

2761{
2762 //printf(">replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s') level=%zu\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),preYYget_extra(yyscanner)->levelGuard.size());
2763 uint32_t j=pos;
2764 len=0;
2765 result.clear();
2766 int cc;
2767
2768 skipCommentMacroName(yyscanner, expr, rest, cc, j, len);
static void skipCommentMacroName(yyscan_t yyscanner, const QCString &expr, QCString *rest, int &cc, uint32_t &j, int &len)
Definition pre.l:2676
2769
2770 if (cc!='(')
2771 {
2772 if (cc!=':') // don't add spaces for colons
2773 {
2774 unputChar(yyscanner,expr,rest,j,' ');
2775 }
2776 return false;
2777 }
2778 getNextChar(yyscanner,expr,rest,j); // eat the '(' character
2779
2780 std::map<std::string,std::string> argTable; // list of arguments
2781 QCString arg;
2782 int argCount=0;
2783 int argCountNonEmpty=0;
2784 bool done=false;
2785
2786 // PHASE 1: read the macro arguments
2787 if (def->nargs==0)
2788 {
2789 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2790 {
2791 char c = (char)cc;
2792 if (c==')') break;
2793 }
2794 }
2795 else
2796 {
2797 while (!done && (argCount<def->nargs || def->varArgs) &&
2798 ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2799 )
2800 {
2801 char c=(char)cc;
2802 if (c=='(') // argument is a function => search for matching )
2803 {
2804 int lvl=1;
2805 arg+=c;
2806 //char term='\0';
2807 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2808 {
2809 c=(char)cc;
2810 //printf("processing %c: term=%c (%d)\n",c,term,term);
2811 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
2812 {
2813 arg+=c;
2814 addTillEndOfString(yyscanner,expr,rest,j,c,arg);
2815 }
2816 else if (c=='/')
2817 {
2818 int nxtChar = getCurrentChar(yyscanner,expr,rest,j);
2819 if (nxtChar == '*')
2820 {
2821 arg+=c;
2822 addTillEndOfComment(yyscanner,expr,rest,j,c,arg);
2823 }
2824 // We don't need to handle the // case as this has already been converted into a /* .. */ comment.
2825 }
static void addTillEndOfString(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
Definition pre.l:2641
static void addTillEndOfComment(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
Definition pre.l:2660
2826
2827 if (c==')')
2828 {
2829 lvl--;
2830 arg+=c;
2831 if (lvl==0) break;
2832 }
2833 else if (c=='(')
2834 {
2835 lvl++;
2836 arg+=c;
2837 }
2838 else
2839 {
2840 arg+=c;
2841 }
2842 }
2843 }
2844 else if (c==')' || c==',') // last or next argument found
2845 {
2846 if (c==',' && argCount==def->nargs-1 && def->varArgs)
2847 {
2848 expandExpression(yyscanner,arg,nullptr,0,level+1);
2849 arg=arg.stripWhiteSpace();
2850 arg+=',';
2851 }
2852 else
2853 {
2854 expandExpression(yyscanner,arg,nullptr,0,level+1);
2855 arg=arg.stripWhiteSpace();
2856 QCString argKey;
2857 argKey.sprintf("@%d",argCount++); // key name
2858 if (c==',' || !arg.isEmpty()) argCountNonEmpty++;
2859 // add argument to the lookup table
2860 argTable.emplace(toStdString(argKey), toStdString(arg));
2861 arg.clear();
2862 if (c==')') // end of the argument list
2863 {
2864 done=true;
2865 }
2866 }
2867 }
2868 else if (c=='\"') // append literal strings
2869 {
2870 arg+=c;
2871 bool found=false;
2872 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2873 {
2874 found = cc=='"';
2875 if (cc=='\\')
2876 {
2877 c=(char)cc;
2878 arg+=c;
2879 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2880 }
2881 c=(char)cc;
2882 arg+=c;
2883 }
2884 }
2885 else if (c=='\'') // append literal characters
2886 {
2887 arg+=c;
2888 bool found=false;
2889 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2890 {
2891 found = cc=='\'';
2892 if (cc=='\\')
2893 {
2894 c=(char)cc;
2895 arg+=c;
2896 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2897 }
2898 c=(char)cc;
2899 arg+=c;
2900 }
2901 }
2902 else if (c=='/') // possible start of a comment
2903 {
2904 char prevChar = '\0';
2905 arg+=c;
2906 if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment
2907 {
2908 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2909 {
2910 c=(char)cc;
2911 arg+=c;
2912 if (c == '/' && prevChar == '*') break; // we have an end of comment
2913 prevChar = c;
2914 }
2915 }
2916 }
2917 else // append other characters
2918 {
2919 arg+=c;
2920 }
2921 }
2922 }
2923
2924 // PHASE 2: apply the macro function
2925 if (argCount==def->nargs || // same number of arguments
2926 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
2927 // params as the non-variadic part (see bug731985)
2928 {
2929 uint32_t k=0;
2930 // substitution of all formal arguments
2931 QCString resExpr;
2933 //printf("varArgs=%d argCount=%d def->nargs=%d d=%s\n",def->varArgs,argCount,def->nargs,qPrint(d));
2934 if (def->varArgs) d = expandVAOpt(d,argCountNonEmpty!=def->nargs-1);
2935 //printf("Macro definition: '%s'\n",qPrint(d));
2936 bool inString=false;
2937 while (k<d.length())
2938 {
2939 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
2940 {
2941 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
2942 {
2943 k+=2;
2944 resExpr+="@@"; // we unescape these later
2945 }
2946 else if (d.at(k+1)=='-') // no-rescan marker
2947 {
2948 k+=2;
2949 resExpr+="@-";
2950 }
2951 else // argument marker => read the argument number
2952 {
2953 QCString key="@";
2954 bool hash=false;
2955 int l=k-1;
2956 // search for ## backward
2957 if (l>=0 && d.at(l)=='"') l--;
2958 while (l>=0 && d.at(l)==' ') l--;
2959 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=true;
2960 k++;
2961 // scan the number
2962 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
2963 if (!hash)
2964 {
2965 // search for ## forward
2966 l=k;
2967 if (l<(int)d.length() && d.at(l)=='"') l++;
2968 while (l<(int)d.length() && d.at(l)==' ') l++;
2969 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=true;
2970 }
2971 //printf("request key %s result %s\n",qPrint(key),argTable[key]->data());
2972 auto it = argTable.find(key.str());
2973 if (it!=argTable.end())
2974 {
2975 QCString substArg = it->second;
2976 //printf("substArg='%s'\n",qPrint(substArg));
2977 // only if no ## operator is before or after the argument
2978 // marker we do macro expansion.
2979 if (!hash)
2980 {
2981 expandExpression(yyscanner,substArg,nullptr,0,level+1);
2982 }
2983 if (inString)
2984 {
2985 //printf("'%s'=stringize('%s')\n",qPrint(stringize(*subst)),subst->data());
static QCString expandVAOpt(const QCString &vaStr, bool hasOptionalArgs)
Definition pre.l:2708
2986
2987 // if the marker is inside a string (because a # was put
2988 // before the macro name) we must escape " and \ characters
2989 resExpr+=stringize(substArg);
2990 }
2991 else
2992 {
2993 if (hash && substArg.isEmpty())
2994 {
2995 resExpr+="@E"; // empty argument will be remove later on
2996 }
2997 resExpr+=substArg;
2998 }
2999 }
3000 }
3001 }
3002 else // no marker, just copy
3003 {
3004 if (!inString && d.at(k)=='\"')
3005 {
3006 inString=true; // entering a literal string
3007 }
3008 else if (k>2 && inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
3009 {
3010 inString=false; // leaving a literal string
3011 }
3012 resExpr+=d.at(k++);
3013 }
3014 }
3015 len=j-pos;
3016 result=resExpr;
3017 //printf("<replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s',result='%s') level=%zu return=true\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),qPrint(result),preYYget_extra(yyscanner)->levelGuard.size());
3018 return true;
3019 }
3020 //printf("<replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s',result='%s') level=%zu return=false\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),qPrint(result),preYYget_extra(yyscanner)->levelGuard.size());
3021 return false;
static QCString stringize(const QCString &s)
Definition pre.l:2510
3022}

References addTillEndOfComment(), addTillEndOfString(), QCString::at(), QCString::clear(), Define::definition, expandExpression(), expandVAOpt(), getCurrentChar(), getNextChar(), QCString::isEmpty(), QCString::length(), Define::nargs, skipCommentMacroName(), QCString::sprintf(), QCString::str(), stringize(), QCString::stripWhiteSpace(), toStdString(), unputChar(), and Define::varArgs.

Referenced by expandExpression().

◆ resolveTrigraph()

char resolveTrigraph ( char c)
static

Definition at line 4012 of file pre.l.

4013{
4014 switch (c)
4015 {
4016 case '=': return '#';
4017 case '/': return '\\';
4018 case '\'': return '^';
4019 case '(': return '[';
4020 case ')': return ']';
4021 case '!': return '|';
4022 case '<': return '{';
4023 case '>': return '}';
4024 case '-': return '~';
4025 }
4026 return '?';
4027}

◆ returnCharToStream()

void returnCharToStream ( yyscan_t yyscanner,
char c )
static

Definition at line 2635 of file pre.l.

2636{
2637 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2638 unput(c);
2639}

Referenced by getCurrentChar(), and unputChar().

◆ setCaseDone()

void setCaseDone ( yyscan_t yyscanner,
bool value )
static

Definition at line 2322 of file pre.l.

2323{
2324 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2325 state->levelGuard.top()=value;
2326}

◆ setFileName()

void setFileName ( yyscan_t yyscanner,
const QCString & name )
static

Definition at line 2259 of file pre.l.

2260{
2261 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2262 bool ambig = false;
2263 FileInfo fi(name.str());
2264 state->fileName=fi.absFilePath();
2265 state->yyFileDef=findFileDef(Doxygen::inputNameLinkedMap,state->fileName,ambig);
2266 if (state->yyFileDef==nullptr) // if this is not an input file check if it is an include file
2267 {
2268 state->yyFileDef=findFileDef(Doxygen::includeNameLinkedMap,state->fileName,ambig);
2269 }
2270 //printf("setFileName(%s) state->fileName=%s state->yyFileDef=%p\n",
2271 // name,qPrint(state->fileName),state->yyFileDef);
2272 if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=nullptr;
2273 state->insideIDL = getLanguageFromFileName(state->fileName)==SrcLangExt::IDL;
2274 state->insideCS = getLanguageFromFileName(state->fileName)==SrcLangExt::CSharp;
2275 state->insideFtn = getLanguageFromFileName(state->fileName)==SrcLangExt::Fortran;
2276 EntryType section = guessSection(state->fileName);
2277 state->isSource = section.isHeader() || section.isSource();
static FileNameLinkedMap * includeNameLinkedMap
Definition doxygen.h:101
Wrapper class for the Entry type.
Definition types.h:856
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5253
EntryType guessSection(const QCString &name)
Definition util.cpp:338
2278}

References FileInfo::absFilePath(), findFileDef(), getLanguageFromFileName(), guessSection(), Doxygen::includeNameLinkedMap, Doxygen::inputNameLinkedMap, and QCString::str().

Referenced by findFile(), and Preprocessor::processFile().

◆ skipCommentMacroName()

void skipCommentMacroName ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
int & cc,
uint32_t & j,
int & len )
static

Definition at line 2676 of file pre.l.

2678{
2679 bool changed = false;
2680
2681 do
2682 {
2683 changed = false;
2684 while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc!='\n' && isspace(cc))
2685 {
2686 len++;
2687 getNextChar(yyscanner,expr,rest,j);
2688 }
2689
2690 if (cc=='/') // possible start of a comment
2691 {
2692 int prevChar = '\0';
2693 getNextChar(yyscanner,expr,rest,j);
2694 if ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc == '*') // we have a comment
2695 {
2696 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2697 {
2698 if (cc == '/' && prevChar == '*') break; // we have an end of comment
2699 prevChar = cc;
2700 }
2701 if (cc != EOF) changed = true;
2702 }
2703 }
2704 } while (changed);
2705}

References getCurrentChar(), and getNextChar().

Referenced by replaceFunctionMacro().

◆ startCondSection()

void startCondSection ( yyscan_t yyscanner,
const QCString & sectId )
static

Definition at line 3940 of file pre.l.

3941{
3942 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3943 //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.size());
3944 CondParser prs;
3945 bool expResult = prs.parse(state->fileName.data(),state->yyLineNr,sectId.data());
3946 state->condStack.emplace(std::make_unique<preYY_CondCtx>(state->fileName,state->yyLineNr,sectId,state->skip));
3947 if (!expResult)
3948 {
3949 state->skip=true;
3950 }
3951 //printf(" expResult=%d skip=%d\n",expResult,state->skip);
Copyright (C) 1997-2015 by Dimitri van Heesch.
Definition condparser.h:28
bool parse(const QCString &fileName, int lineNr, const QCString &expr)
Copyright (C) 1997-2015 by Dimitri van Heesch.
3952}

References QCString::data(), and CondParser::parse().

◆ stateToString()

const char * stateToString ( int state)
static

◆ stringize()

QCString stringize ( const QCString & s)
static

Definition at line 2510 of file pre.l.

2511{
2512 QCString result;
2513 uint32_t i=0;
2514 bool inString=false;
2515 bool inChar=false;
2516 char c,pc;
2517 while (i<s.length())
2518 {
2519 if (!inString && !inChar)
2520 {
2521 while (i<s.length() && !inString && !inChar)
2522 {
2523 c=s.at(i++);
2524 if (c=='"')
2525 {
2526 result+="\\\"";
2527 inString=true;
2528 }
2529 else if (c=='\'')
2530 {
2531 result+=c;
2532 inChar=true;
2533 }
2534 else
2535 {
2536 result+=c;
2537 }
2538 }
2539 }
2540 else if (inChar)
2541 {
2542 while (i<s.length() && inChar)
2543 {
2544 c=s.at(i++);
2545 if (c=='\'')
2546 {
2547 result+='\'';
2548 inChar=false;
2549 }
2550 else if (c=='\\')
2551 {
2552 result+="\\\\";
2553 }
2554 else
2555 {
2556 result+=c;
2557 }
2558 }
2559 }
2560 else
2561 {
2562 pc=0;
2563 while (i<s.length() && inString)
2564 {
2565 c=s.at(i++);
2566 if (c=='"')
2567 {
2568 result+="\\\"";
2569 inString= pc=='\\';
2570 }
2571 else if (c=='\\')
2572 result+="\\\\";
2573 else
2574 result+=c;
2575 pc=c;
2576 }
2577 }
2578 }
2579 //printf("stringize '%s'->'%s'\n",qPrint(s),qPrint(result));
2580 return result;
2581}

References QCString::at(), and QCString::length().

Referenced by replaceFunctionMacro().

◆ unputChar()

void unputChar ( yyscan_t yyscanner,
const QCString & expr,
QCString * rest,
uint32_t & pos,
char c )
static

Definition at line 4078 of file pre.l.

4079{
4080 //printf("unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
4081 if (pos<expr.length())
4082 {
4083 pos++;
4084 }
4085 else if (rest)
4086 {
4087 //printf(" prepending '%c' to rest!\n",c);
4088 char cs[2];cs[0]=c;cs[1]='\0';
4089 rest->prepend(cs);
4090 }
4091 else
4092 {
4093 //printf(" yyunput()='%c'\n",c);
4094 returnCharToStream(yyscanner,c);
4095 }
4096 //printf("result: unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
QCString & prepend(const char *s)
Definition qcstring.h:420
4097}

References QCString::length(), QCString::prepend(), and returnCharToStream().

Referenced by addSeparatorsIfNeeded(), and replaceFunctionMacro().

◆ yylex()

int yylex ( yyscan_t yyscanner)

Definition at line 489 of file pre.l.

494 { // Trigraph
495 unput(resolveTrigraph(yytext[2]));
496 }
static char resolveTrigraph(char c)
Definition pre.l:4012
497<Start>^{B}*"#" {
498 yyextra->yyColNr+=(int)yyleng;
499 yyextra->yyMLines=0;
500 yyextra->potentialDefine=yytext;
501 BEGIN(Command);
502 }
503<Start>^("%top{"|"%{") {
504 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Lex) REJECT
505 outputArray(yyscanner,yytext,yyleng);
506 BEGIN(LexCopyLine);
507 }
static void outputArray(yyscan_t yyscanner, const char *a, yy_size_t len)
Definition pre.l:3710
508<Start>^{Bopt}"cpp_quote"{Bopt}"("{Bopt}\" {
509 if (yyextra->insideIDL)
510 {
511 BEGIN(IDLquote);
512 }
513 else
514 {
515 REJECT;
516 }
517 }
518<IDLquote>"\\\\" {
519 outputArray(yyscanner,"\\",1);
520 }
521<IDLquote>"\\\"" {
522 outputArray(yyscanner,"\"",1);
523 }
524<IDLquote>"\""{Bopt}")" {
525 BEGIN(Start);
526 }
527<IDLquote>\n {
528 outputChar(yyscanner,'\n');
529 yyextra->yyLineNr++;
530 }
531<IDLquote>. {
532 outputArray(yyscanner,yytext,yyleng);
533 }
534<Start>^{Bopt}/[^#] {
535 outputArray(yyscanner,yytext,yyleng);
536 BEGIN(CopyLine);
537 }
538<Start>^{B}*[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]+{B}*"("[^\‍)\n]*")"/{BN}{1,10}*[:{] { // constructors?
539 int i;
540 for (i=(int)yyleng-1;i>=0;i--)
541 {
542 unput(yytext[i]);
543 }
544 BEGIN(CopyLine);
545 }
546<Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\‍(\‍)\n]*"("[^\‍)\n]*")"[^\‍)\n]*")"{B}*\n | // function list macro with one (...) argument, e.g. for K_GLOBAL_STATIC_WITH_ARGS
547<Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\‍)\n]*")"{B}*\n | // function like macro
548<Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\‍(\‍)\n]*"("[^\‍)\n]*")"[^\‍)\n]*")"/{B}*("//"|"/\*") | // function list macro with one (...) argument followed by comment
549<Start>^{B}*[_A-Z][_A-Z0-9]+{B}*"("[^\‍)\n]*")"/{B}*("//"|"/\*") { // function like macro followed by comment
550 bool skipFuncMacros = Config_getBool(SKIP_FUNCTION_MACROS);
551 QCString name(yytext);
552 int pos = name.find('(');
553 if (pos<0) pos=0; // should never happen
554 name=name.left(pos).stripWhiteSpace();
#define Config_getBool(name)
Definition config.h:33
555
556 Define *def=nullptr;
557 if (skipFuncMacros && !yyextra->insideFtn &&
558 name!="Q_PROPERTY" &&
559 !(
560 (yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
561 yyextra->macroExpansion &&
562 (def=isDefined(yyscanner,name)) &&
563 /*macroIsAccessible(def) &&*/
564 (!yyextra->expandOnlyPredef || def->isPredefined)
565 )
566 )
567 {
568 // Only when ends on \n
569 if (yytext[yyleng-1] == '\n')
570 {
571 outputChar(yyscanner,'\n');
572 yyextra->yyLineNr++;
573 }
574 }
575 else // don't skip
576 {
577 int i;
578 for (i=(int)yyleng-1;i>=0;i--)
579 {
580 unput(yytext[i]);
581 }
582 BEGIN(CopyLine);
583 }
584 }
585<CopyLine,LexCopyLine>"extern"{BN}*"\""[^\"]+"\""{BN}*("{")? {
586 QCString text=yytext;
587 yyextra->yyLineNr+=text.contains('\n');
588 outputArray(yyscanner,yytext,yyleng);
589 }
590<CopyLine,LexCopyLine>{RAWBEGIN} {
591 yyextra->delimiter = extractBeginRawStringDelimiter(yytext);
592 outputArray(yyscanner,yytext,yyleng);
593 BEGIN(CopyRawString);
594 }
QCString extractBeginRawStringDelimiter(const char *rawStart)
Definition util.cpp:6974
595<CopyLine,LexCopyLine>"{" { // count brackets inside the main file
596 if (yyextra->includeStack.empty())
597 {
598 yyextra->curlyCount++;
599 }
600 outputChar(yyscanner,*yytext);
601 }
602<LexCopyLine>^"%}" {
603 outputArray(yyscanner,yytext,yyleng);
604 }
605<CopyLine,LexCopyLine>"}" { // count brackets inside the main file
606 if (yyextra->includeStack.empty() && yyextra->curlyCount>0)
607 {
608 yyextra->curlyCount--;
609 }
610 outputChar(yyscanner,*yytext);
611 }
612<CopyLine,LexCopyLine>"'"\\‍[0-7]{1,3}"'" {
613 outputArray(yyscanner,yytext,yyleng);
614 }
615<CopyLine,LexCopyLine>"'"\\."'" {
616 outputArray(yyscanner,yytext,yyleng);
617 }
618<CopyLine,LexCopyLine>"'"."'" {
619 outputArray(yyscanner,yytext,yyleng);
620 }
621<CopyLine,LexCopyLine>[$]?@\" {
622 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::CSharp) REJECT;
623 outputArray(yyscanner,yytext,yyleng);
624 BEGIN( CopyStringCs );
625 }
626<CopyLine,LexCopyLine>\" {
627 outputChar(yyscanner,*yytext);
628 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Fortran)
629 {
630 BEGIN( CopyString );
631 }
632 else
633 {
634 BEGIN( CopyStringFtnDouble );
635 }
636 }
637<CopyLine,LexCopyLine>\' {
638 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Fortran) REJECT;
639 outputChar(yyscanner,*yytext);
640 BEGIN( CopyStringFtn );
641 }
642<CopyString>[^\"\\\r\n]{1,1000} {
643 outputArray(yyscanner,yytext,yyleng);
644 }
645<CopyStringCs>[^\"\r\n]{1,1000} {
646 outputArray(yyscanner,yytext,yyleng);
647 }
648<CopyStringCs>\"\" {
649 outputArray(yyscanner,yytext,yyleng);
650 }
651<CopyString>\\. {
652 outputArray(yyscanner,yytext,yyleng);
653 }
654<CopyString,CopyStringCs>\" {
655 outputChar(yyscanner,*yytext);
656 BEGIN( CopyLine );
657 }
658<CopyStringFtnDouble>[^\"\\\r\n]{1,1000} {
659 outputArray(yyscanner,yytext,yyleng);
660 }
661<CopyStringFtnDouble>\\. {
662 outputArray(yyscanner,yytext,yyleng);
663 }
664<CopyStringFtnDouble>\" {
665 outputChar(yyscanner,*yytext);
666 BEGIN( CopyLine );
667 }
668<CopyStringFtn>[^\'\\\r\n]{1,1000} {
669 outputArray(yyscanner,yytext,yyleng);
670 }
671<CopyStringFtn>\\. {
672 outputArray(yyscanner,yytext,yyleng);
673 }
674<CopyStringFtn>\' {
675 outputChar(yyscanner,*yytext);
676 BEGIN( CopyLine );
677 }
678<CopyRawString>{RAWEND} {
679 outputArray(yyscanner,yytext,yyleng);
680 if (extractEndRawStringDelimiter(yytext)==yyextra->delimiter)
681 {
682 BEGIN( CopyLine );
683 }
684 }
QCString extractEndRawStringDelimiter(const char *rawEnd)
Definition util.cpp:6982
685<CopyRawString>[^)]{1,1000} {
686 outputArray(yyscanner,yytext,yyleng);
687 }
688<CopyRawString>. {
689 outputChar(yyscanner,*yytext);
690 }
691<CopyLine,LexCopyLine>{ID}/{BN}{0,80}"(" {
692 yyextra->expectGuard = false;
693 Define *def=nullptr;
694 //def=yyextra->globalDefineDict->find(yytext);
695 //def=isDefined(yyscanner,yytext);
696 //printf("Search for define %s found=%d yyextra->includeStack.empty()=%d "
697 // "yyextra->curlyCount=%d yyextra->macroExpansion=%d yyextra->expandOnlyPredef=%d "
698 // "isPreDefined=%d\n",yytext,def ? 1 : 0,
699 // yyextra->includeStack.empty(),yyextra->curlyCount,yyextra->macroExpansion,yyextra->expandOnlyPredef,
700 // def ? def->isPredefined : -1
701 // );
702 if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
703 yyextra->macroExpansion &&
704 (def=isDefined(yyscanner,yytext)) &&
705 (!yyextra->expandOnlyPredef || def->isPredefined)
706 )
707 {
708 //printf("Found it! #args=%d\n",def->nargs);
709 yyextra->roundCount=0;
710 yyextra->defArgsStr=yytext;
711 QCString resultExpr;
712 if (def->nargs==-1) // no function macro
713 {
714 QCString result = def->isPredefined && !def->expandAsDefined ?
715 def->definition :
716 expandMacro(yyscanner,yyextra->defArgsStr);
717 outputString(yyscanner,result);
718 }
719 else // zero or more arguments
720 {
721 yyextra->findDefArgContext = CopyLine;
722 BEGIN(FindDefineArgs);
723 }
724 }
725 else
726 {
727 outputArray(yyscanner,yytext,yyleng);
728 }
729 }
static QCString expandMacro(yyscan_t yyscanner, const QCString &name)
Definition pre.l:3588
730<CopyLine>{RulesDelim} {
731 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Lex) REJECT;
732 yyextra->lexRulesPart = !yyextra->lexRulesPart;
733 outputArray(yyscanner,yytext,yyleng);
734 }
735 /* start lex rule handling */
736<CopyLine>{RulesSharp} {
737 if (!yyextra->lexRulesPart) REJECT;
738 if (yyextra->curlyCount) REJECT;
739 outputArray(yyscanner,yytext,yyleng);
740 BEGIN(RulesPattern);
741 }
742<RulesPattern>{EscapeRulesChar} {
743 outputArray(yyscanner,yytext,yyleng);
744 }
745<RulesPattern>{RulesCurly} {
746 outputArray(yyscanner,yytext,yyleng);
747 }
748<RulesPattern>{StartDouble} {
749 outputArray(yyscanner,yytext,yyleng);
750 yyextra->lastContext = YY_START;
751 BEGIN(RulesDouble);
752 }
753<RulesDouble,RulesRoundDouble>"\\\\" {
754 outputArray(yyscanner,yytext,yyleng);
755 }
756<RulesDouble,RulesRoundDouble>"\\\"" {
757 outputArray(yyscanner,yytext,yyleng);
758 }
759<RulesDouble>"\"" {
760 outputArray(yyscanner,yytext,yyleng);
761 BEGIN( yyextra->lastContext ) ;
762 }
763<RulesRoundDouble>"\"" {
764 outputArray(yyscanner,yytext,yyleng);
765 BEGIN(RulesRound) ;
766 }
767<RulesDouble,RulesRoundDouble>. {
768 outputArray(yyscanner,yytext,yyleng);
769 }
770<RulesPattern>{StartSquare} {
771 outputArray(yyscanner,yytext,yyleng);
772 yyextra->lastContext = YY_START;
773 BEGIN(RulesSquare);
774 }
775<RulesSquare,RulesRoundSquare>{CHARCE} {
776 outputArray(yyscanner,yytext,yyleng);
777 }
778<RulesSquare,RulesRoundSquare>"\\‍[" |
779<RulesSquare,RulesRoundSquare>"\\‍]" {
780 outputArray(yyscanner,yytext,yyleng);
781 }
782<RulesSquare>"]" {
783 outputArray(yyscanner,yytext,yyleng);
784 BEGIN(RulesPattern);
785 }
786<RulesRoundSquare>"]" {
787 outputArray(yyscanner,yytext,yyleng);
788 BEGIN(RulesRound) ;
789 }
790<RulesSquare,RulesRoundSquare>"\\\\" {
791 outputArray(yyscanner,yytext,yyleng);
792 }
793<RulesSquare,RulesRoundSquare>. {
794 outputArray(yyscanner,yytext,yyleng);
795 }
796<RulesPattern>{StartRoundQuest} {
797 outputArray(yyscanner,yytext,yyleng);
798 yyextra->lastContext = YY_START;
799 BEGIN(RulesRoundQuest);
800 }
801<RulesRoundQuest>{nl} {
802 outputArray(yyscanner,yytext,yyleng);
803 }
804<RulesRoundQuest>[^)] {
805 outputArray(yyscanner,yytext,yyleng);
806 }
807<RulesRoundQuest>")" {
808 outputArray(yyscanner,yytext,yyleng);
809 BEGIN(yyextra->lastContext);
810 }
811<RulesPattern>{StartRound} {
812 yyextra->roundCount++;
813 outputArray(yyscanner,yytext,yyleng);
814 yyextra->lastContext = YY_START;
815 BEGIN(RulesRound);
816 }
817<RulesRound>{RulesCurly} {
818 outputArray(yyscanner,yytext,yyleng);
819 }
820<RulesRound>{StartSquare} {
821 outputArray(yyscanner,yytext,yyleng);
822 BEGIN(RulesRoundSquare);
823 }
824<RulesRound>{StartDouble} {
825 outputArray(yyscanner,yytext,yyleng);
826 BEGIN(RulesRoundDouble);
827 }
828<RulesRound>{EscapeRulesChar} {
829 outputArray(yyscanner,yytext,yyleng);
830 }
831<RulesRound>"(" {
832 yyextra->roundCount++;
833 outputArray(yyscanner,yytext,yyleng);
834 }
835<RulesRound>")" {
836 yyextra->roundCount--;
837 outputArray(yyscanner,yytext,yyleng);
838 if (!yyextra->roundCount) BEGIN( yyextra->lastContext ) ;
839 }
840<RulesRound>{nl} {
841 outputArray(yyscanner,yytext,yyleng);
842 }
843<RulesRound>{B} {
844 outputArray(yyscanner,yytext,yyleng);
845 }
846<RulesRound>. {
847 outputArray(yyscanner,yytext,yyleng);
848 }
849<RulesPattern>{B} {
850 outputArray(yyscanner,yytext,yyleng);
851 BEGIN(CopyLine);
852 }
853<RulesPattern>. {
854 outputArray(yyscanner,yytext,yyleng);
855 }
856 /* end lex rule handling */
857<CopyLine,LexCopyLine>{ID} {
858 Define *def=nullptr;
859 QCString result;
860 if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) &&
861 yyextra->macroExpansion &&
862 (def=isDefined(yyscanner,yytext)) &&
863 def->nargs==-1 &&
864 (!yyextra->expandOnlyPredef || def->isPredefined)
865 )
866 {
867 result=def->isPredefined && !def->expandAsDefined ?
868 def->definition :
869 expandMacro(yyscanner,yytext);
870 outputString(yyscanner,result);
871 }
872 else if (!(result = expandStandardMacro(yyscanner,yytext)).isEmpty())
873 {
874 outputString(yyscanner,result);
875 }
876 else
877 {
878 outputArray(yyscanner,yytext,yyleng);
879 }
880 }
881<CopyLine,LexCopyLine>"\\"\r?/\n { // strip line continuation characters
882 if (getLanguageFromFileName(yyextra->fileName)==SrcLangExt::Fortran) outputChar(yyscanner,*yytext);
883 }
884<CopyLine,LexCopyLine>\\. {
885 outputArray(yyscanner,yytext,(int)yyleng);
886 }
887<CopyLine,LexCopyLine>. {
888 outputChar(yyscanner,*yytext);
889 }
890<CopyLine,LexCopyLine>\n {
891 outputChar(yyscanner,'\n');
892 BEGIN(Start);
893 yyextra->yyLineNr++;
894 yyextra->yyColNr=1;
895 }
896<FindDefineArgs>"(" {
897 yyextra->defArgsStr+='(';
898 yyextra->roundCount++;
899 }
900<FindDefineArgs>")" {
901 yyextra->defArgsStr+=')';
902 yyextra->roundCount--;
903 if (yyextra->roundCount==0)
904 {
905 QCString result=expandMacro(yyscanner,yyextra->defArgsStr);
906 //printf("yyextra->defArgsStr='%s'->'%s'\n",qPrint(yyextra->defArgsStr),qPrint(result));
907 if (yyextra->findDefArgContext==CopyLine)
908 {
909 outputString(yyscanner,result);
910 BEGIN(yyextra->findDefArgContext);
911 }
912 else // yyextra->findDefArgContext==IncludeID
913 {
914 readIncludeFile(yyscanner,result);
915 yyextra->nospaces=false;
916 BEGIN(Start);
917 }
918 }
919 }
920 /*
static void readIncludeFile(yyscan_t yyscanner, const QCString &inc)
Definition pre.l:3785
921<FindDefineArgs>")"{B}*"(" {
922 yyextra->defArgsStr+=yytext;
923 }
924 */
925<FindDefineArgs>{CHARLIT} {
926 yyextra->defArgsStr+=yytext;
927 }
928<FindDefineArgs>{CCS}[*!]? {
929 yyextra->defArgsStr+=yytext;
930 BEGIN(ArgCopyCComment);
931 }
932<FindDefineArgs>{CPPC}[/!].*\n/{B}*{CPPC}[/!] { // replace multi line C++ style comment by C style comment
933 if (Config_getBool(MULTILINE_CPP_IS_BRIEF) && !Config_getBool(QT_AUTOBRIEF))
934 {
935 if (yytext[3]=='<') // preserve < before @brief
936 {
937 yyextra->defArgsStr+=QCString("/**< @brief ")+&yytext[4];
938 }
939 else
940 {
941 yyextra->defArgsStr+=QCString("/** @brief ")+&yytext[3];
942 }
943 }
944 else
945 {
946 yyextra->defArgsStr+=QCString("/**")+&yytext[3];
947 }
948 BEGIN(ArgCopyCppComment);
949 }
950<FindDefineArgs>{CPPC}[/!].*\n { // replace C++ single line style comment by C style comment
951 if (Config_getBool(QT_AUTOBRIEF))
952 {
953 yyextra->defArgsStr+=QCString("/**")+&yytext[3]+" */";
954 }
955 else // add brief command explicitly when translating C++ to C comment style
956 {
957 if (yytext[3]=='<') // preserve < before @brief
958 {
959 yyextra->defArgsStr+=QCString("/**< @brief ")+&yytext[4]+" */";
960 }
961 else
962 {
963 yyextra->defArgsStr+=QCString("/** @brief ")+&yytext[3]+" */";
964 }
965 }
966 }
967<FindDefineArgs>{CPPC}.*\n { // replace C++ single line style comment by C style comment
968 if (getLanguageFromFileName(yyextra->fileName)==SrcLangExt::Fortran) REJECT;
969 yyextra->defArgsStr+=QCString("/*")+&yytext[2]+" */";
970 }
971<FindDefineArgs>\" {
972 yyextra->defArgsStr+=*yytext;
973 BEGIN(ReadString);
974 }
975<FindDefineArgs>' {
976 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Fortran) REJECT;
977 yyextra->defArgsStr+=*yytext;
978 BEGIN(ReadString);
979 }
980<FindDefineArgs>\n {
981 yyextra->defArgsStr+=' ';
982 yyextra->yyLineNr++;
983 outputChar(yyscanner,'\n');
984 }
985<FindDefineArgs>"@" {
986 yyextra->defArgsStr+="@@";
987 }
988<FindDefineArgs>. {
989 yyextra->defArgsStr+=*yytext;
990 }
991<ArgCopyCComment>[^*\n]+ {
992 yyextra->defArgsStr+=yytext;
993 }
994<ArgCopyCComment>{CCE} {
995 yyextra->defArgsStr+=yytext;
996 BEGIN(FindDefineArgs);
997 }
998<ArgCopyCComment>\n {
999 yyextra->defArgsStr+=yytext;
1000 yyextra->yyLineNr++;
1001 }
1002<ArgCopyCComment>. {
1003 yyextra->defArgsStr+=yytext;
1004 }
1005<ArgCopyCppComment>^{B}*
1006<ArgCopyCppComment>{CPPC}[/!].*\n/{B}*{CPPC}[/!] { // replace multi line C++ style comment by C style comment
1007 const char *startContent = &yytext[3];
1008 if (startContent[0]=='<') startContent++;
1009 yyextra->defArgsStr+=startContent;
1010 }
1011<ArgCopyCppComment>{CPPC}[/!].*\n { // replace C++ multie line style comment by C style comment
1012 const char *startContent = &yytext[3];
1013 if (startContent[0]=='<') startContent++;
1014 yyextra->defArgsStr+=QCString(startContent)+" */";
1015 BEGIN(FindDefineArgs);
1016 }
1017<ArgCopyCppComment>. { // unexpected character
1018 unput(*yytext);
1019 yyextra->defArgsStr+=" */";
1020 BEGIN(FindDefineArgs);
1021 }
1022<ReadString>"\"" {
1023 yyextra->defArgsStr+=*yytext;
1024 BEGIN(FindDefineArgs);
1025 }
1026<ReadString>"'" {
1027 if (getLanguageFromFileName(yyextra->fileName)!=SrcLangExt::Fortran) REJECT;
1028 yyextra->defArgsStr+=*yytext;
1029 BEGIN(FindDefineArgs);
1030 }
1031
1032<ReadString>{CPPC}|{CCS} {
1033 yyextra->defArgsStr+=yytext;
1034 }
1035<ReadString>\\/\r?\n { // line continuation
1036 }
1037<ReadString>\\. {
1038 yyextra->defArgsStr+=yytext;
1039 }
1040<ReadString>. {
1041 yyextra->defArgsStr+=*yytext;
1042 }
1043<Command>("include"|"import"){B}+/{ID} {
1044 yyextra->isImported = yytext[1]=='m';
1045 if (yyextra->macroExpansion)
1046 BEGIN(IncludeID);
1047 }
1048<Command>("include"|"import"){B}*[<"] {
1049 yyextra->isImported = yytext[1]=='m';
1050 char c[2];
1051 c[0]=yytext[yyleng-1];c[1]='\0';
1052 yyextra->incName=c;
1053 BEGIN(Include);
1054 }
1055<Command>("cmake")?"define"{B}+ {
1056 yyextra->potentialDefine += substitute(yytext,"cmake"," ");
1057 //printf("!!!DefName\n");
1058 yyextra->yyColNr+=(int)yyleng;
1059 BEGIN(DefName);
1060 }
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:571
1061<Command>"cmakedefine01"{B}+ {
1062 yyextra->potentialDefine += substitute(yytext,"cmakedefine01"," define ");
1063 //printf("!!!DefName\n");
1064 yyextra->yyColNr+=(int)yyleng;
1065 BEGIN(CmakeDefName01);
1066 }
1067<Command>"ifdef"/{B}*"(" {
1068 incrLevel(yyscanner);
1069 yyextra->guardExpr.clear();
1070 BEGIN(DefinedExpr2);
1071 }
static void incrLevel(yyscan_t yyscanner)
Definition pre.l:2280
1072<Command>"ifdef"/{B}+ {
1073 //printf("Pre.l: ifdef\n");
1074 incrLevel(yyscanner);
1075 yyextra->guardExpr.clear();
1076 BEGIN(DefinedExpr1);
1077 }
1078<Command>"ifndef"/{B}*"(" {
1079 incrLevel(yyscanner);
1080 yyextra->guardExpr="! ";
1081 BEGIN(DefinedExpr2);
1082 }
1083<Command>"ifndef"/{B}+ {
1084 incrLevel(yyscanner);
1085 yyextra->guardExpr="! ";
1086 BEGIN(DefinedExpr1);
1087 }
1088<Command>"if"/[ \t(!] {
1089 incrLevel(yyscanner);
1090 yyextra->guardExpr.clear();
1091 BEGIN(Guard);
1092 }
1093<Command>("elif"|"else"{B}*"if")/[ \t(!] {
1094 if (!otherCaseDone(yyscanner))
1095 {
1096 yyextra->guardExpr.clear();
1097 BEGIN(Guard);
1098 }
1099 else
1100 {
1101 yyextra->ifcount=0;
1102 BEGIN(SkipCPPBlock);
1103 }
1104 }
static bool otherCaseDone(yyscan_t yyscanner)
Definition pre.l:2308
1105<Command>"else"/[^a-z_A-Z0-9\x80-\xFF] {
1106 if (otherCaseDone(yyscanner))
1107 {
1108 yyextra->ifcount=0;
1109 BEGIN(SkipCPPBlock);
1110 }
1111 else
1112 {
1113 setCaseDone(yyscanner,true);
1114 }
1115 }
static void setCaseDone(yyscan_t yyscanner, bool value)
Definition pre.l:2322
1116<Command>"undef"{B}+ {
1117 BEGIN(UndefName);
1118 }
1119<Command>("elif"|"else"{B}*"if")/[ \t(!] {
1120 if (!otherCaseDone(yyscanner))
1121 {
1122 yyextra->guardExpr.clear();
1123 BEGIN(Guard);
1124 }
1125 }
1126<Command>"endif"/[^a-z_A-Z0-9\x80-\xFF] {
1127 //printf("Pre.l: #endif\n");
1128 decrLevel(yyscanner);
1129 }
static void decrLevel(yyscan_t yyscanner)
Definition pre.l:2287
1130<Command,IgnoreLine>\n {
1131 outputChar(yyscanner,'\n');
1132 BEGIN(Start);
1133 yyextra->yyLineNr++;
1134 }
1135<Command>"pragma"{B}+"once" {
1136 yyextra->expectGuard = false;
1137 if (yyextra->pragmaSet.find(yyextra->fileName.str())!=yyextra->pragmaSet.end())
1138 {
1139 outputChar(yyscanner,'\n');
1140 BEGIN(PragmaOnce);
1141 }
1142 else
1143 {
1144 yyextra->pragmaSet.insert(yyextra->fileName.data());
1145 }
1146 }
1147<PragmaOnce>. {}
1148<PragmaOnce>\n {}
1149<PragmaOnce><<EOF>> {
1150 yyextra->expectGuard = false;
1151 BEGIN(Start);
1152 }
1153<Command>{ID} { // unknown directive
1154 BEGIN(IgnoreLine);
1155 }
1156<IgnoreLine>\\‍[\r]?\n {
1157 outputChar(yyscanner,'\n');
1158 yyextra->yyLineNr++;
1159 }
1160<IgnoreLine>.
1161<Command>. { yyextra->potentialDefine += yytext[0]=='\t' ? '\t' : ' ';
1162 yyextra->yyColNr+=(int)yyleng;
1163 }
1164<UndefName>{ID} {
1165 Define *def;
1166 if ((def=isDefined(yyscanner,yytext))
1167 /*&& !def->isPredefined*/
1168 && !def->nonRecursive
1169 )
1170 {
1171 //printf("undefining %s\n",yytext);
1172 def->undef=true;
1173 }
1174 BEGIN(Start);
1175 }
1176<Guard>\\‍[\r]?\n {
1177 outputChar(yyscanner,'\n');
1178 yyextra->guardExpr+=' ';
1179 yyextra->yyLineNr++;
1180 }
1181<Guard>"defined"/{B}*"(" {
1182 BEGIN(DefinedExpr2);
1183 }
1184<Guard>"defined"/{B}+ {
1185 BEGIN(DefinedExpr1);
1186 }
1187<Guard>"true"/{B}|{B}*[\r]?\n { yyextra->guardExpr+="1L"; }
1188<Guard>"false"/{B}|{B}*[\r]?\n { yyextra->guardExpr+="0L"; }
1189<Guard>"not"/{B} { yyextra->guardExpr+='!'; }
1190<Guard>"not_eq"/{B} { yyextra->guardExpr+="!="; }
1191<Guard>"and"/{B} { yyextra->guardExpr+="&&"; }
1192<Guard>"or"/{B} { yyextra->guardExpr+="||"; }
1193<Guard>"bitand"/{B} { yyextra->guardExpr+="&"; }
1194<Guard>"bitor"/{B} { yyextra->guardExpr+="|"; }
1195<Guard>"xor"/{B} { yyextra->guardExpr+="^"; }
1196<Guard>"compl"/{B} { yyextra->guardExpr+="~"; }
1197<Guard>{ID} { yyextra->guardExpr+=yytext; }
1198<Guard>"@" { yyextra->guardExpr+="@@"; }
1199<Guard>. { yyextra->guardExpr+=*yytext; }
1200<Guard>\n {
1201 unput(*yytext);
1202 //printf("Guard: '%s'\n",
1203 // qPrint(yyextra->guardExpr));
1204 bool guard=computeExpression(yyscanner,yyextra->guardExpr);
1205 setCaseDone(yyscanner,guard);
1206 if (guard)
1207 {
1208 BEGIN(Start);
1209 }
1210 else
1211 {
1212 yyextra->ifcount=0;
1213 BEGIN(SkipCPPBlock);
1214 }
1215 }
static bool computeExpression(yyscan_t yyscanner, const QCString &expr)
Definition pre.l:3569
1216<DefinedExpr1,DefinedExpr2>\\\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1217<DefinedExpr1>{ID} {
1218 if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
1219 yyextra->guardExpr+=" 1L ";
1220 else
1221 yyextra->guardExpr+=" 0L ";
1222 yyextra->lastGuardName=yytext;
1223 BEGIN(Guard);
1224 }
1225<DefinedExpr2>{ID} {
1226 if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext)
1227 yyextra->guardExpr+=" 1L ";
1228 else
1229 yyextra->guardExpr+=" 0L ";
1230 yyextra->lastGuardName=yytext;
1231 }
1232<DefinedExpr1,DefinedExpr2>\n { // should not happen, handle anyway
1233 yyextra->yyLineNr++;
1234 yyextra->ifcount=0;
1235 BEGIN(SkipCPPBlock);
1236 }
1237<DefinedExpr2>")" {
1238 BEGIN(Guard);
1239 }
1240<DefinedExpr1,DefinedExpr2>.
1241<SkipCPPBlock>^{B}*"#" { BEGIN(SkipCommand); }
1242<SkipCPPBlock>^{Bopt}/[^#] { BEGIN(SkipLine); }
1243<SkipCPPBlock>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1244<SkipCPPBlock>.
1245<SkipCommand>"if"(("n")?("def"))?/[ \t(!] {
1246 incrLevel(yyscanner);
1247 yyextra->ifcount++;
1248 //printf("#if... depth=%d\n",yyextra->ifcount);
1249 }
1250<SkipCommand>"else" {
1251 //printf("Else! yyextra->ifcount=%d otherCaseDone=%d\n",yyextra->ifcount,otherCaseDone());
1252 if (yyextra->ifcount==0 && !otherCaseDone(yyscanner))
1253 {
1254 setCaseDone(yyscanner,true);
1255 //outputChar(yyscanner,'\n');
1256 BEGIN(Start);
1257 }
1258 }
1259<SkipCommand>("elif"|"else"{B}*"if")/[ \t(!] {
1260 if (yyextra->ifcount==0)
1261 {
1262 if (!otherCaseDone(yyscanner))
1263 {
1264 yyextra->guardExpr.clear();
1265 yyextra->lastGuardName.clear();
1266 BEGIN(Guard);
1267 }
1268 else
1269 {
1270 BEGIN(SkipCPPBlock);
1271 }
1272 }
1273 }
1274<SkipCommand>"endif" {
1275 yyextra->expectGuard = false;
1276 decrLevel(yyscanner);
1277 if (--yyextra->ifcount<0)
1278 {
1279 //outputChar(yyscanner,'\n');
1280 BEGIN(Start);
1281 }
1282 }
1283<SkipCommand>\n {
1284 outputChar(yyscanner,'\n');
1285 yyextra->yyLineNr++;
1286 BEGIN(SkipCPPBlock);
1287 }
1288<SkipCommand>{ID} { // unknown directive
1289 BEGIN(SkipLine);
1290 }
1291<SkipCommand>.
1292<SkipLine>[^'"/\n]+
1293<SkipLine>{CHARLIT} { }
1294<SkipLine>\" {
1295 BEGIN(SkipString);
1296 }
1297<SkipLine>.
1298<SkipString>{CPPC}/[^\n]* {
1299 }
1300<SkipLine,SkipCommand,SkipCPPBlock>{CPPC}[^\n]* {
1301 yyextra->lastCPPContext=YY_START;
1302 BEGIN(RemoveCPPComment);
1303 }
1304<SkipString>{CCS}/[^\n]* {
1305 }
1306<SkipLine,SkipCommand,SkipCPPBlock>{CCS}/[^\n]* {
1307 yyextra->lastCContext=YY_START;
1308 BEGIN(RemoveCComment);
1309 }
1310<SkipLine>\n {
1311 outputChar(yyscanner,'\n');
1312 yyextra->yyLineNr++;
1313 BEGIN(SkipCPPBlock);
1314 }
1315<SkipString>[^"\\\n]+ { }
1316<SkipString>\\. { }
1317<SkipString>\" {
1318 BEGIN(SkipLine);
1319 }
1320<SkipString>. { }
1321<IncludeID>{ID}{Bopt}/"(" {
1322 yyextra->nospaces=true;
1323 yyextra->roundCount=0;
1324 yyextra->defArgsStr=yytext;
1325 yyextra->findDefArgContext = IncludeID;
1326 BEGIN(FindDefineArgs);
1327 }
1328<IncludeID>{ID} {
1329 yyextra->nospaces=true;
1330 readIncludeFile(yyscanner,expandMacro(yyscanner,yytext));
1331 BEGIN(Start);
1332 }
1333<Include>[^\">\n]+[\">] {
1334 yyextra->incName+=yytext;
1335 if (yyextra->isImported)
1336 {
1337 BEGIN(EndImport);
1338 }
1339 else
1340 {
1341 readIncludeFile(yyscanner,yyextra->incName);
1342 BEGIN(Start);
1343 }
1344 }
1345<EndImport>{ENDIMPORTopt}/\n {
1346 readIncludeFile(yyscanner,yyextra->incName);
1347 BEGIN(Start);
1348 }
1349<EndImport>\\‍[\r]?"\n" {
1350 outputChar(yyscanner,'\n');
1351 yyextra->yyLineNr++;
1352 }
1353<EndImport>. {
1354 }
1355<DefName>{ID}/("\\\n")*"(" { // define with argument
1356 //printf("Define() '%s'\n",yytext);
1357 yyextra->argMap.clear();
1358 yyextra->defArgs = 0;
1359 yyextra->defArgsStr.clear();
1360 yyextra->defText.clear();
1361 yyextra->defLitText.clear();
1362 yyextra->defName = yytext;
1363 yyextra->defVarArgs = false;
1364 yyextra->defExtraSpacing.clear();
1365 yyextra->defContinue = false;
1366 BEGIN(DefineArg);
1367 }
1368<DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
1369 //printf("Define '%s'\n",yytext);
1370 yyextra->argMap.clear();
1371 yyextra->defArgs = -1;
1372 yyextra->defArgsStr.clear();
1373 yyextra->defName = QCString(yytext).left(yyleng-1).stripWhiteSpace();
1374 yyextra->defVarArgs = false;
1375 //printf("Guard check: %s!=%s || %d\n",
1376 // qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1377 if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1378 { // define may appear in the output
1379 QCString def = yyextra->potentialDefine +
1380 yyextra->defName ;
1381 outputString(yyscanner,def);
1382 outputSpaces(yyscanner,yytext+yyextra->defName.length());
1383 yyextra->quoteArg=false;
1384 yyextra->insideComment=false;
1385 yyextra->lastGuardName.clear();
1386 yyextra->defText="1";
1387 yyextra->defLitText="1";
1388 BEGIN(DefineText);
1389 }
1390 else // define is a guard => hide
1391 {
1392 //printf("Found a guard %s\n",yytext);
1393 yyextra->defText.clear();
1394 yyextra->defLitText.clear();
1395 BEGIN(Start);
1396 }
1397 yyextra->expectGuard=false;
1398 }
static void outputSpaces(yyscan_t yyscanner, char *s)
Definition pre.l:3728
1399<DefName,CmakeDefName01>{ID}/{B}*"\n" { // empty define
1400 yyextra->argMap.clear();
1401 yyextra->defArgs = -1;
1402 yyextra->defName = yytext;
1403 yyextra->defArgsStr.clear();
1404 yyextra->defText.clear();
1405 yyextra->defLitText.clear();
1406 yyextra->defVarArgs = false;
1407 //printf("Guard check: %s!=%s || %d\n",
1408 // qPrint(yyextra->defName),qPrint(yyextra->lastGuardName),yyextra->expectGuard);
1409 if (yyextra->curlyCount>0 || yyextra->defName!=yyextra->lastGuardName || !yyextra->expectGuard)
1410 { // define may appear in the output
1411 QCString def = yyextra->potentialDefine + yyextra->defName;
1412 outputString(yyscanner,def);
1413 yyextra->quoteArg=false;
1414 yyextra->insideComment=false;
1415 if (YY_START == CmakeDefName01) yyextra->defText = "0";
1416 else if (yyextra->insideCS) yyextra->defText="1"; // for C#, use "1" as define text
1417 BEGIN(DefineText);
1418 }
1419 else // define is a guard => hide
1420 {
1421 //printf("Found a guard %s\n",yytext);
1422 yyextra->guardName = yytext;
1423 yyextra->lastGuardName.clear();
1424 BEGIN(Start);
1425 }
1426 yyextra->expectGuard=false;
1427 }
1428<DefName>{ID}/{B}* { // define with content
1429 //printf("Define '%s'\n",yytext);
1430 yyextra->argMap.clear();
1431 yyextra->defArgs = -1;
1432 yyextra->defArgsStr.clear();
1433 yyextra->defText.clear();
1434 yyextra->defLitText.clear();
1435 yyextra->defName = yytext;
1436 yyextra->defVarArgs = false;
1437 QCString def = yyextra->potentialDefine +
1438 yyextra->defName +
1439 yyextra->defArgsStr ;
1440 outputString(yyscanner,def);
1441 yyextra->quoteArg=false;
1442 yyextra->insideComment=false;
1443 BEGIN(DefineText);
1444 }
1445<DefineArg>"\\\n" {
1446 yyextra->defExtraSpacing+="\n";
1447 yyextra->defContinue = true;
1448 yyextra->yyLineNr++;
1449 }
1450<DefineArg>{B}* { yyextra->defExtraSpacing+=yytext; }
1451<DefineArg>","{B}* { yyextra->defArgsStr+=yytext; }
1452<DefineArg>"("{B}* { yyextra->defArgsStr+=yytext; }
1453<DefineArg>{B}*")"{B}* {
1454 extraSpacing(yyscanner);
1455 yyextra->defArgsStr+=yytext;
1456 QCString def = yyextra->potentialDefine +
1457 yyextra->defName +
1458 yyextra->defArgsStr +
1459 yyextra->defExtraSpacing ;
1460 outputString(yyscanner,def);
1461 yyextra->quoteArg=false;
1462 yyextra->insideComment=false;
1463 BEGIN(DefineText);
1464 }
static void extraSpacing(yyscan_t yyscanner)
Definition pre.l:3739
1465<DefineArg>"..." { // Variadic macro
1466 yyextra->defVarArgs = true;
1467 yyextra->defArgsStr+=yytext;
1468 yyextra->argMap.emplace(std::string("__VA_ARGS__"),yyextra->defArgs);
1469 yyextra->defArgs++;
1470 }
1471<DefineArg>{ID}{B}*("..."?) {
1472 //printf("Define addArg(%s)\n",yytext);
1473 QCString argName=yytext;
1474 yyextra->defVarArgs = yytext[yyleng-1]=='.';
1475 if (yyextra->defVarArgs) // strip ellipsis
1476 {
1477 argName=argName.left(argName.length()-3);
1478 }
1479 argName = argName.stripWhiteSpace();
1480 yyextra->defArgsStr+=yytext;
1481 yyextra->argMap.emplace(toStdString(argName),yyextra->defArgs);
1482 yyextra->defArgs++;
1483 extraSpacing(yyscanner);
1484 }
1485 /*
1486<DefineText>"/ **"|"/ *!" {
1487 yyextra->defText+=yytext;
1488 yyextra->defLitText+=yytext;
1489 yyextra->insideComment=true;
1490 }
1491<DefineText>"* /" {
1492 yyextra->defText+=yytext;
1493 yyextra->defLitText+=yytext;
1494 yyextra->insideComment=false;
1495 }
1496 */
1497<DefineText>{CCS}[^!*] {
1498 yyextra->defLitText+=' ';
1499 outputArray(yyscanner,yytext,yyleng);
1500 yyextra->lastCContext=YY_START;
1501 yyextra->commentCount=1;
1502 BEGIN(SkipCComment);
1503 }
1504<DefineText>{CCS}[!*] {
1505 yyextra->defText+=yytext;
1506 yyextra->defLitText+=yytext;
1507 yyextra->lastCContext=YY_START;
1508 yyextra->commentCount=1;
1509 BEGIN(CopyCComment);
1510 }
1511<DefineText>{CPPC}[!/]? {
1512 outputArray(yyscanner,yytext,yyleng);
1513 yyextra->lastCPPContext=YY_START;
1514 yyextra->defLitText+=' ';
1515 BEGIN(SkipCPPComment);
1516 }
1517<SkipCComment>[/]?{CCE} {
1518 if (yytext[0]=='/') outputChar(yyscanner,'/');
1519 outputChar(yyscanner,'*');outputChar(yyscanner,'/');
1520 if (--yyextra->commentCount<=0)
1521 {
1522 if (yyextra->lastCContext==Start)
1523 // small hack to make sure that ^... rule will
1524 // match when going to Start... Example: "/*...*/ some stuff..."
1525 {
1526 YY_CURRENT_BUFFER->yy_at_bol=1;
1527 }
1528 BEGIN(yyextra->lastCContext);
1529 }
1530 }
1531<SkipCComment>{CPPC}("/")* {
1532 outputArray(yyscanner,yytext,yyleng);
1533 }
1534<SkipCComment>{CCS} {
1535 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1536 //yyextra->commentCount++;
1537 }
1538<SkipCond>{CMD}{CMD} { }
1539<SkipCond>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1540 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1541 if (!markdownSupport || !yyextra->isSpecialComment)
1542 {
1543 REJECT;
1544 }
1545 else
1546 {
1547 yyextra->fenceChar='~';
1548 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1549 BEGIN(SkipCondVerbatim);
1550 }
1551 }
static yy_size_t getFenceSize(char *txt, yy_size_t leng)
Definition pre.l:2248
1552<SkipCond>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1553 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1554 if (!markdownSupport || !yyextra->isSpecialComment)
1555 {
1556 REJECT;
1557 }
1558 else
1559 {
1560 yyextra->fenceChar='`';
1561 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1562 BEGIN(SkipCondVerbatim);
1563 }
1564 }
1565<SkipCComment>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1566 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1567 if (!markdownSupport || !yyextra->isSpecialComment)
1568 {
1569 REJECT;
1570 }
1571 else
1572 {
1573 outputArray(yyscanner,yytext,yyleng);
1574 yyextra->fenceChar='~';
1575 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1576 BEGIN(SkipVerbatim);
1577 }
1578 }
1579<SkipCComment>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1580 bool markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
1581 if (!markdownSupport || !yyextra->isSpecialComment)
1582 {
1583 REJECT;
1584 }
1585 else
1586 {
1587 outputArray(yyscanner,yytext,yyleng);
1588 yyextra->fenceChar='`';
1589 yyextra->fenceSize=(int)getFenceSize(yytext,yyleng);
1590 BEGIN(SkipVerbatim);
1591 }
1592 }
1593<SkipCComment>{CMD}{VERBATIM_LINE} |
1594<SkipCComment>{CMD}{LITERAL_BLOCK} { // escaped command
1595 outputArray(yyscanner,yytext,yyleng);
1596 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1597 }
1598<SkipCComment>{VERBATIM_LINE}.*/\n { // normal command
1599 outputArray(yyscanner,yytext,yyleng);
1600 }
1601<SkipCComment>{LITERAL_BLOCK} { // normal block command
1602 outputArray(yyscanner,yytext,yyleng);
1603 yyextra->yyLineNr+=QCString(yytext).contains('\n');
1604 if (yyextra->isSpecialComment)
1605 {
1606 determineBlockName(yyscanner);
1607 BEGIN(SkipVerbatim);
1608 }
1609 }
static void determineBlockName(yyscan_t yyscanner)
Definition pre.l:3752
1610<SkipCond>{CMD}{CMD}"cond"[ \t]+ {}// escaped cond command
1611<SkipCond>{CMD}"cond"/\n |
1612<SkipCond>{CMD}"cond"[ \t]+ { // cond command in a skipped cond section, this section has to be skipped as well
1613 // but has to be recorded to match the endcond command
1614 startCondSection(yyscanner," ");
1615 }
static void startCondSection(yyscan_t yyscanner, const QCString &sectId)
Definition pre.l:3940
1616<SkipCComment>"{"[ \t]*"@code"/[ \t\n] {
1617 outputArray(yyscanner,"@iliteral{code}",15);
1618 yyextra->javaBlock=1;
1619 BEGIN(JavaDocVerbatimCode);
1620 }
1621<SkipCComment>"{"[ \t]*"@literal"/[ \t\n] {
1622 outputArray(yyscanner,"@iliteral",9);
1623 yyextra->javaBlock=1;
1624 BEGIN(JavaDocVerbatimCode);
1625 }
1626<SkipCComment,SkipCPPComment>{CMD}{CMD}"cond"[ \t\n]+ { // escaped cond command
1627 outputArray(yyscanner,yytext,yyleng);
1628 }
1629<SkipCPPComment>{CMD}"cond"[ \t]+ { // conditional section
1630 yyextra->ccomment=true;
1631 yyextra->condCtx=YY_START;
1632 BEGIN(CondLineCpp);
1633 }
1634<SkipCComment>{CMD}"cond"[ \t]+ { // conditional section
1635 yyextra->ccomment=false;
1636 yyextra->condCtx=YY_START;
1637 BEGIN(CondLineC);
1638 }
1639<CondLineC,CondLineCpp>[!()&| \ta-z_A-Z0-9\x80-\xFF.\-]+ {
1640 startCondSection(yyscanner,yytext);
1641 if (yyextra->skip)
1642 {
1643 if (YY_START==CondLineC)
1644 {
1645 // end C comment
1646 outputArray(yyscanner,"*/",2);
1647 yyextra->ccomment=true;
1648 }
1649 else
1650 {
1651 yyextra->ccomment=false;
1652 }
1653 BEGIN(SkipCond);
1654 }
1655 else
1656 {
1657 BEGIN(yyextra->condCtx);
1658 }
1659 }
1660<CondLineC,CondLineCpp>. { // non-guard character
1661 unput(*yytext);
1662 startCondSection(yyscanner," ");
1663 if (yyextra->skip)
1664 {
1665 if (YY_START==CondLineC)
1666 {
1667 // end C comment
1668 outputArray(yyscanner,"*/",2);
1669 yyextra->ccomment=true;
1670 }
1671 else
1672 {
1673 yyextra->ccomment=false;
1674 }
1675 BEGIN(SkipCond);
1676 }
1677 else
1678 {
1679 BEGIN(yyextra->condCtx);
1680 }
1681 }
1682<SkipCComment,SkipCPPComment>{CMD}"cond"{WSopt}/\n { // no guard
1683 if (YY_START==SkipCComment)
1684 {
1685 yyextra->ccomment=true;
1686 // end C comment
1687 outputArray(yyscanner,"*/",2);
1688 }
1689 else
1690 {
1691 yyextra->ccomment=false;
1692 }
1693 yyextra->condCtx=YY_START;
1694 yyextra->condGuardCount=0;
1695 startCondSection(yyscanner," ");
1696 BEGIN(SkipCond);
1697 }
1698<SkipCond>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1699<SkipCond>{VERBATIM_LINE}.*/\n { }
1700<SkipCond>{LITERAL_BLOCK} {
1701 auto numNLs = QCString(yytext).contains('\n');
1702 yyextra->yyLineNr+=numNLs;
1703 for (int i = 0; i < numNLs; i++) outputChar(yyscanner,'\n');
1704 determineBlockName(yyscanner);
1705 BEGIN(SkipCondVerbatim);
1706 }
1707
1708<SkipCond>. { }
1709<SkipCond>"#if"("def")? { yyextra->condGuardCount++; }
1710<SkipCond>"#endif" { yyextra->condGuardCount--; }
1711<SkipCond>[^\/\!*\\@\n#]+ { }
1712<SkipCond>{CPPC}[/!] { yyextra->ccomment=false; }
1713<SkipCond>{CCS}[*!] { yyextra->ccomment=true; }
1714<SkipCond,SkipCComment,SkipCPPComment>{CMD}{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1715 if (!yyextra->skip)
1716 {
1717 outputArray(yyscanner,yytext,yyleng);
1718 }
1719 }
1720<SkipCond>{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1721 bool oldSkip = yyextra->skip;
1722 endCondSection(yyscanner);
1723 if (oldSkip && !yyextra->skip)
1724 {
1725 if (yyextra->ccomment)
1726 {
1727 outputArray(yyscanner,"/** ",4); // */
1728 }
1729 BEGIN(yyextra->condCtx);
1730 }
1731 }
static void endCondSection(yyscan_t yyscanner)
Definition pre.l:3954
1732<SkipCComment,SkipCPPComment>{CMD}"endcond"/[^a-z_A-Z0-9\x80-\xFF] {
1733 bool oldSkip = yyextra->skip;
1734 endCondSection(yyscanner);
1735 if (oldSkip && !yyextra->skip)
1736 {
1737 BEGIN(yyextra->condCtx);
1738 }
1739 }
1740<SkipCondVerbatim>{LITERAL_BLOCK_END} { /* end of verbatim block */
1741 if (yytext[1]=='f' && yyextra->blockName==&yytext[2])
1742 {
1743 BEGIN(SkipCond);
1744 }
1745 else if (&yytext[4]==yyextra->blockName)
1746 {
1747 BEGIN(SkipCond);
1748 }
1749 }
1750<SkipVerbatim>{LITERAL_BLOCK_END} { /* end of verbatim block */
1751 outputArray(yyscanner,yytext,yyleng);
1752 if (yytext[1]=='f' && yyextra->blockName==&yytext[2])
1753 {
1754 BEGIN(SkipCComment);
1755 }
1756 else if (&yytext[4]==yyextra->blockName)
1757 {
1758 BEGIN(SkipCComment);
1759 }
1760 }
1761<SkipCondVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1762 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='~')
1763 {
1764 BEGIN(SkipCond);
1765 }
1766 }
1767<SkipCondVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1768 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='`')
1769 {
1770 BEGIN(SkipCond);
1771 }
1772 }
1773<SkipVerbatim>^({B}*"*"+)?{B}{0,3}"~~~"[~]* {
1774 outputArray(yyscanner,yytext,yyleng);
1775 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='~')
1776 {
1777 BEGIN(SkipCComment);
1778 }
1779 }
1780<SkipVerbatim>^({B}*"*"+)?{B}{0,3}"```"[`]* {
1781 outputArray(yyscanner,yytext,yyleng);
1782 if (yyextra->fenceSize==getFenceSize(yytext,yyleng) && yyextra->fenceChar=='`')
1783 {
1784 BEGIN(SkipCComment);
1785 }
1786 }
1787<SkipCondVerbatim>{CCE}|{CCS} { }
1788<SkipVerbatim>{CCE}|{CCS} {
1789 outputArray(yyscanner,yytext,yyleng);
1790 }
1791<JavaDocVerbatimCode>"{" {
1792 if (yyextra->javaBlock==0)
1793 {
1794 REJECT;
1795 }
1796 else
1797 {
1798 yyextra->javaBlock++;
1799 outputArray(yyscanner,yytext,(int)yyleng);
1800 }
1801 }
1802<JavaDocVerbatimCode>"}" {
1803 if (yyextra->javaBlock==0)
1804 {
1805 REJECT;
1806 }
1807 else
1808 {
1809 yyextra->javaBlock--;
1810 if (yyextra->javaBlock==0)
1811 {
1812 outputArray(yyscanner," @endiliteral ",14);
1813 BEGIN(SkipCComment);
1814 }
1815 else
1816 {
1817 outputArray(yyscanner,yytext,(int)yyleng);
1818 }
1819 }
1820 }
1821<JavaDocVerbatimCode>\n { /* new line in verbatim block */
1822 outputArray(yyscanner,yytext,(int)yyleng);
1823 }
1824<JavaDocVerbatimCode>. { /* any other character */
1825 outputArray(yyscanner,yytext,(int)yyleng);
1826 }
1827<SkipCondVerbatim>[^{*\\@\x06~`\n\/]+ { }
1828<SkipCComment,SkipVerbatim>[^{*\\@\x06~`\n\/]+ {
1829 outputArray(yyscanner,yytext,yyleng);
1830 }
1831<SkipCComment,SkipVerbatim,SkipCondVerbatim>\n {
1832 yyextra->yyLineNr++;
1833 outputChar(yyscanner,'\n');
1834 }
1835<SkipCondVerbatim>. { }
1836<SkipCComment,SkipVerbatim>. {
1837 outputChar(yyscanner,*yytext);
1838 }
1839<CopyCComment>[^*a-z_A-Z\x80-\xFF\n]*[^*a-z_A-Z\x80-\xFF\\\n] {
1840 yyextra->defLitText+=yytext;
1841 yyextra->defText+=escapeAt(yytext);
1842 }
static QCString escapeAt(const QCString &text)
Definition pre.l:3997
1843<CopyCComment>\\‍[\r]?\n {
1844 yyextra->defLitText+=yytext;
1845 yyextra->defText+=" ";
1846 yyextra->yyLineNr++;
1847 yyextra->yyMLines++;
1848 }
1849<CopyCComment>{CCE} {
1850 yyextra->defLitText+=yytext;
1851 yyextra->defText+=yytext;
1852 BEGIN(yyextra->lastCContext);
1853 }
1854<CopyCComment>\n {
1855 yyextra->yyLineNr++;
1856 yyextra->defLitText+=yytext;
1857 yyextra->defText+=' ';
1858 }
1859<RemoveCComment>{CCE}{B}*"#" { // see bug 594021 for a usecase for this rule
1860 if (yyextra->lastCContext==SkipCPPBlock)
1861 {
1862 BEGIN(SkipCommand);
1863 }
1864 else
1865 {
1866 REJECT;
1867 }
1868 }
1869<RemoveCComment>{CCE} { BEGIN(yyextra->lastCContext); }
1870<RemoveCComment>{CPPC}
1871<RemoveCComment>{CCS}
1872<RemoveCComment>[^*\x06\n]+
1873<RemoveCComment>\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); }
1874<RemoveCComment>.
1875<SkipCPPComment>[^\n\/\\@]+ {
1876 outputArray(yyscanner,yytext,yyleng);
1877 }
1878<SkipCPPComment,RemoveCPPComment>\n {
1879 unput(*yytext);
1880 BEGIN(yyextra->lastCPPContext);
1881 }
1882<SkipCPPComment>{CCS} {
1883 outputChar(yyscanner,'/');outputChar(yyscanner,'*');
1884 }
1885<SkipCPPComment>{CPPC} {
1886 outputChar(yyscanner,'/');outputChar(yyscanner,'/');
1887 }
1888<SkipCPPComment>[^\x06\@\\\n]+ {
1889 outputArray(yyscanner,yytext,yyleng);
1890 }
1891<SkipCPPComment>. {
1892 outputChar(yyscanner,*yytext);
1893 }
1894<RemoveCPPComment>{CCS}
1895<RemoveCPPComment>{CPPC}
1896<RemoveCPPComment>[^\x06\n]+
1897<RemoveCPPComment>.
1898<DefineText>"__VA_OPT__("{B}*"##" {
1899 warn(yyextra->fileName,yyextra->yyLineNr,
1900 "'##' may not appear at the beginning of a __VA_OPT__()",
1901 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1902 yyextra->defText+="__VA_OPT__(";
1903 yyextra->defLitText+="__VA_OPT__(";
1904 }
1905<DefineText>"#"/"__VA_OPT__" {
1906 yyextra->defText+=yytext;
1907 yyextra->defLitText+=yytext;
1908 }
1909<DefineText>"#"/{IDSTART} {
1910 outputChar(yyscanner,' ');
1911 yyextra->quoteArg=true;
1912 yyextra->idStart=true;
1913 yyextra->defLitText+=yytext;
1914 }
1915<DefineText,CopyCComment>{ID} {
1916 yyextra->defLitText+=yytext;
1917 if (YY_START == DefineText) outputSpaces(yyscanner,yytext);
1918 if (yyextra->quoteArg)
1919 {
1920 yyextra->defText+="\"";
1921 }
1922 if (yyextra->defArgs>0)
1923 {
1924 auto it = yyextra->argMap.find(yytext);
1925 if (it!=yyextra->argMap.end())
1926 {
1927 int n = it->second;
1928 yyextra->defText+='@';
1929 yyextra->defText+=QCString().setNum(n);
1930 }
1931 else
1932 {
1933 if (yyextra->idStart)
1934 {
1935 warn(yyextra->fileName,yyextra->yyLineNr,
1936 "'#' is not followed by a macro parameter '{}': '{}'",
1937 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1938 }
1939 yyextra->defText+=yytext;
1940 }
1941 }
1942 else
1943 {
1944 yyextra->defText+=yytext;
1945 }
1946 if (yyextra->quoteArg)
1947 {
1948 yyextra->defText+="\"";
1949 }
1950 yyextra->quoteArg=false;
1951 yyextra->idStart=false;
1952 }
1953<CopyCComment>. {
1954 yyextra->defLitText+=yytext;
1955 yyextra->defText+=yytext;
1956 }
1957<DefineText>\\‍[\r]?\n {
1958 yyextra->defLitText+=yytext;
1959 outputChar(yyscanner,'\\');
1960 outputChar(yyscanner,'\n');
1961 yyextra->defText += ' ';
1962 yyextra->yyLineNr++;
1963 yyextra->yyMLines++;
1964 }
1965<DefineText>\n {
1966 QCString comment=extractTrailingComment(yyextra->defLitText);
1967 yyextra->defText = yyextra->defText.stripWhiteSpace();
1968 if (yyextra->defText.startsWith("##"))
1969 {
1970 warn(yyextra->fileName,yyextra->yyLineNr,
1971 "'##' cannot occur at the beginning of a macro definition '{}': '{}'",
1972 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1973 }
1974 else if (yyextra->defText.endsWith("##"))
1975 {
1976 warn(yyextra->fileName,yyextra->yyLineNr,
1977 "'##' cannot occur at the end of a macro definition '{}': '{}'",
1978 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1979 }
1980 else if (yyextra->defText.endsWith("#"))
1981 {
1982 warn(yyextra->fileName,yyextra->yyLineNr,
1983 "expected formal parameter after # in macro definition '{}': '{}'",
1984 yyextra->defName,yyextra->defLitText.stripWhiteSpace());
1985 }
1986 if (!comment.isEmpty())
1987 {
1988 outputString(yyscanner,comment);
1989 yyextra->defLitText=yyextra->defLitText.left(yyextra->defLitText.length()-comment.length()-1);
1990 }
1991 outputChar(yyscanner,'\n');
1992 yyextra->defLitText+=yytext;
1993 Define *def=nullptr;
1994 //printf("Define name='%s' text='%s' litTexti='%s'\n",qPrint(yyextra->defName),qPrint(yyextra->defText),qPrint(yyextra->defLitText));
1995 if (yyextra->includeStack.empty() || yyextra->curlyCount>0)
1996 {
1997 addMacroDefinition(yyscanner);
1998 }
1999 def=isDefined(yyscanner,yyextra->defName);
2000 if (def==0) // new define
2001 {
2002 //printf("new define '%s'!\n",qPrint(yyextra->defName));
2003 addDefine(yyscanner);
2004 }
2005 else if (def /*&& macroIsAccessible(def)*/)
2006 // name already exists
2007 {
2008 //printf("existing define!\n");
2009 //printf("define found\n");
2010 if (def->undef) // undefined name
2011 {
2012 def->undef = false;
2013 def->name = yyextra->defName;
2014 def->definition = yyextra->defText.stripWhiteSpace();
2015 def->nargs = yyextra->defArgs;
2016 def->fileName = yyextra->fileName;
2017 def->lineNr = yyextra->yyLineNr-yyextra->yyMLines;
2018 def->columnNr = yyextra->yyColNr;
2019 }
2020 else
2021 {
2022 if (def->fileName != yyextra->fileName && !yyextra->expandOnlyPredef) addDefine(yyscanner);
2023 //printf("error: define %s is defined more than once!\n",qPrint(yyextra->defName));
2024 }
2025 }
2026 yyextra->argMap.clear();
2027 yyextra->yyLineNr++;
2028 yyextra->yyColNr=1;
2029 yyextra->lastGuardName.clear();
2030 BEGIN(Start);
2031 }
static void addMacroDefinition(yyscan_t yyscanner)
Definition pre.l:3660
static void addDefine(yyscan_t yyscanner)
Definition pre.l:3631
static QCString extractTrailingComment(const QCString &s)
Definition pre.l:2460
2032<DefineText>{B}* { outputString(yyscanner,yytext);
2033 yyextra->defText += ' ';
2034 yyextra->defLitText+=yytext;
2035 }
2036<DefineText>{B}*"##"{B}* { outputString(yyscanner,substitute(yytext,"##"," "));
2037 yyextra->defText += "##";
2038 yyextra->defLitText+=yytext;
2039 }
2040<DefineText>"@" { outputString(yyscanner,substitute(yytext,"@@"," "));
2041 yyextra->defText += "@@";
2042 yyextra->defLitText+=yytext;
2043 }
2044<DefineText>\" {
2045 outputChar(yyscanner,' ');
2046 yyextra->defText += *yytext;
2047 yyextra->defLitText+=yytext;
2048 if (!yyextra->insideComment)
2049 {
2050 BEGIN(SkipDoubleQuote);
2051 }
2052 }
2053<DefineText>{NUMBER} {
2054 outputSpaces(yyscanner,yytext);
2055 yyextra->defText += yytext;
2056 yyextra->defLitText+=yytext;
2057 }
2058<DefineText>\' {
2059 outputChar(yyscanner,' ');
2060 yyextra->defText += *yytext;
2061 yyextra->defLitText+=yytext;
2062 if (!yyextra->insideComment)
2063 {
2064 BEGIN(SkipSingleQuote);
2065 }
2066 }
2067<SkipDoubleQuote>{CPPC}[/]? { outputSpaces(yyscanner,yytext);
2068 yyextra->defText += yytext;
2069 yyextra->defLitText+=yytext;
2070 }
2071<SkipDoubleQuote>{CCS}[*]? { outputSpaces(yyscanner,yytext);
2072 yyextra->defText += yytext;
2073 yyextra->defLitText+=yytext;
2074 }
2075<SkipDoubleQuote>\" {
2076 outputChar(yyscanner,' ');
2077 yyextra->defText += *yytext;
2078 yyextra->defLitText+=yytext;
2079 BEGIN(DefineText);
2080 }
2081<SkipSingleQuote,SkipDoubleQuote>\\. {
2082 outputSpaces(yyscanner,yytext);
2083 yyextra->defText += yytext;
2084 yyextra->defLitText+=yytext;
2085 }
2086<SkipSingleQuote>\' {
2087 outputChar(yyscanner,' ');
2088 yyextra->defText += *yytext;
2089 yyextra->defLitText+=yytext;
2090 BEGIN(DefineText);
2091 }
2092<SkipDoubleQuote,SkipSingleQuote>. { outputSpace(yyscanner,yytext[0]);
2093 yyextra->defText += *yytext;
2094 yyextra->defLitText += *yytext;
2095 }
2096<DefineText>. { outputSpace(yyscanner,yytext[0]);
2097 yyextra->defText += *yytext;
2098 yyextra->defLitText += *yytext;
2099 }
2100<<EOF>> {
2101 TRACE("End of include file");
2102 //printf("Include stack depth=%d\n",yyextra->includeStack.size());
2103 if (yyextra->includeStack.empty())
2104 {
2105 TRACE("Terminating scanner");
2106 yyterminate();
2107 }
2108 else
2109 {
2110 if (!yyextra->levelGuard.empty())
2111 {
2112 if (yyextra->condGuardErrorLine!=0)
2113 {
2114 warn(yyextra->condGuardErrorFileName,yyextra->condGuardErrorLine,"{}",yyextra->condGuardErrorMessage);
2115 }
2116 else
2117 {
2118 warn(yyextra->fileName,yyextra->yyLineNr,"More #endif's than #if's found.");
2119 }
2120 }
2121 QCString toFileName = yyextra->fileName;
2122 const std::unique_ptr<FileState> &fs=yyextra->includeStack.back();
2123 //fileDefineCache->merge(yyextra->fileName,fs->fileName);
2124 YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER;
2125 yy_switch_to_buffer( fs->bufState, yyscanner );
2126 yy_delete_buffer( oldBuf, yyscanner );
2127 yyextra->yyLineNr = fs->lineNr;
2128 //preYYin = fs->oldYYin;
2129 yyextra->inputBuf = fs->oldFileBuf;
2130 yyextra->inputBufPos = fs->oldFileBufPos;
2131 yyextra->curlyCount = fs->curlyCount;
2132 yyextra->levelGuard = fs->levelGuard;
2133 setFileName(yyscanner,fs->fileName);
2134 TRACE("switching to {}",yyextra->fileName);
#define yyterminate()
#define TRACE(...)
Definition trace.h:77
2135
2136 // Deal with file changes due to
2137 // #include's within { .. } blocks
2138 QCString lineStr(15+yyextra->fileName.length(), QCString::ExplicitSize);
2139 lineStr.sprintf("# %d \"%s\" 2",yyextra->yyLineNr,qPrint(yyextra->fileName));
2140 outputString(yyscanner,lineStr);
2141
2142 yyextra->includeStack.pop_back();
2143
2144 {
2145 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
2146 // to avoid deadlocks we allow multiple threads to process the same header file.
2147 // The first one to finish will store the results globally. After that the
2148 // next time the same file is encountered, the stored data is used and the file
2149 // is not processed again.
2150 if (!g_defineManager.alreadyProcessed(toFileName.str()))
2151 {
2152 // now that the file is completely processed, prevent it from processing it again
2153 g_defineManager.addInclude(yyextra->fileName.str(),toFileName.str());
2154 g_defineManager.store(toFileName.str(),yyextra->localDefines);
2155 }
2156 else
2157 {
2159 {
2160 Debug::print(Debug::Preprocessor,0,"#include {}: was already processed by another thread! not storing data...\n",toFileName);
2161 }
2162 }
2163 }
2164 // move the local macros definitions for in this file to the translation unit context
2165 for (const auto &kv : yyextra->localDefines)
2166 {
2167 auto pair = yyextra->contextDefines.insert(kv);
2168 if (!pair.second) // define already in context -> replace with local version
2169 {
2170 yyextra->contextDefines.erase(pair.first);
2171 yyextra->contextDefines.insert(kv);
2172 }
2173 }
2174 yyextra->localDefines.clear();
2175 }
2176 }
void store(const std::string &fileName, const DefineMap &fromMap)
Definition pre.l:184
2177<*>{CCS}/{CCE} |
2178<*>{CCS}[*!]? {
2179 if (YY_START==SkipVerbatim || YY_START == SkipCondVerbatim || YY_START==SkipCond || YY_START==IDLquote || YY_START == PragmaOnce)
2180 {
2181 REJECT;
2182 }
2183 else
2184 {
2185 outputArray(yyscanner,yytext,yyleng);
2186 yyextra->lastCContext=YY_START;
2187 yyextra->commentCount=1;
2188 if (yyleng==3)
2189 {
2190 yyextra->isSpecialComment = true;
2191 yyextra->lastGuardName.clear(); // reset guard in case the #define is documented!
2192 }
2193 else
2194 {
2195 yyextra->isSpecialComment = false;
2196 }
2197 BEGIN(SkipCComment);
2198 }
2199 }
2200<*>{CPPC}[/!]? {
2201 if (YY_START==SkipVerbatim || YY_START == SkipCondVerbatim || YY_START==SkipCond || getLanguageFromFileName(yyextra->fileName)==SrcLangExt::Fortran || YY_START==IDLquote || YY_START == PragmaOnce)
2202 {
2203 REJECT;
2204 }
2205 else if (YY_START==RulesRoundDouble)
2206 {
2207 REJECT;
2208 }
2209 else
2210 {
2211 outputArray(yyscanner,yytext,yyleng);
2212 yyextra->lastCPPContext=YY_START;
2213 if (yyleng==3)
2214 {
2215 yyextra->isSpecialComment = true;
2216 yyextra->lastGuardName.clear(); // reset guard in case the #define is documented!
2217 }
2218 else
2219 {
2220 yyextra->isSpecialComment = false;
2221 }
2222 BEGIN(SkipCPPComment);
2223 }
2224 }
2225<*>\n {
2226 outputChar(yyscanner,'\n');
2227 yyextra->yyLineNr++;
2228 }
2229<*>. {
2230 yyextra->expectGuard = false;
2231 outputChar(yyscanner,*yytext);
2232 }
2233
2234%%

◆ yyread()

int yyread ( yyscan_t yyscanner,
char * buf,
int max_size )
static

Definition at line 2238 of file pre.l.

2239{
2240 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2241 int bytesInBuf = static_cast<int>(state->inputBuf->size())-state->inputBufPos;
2242 int bytesToCopy = std::min(max_size,bytesInBuf);
2243 memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy);
2244 state->inputBufPos+=bytesToCopy;
2245 return bytesToCopy;
2246}

Variable Documentation

◆ g_debugMutex

std::mutex g_debugMutex
static

Definition at line 232 of file pre.l.

Referenced by Preprocessor::processFile().

◆ g_defineManager

DefineManager g_defineManager
static

Definition at line 235 of file pre.l.

Referenced by checkAndOpenFile(), and readIncludeFile().

◆ g_globalDefineMutex

std::mutex g_globalDefineMutex
static

Definition at line 233 of file pre.l.

Referenced by checkAndOpenFile(), and readIncludeFile().

◆ g_updateGlobals

std::mutex g_updateGlobals
static

Definition at line 234 of file pre.l.

Referenced by Preprocessor::processFile().