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 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 skipCommentMacroName (yyscan_t yyscanner, const QCString &expr, QCString *rest, int &cc, uint32_t &j, int &len)
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 2948 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 code.l:3971

Definition at line 349 of file pre.l.

◆ YY_NO_UNISTD_H

#define YY_NO_UNISTD_H   1

Definition at line 68 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 109 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 3484 of file pre.l.

3485{
3486 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3487 Define def;
3488 def.name = state->defName;
3489 def.definition = state->defText.stripWhiteSpace();
3490 def.nargs = state->defArgs;
3491 def.fileName = state->fileName;
3492 def.fileDef = state->yyFileDef;
3493 def.lineNr = state->yyLineNr-state->yyMLines;
3494 def.columnNr = state->yyColNr;
3495 def.varArgs = state->defVarArgs;
3496 //printf("newDefine: %s %s file: %s\n",qPrint(def.name),qPrint(def.definition),
3497 // def.fileDef ? qPrint(def.fileDef->name()) : qPrint(def.fileName));
3498 //printf("newDefine: '%s'->'%s'\n",qPrint(def.name),qPrint(def.definition));
3499 if (!def.name.isEmpty() &&
3501 {
3502 def.isPredefined=TRUE;
3504 }
3505 auto it = state->localDefines.find(def.name.str());
3506 if (it!=state->localDefines.end()) // redefine
3507 {
3508 state->localDefines.erase(it);
3509 }
3510 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:163
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
const std::string & str() const
Definition qcstring.h:552
#define TRUE
Definition qcstring.h:37
3511}

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(), TRUE, and Define::varArgs.

◆ addMacroDefinition()

void addMacroDefinition ( yyscan_t yyscanner)
static

Definition at line 3513 of file pre.l.

3514{
3515 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3516 if (state->skip) return; // do not add this define as it is inside a
3517 // conditional section (cond command) that is disabled.
3518
3519 Define define;
3520 define.fileName = state->fileName;
3521 define.lineNr = state->yyLineNr - state->yyMLines;
3522 define.columnNr = state->yyColNr;
3523 define.name = state->defName;
3524 define.args = state->defArgsStr;
3525 define.fileDef = state->inputFileDef;
QCString args
Definition define.h:36
3526
3527 QCString litText = state->defLitText;
3528 int l=litText.find('\n');
3529 if (l>0 && litText.left(l).stripWhiteSpace()=="\\")
3530 {
3531 // strip first line if it only contains a slash
3532 litText = litText.right(litText.length()-l-1);
3533 }
3534 else if (l>0)
3535 {
3536 // align the items on the first line with the items on the second line
3537 int k=l+1;
3538 const char *p=litText.data()+k;
3539 char c = 0;
3540 while ((c=*p++) && (c==' ' || c=='\t')) k++;
3541 litText=litText.mid(l+1,k-l-1)+litText.stripWhiteSpace();
3542 }
3543 QCString litTextStripped = state->defLitText.stripWhiteSpace();
3544 if (litTextStripped.contains('\n')>=1)
3545 {
3546 define.definition = litText;
3547 }
3548 else
3549 {
3550 define.definition = litTextStripped;
3551 }
3552 {
3553 state->macroDefinitions.push_back(define);
3554 }
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
QCString right(size_t len) const
Definition qcstring.h:234
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:172
QCString left(size_t len) const
Definition qcstring.h:229
int contains(char c, bool cs=TRUE) const
Definition qcstring.cpp:148
3555}

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 2950 of file pre.l.

2951{
2952 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2953 if (!state->nospaces)
2954 {
2955 // peek back in the stream, for a colon character
2956 char ccPrev = pos==0 || (int)expr.length()<pos ? state->prevChar : expr.at(pos-1);
2957 QCString leftSpace = ccPrev!=':' && ccPrev!=' ' ? " " : "";
2958 int ccNext = 0;
2959 restExpr=restExpr.stripWhiteSpace();
2960 if (restExpr.isEmpty()) // peek ahead in the stream for non-whitespace
2961 {
2962 uint32_t j=(uint32_t)resultExpr.length();
2963 while ((ccNext=getNextChar(yyscanner,resultExpr,nullptr,j))!=EOF && ccNext==' ') { }
2964 if (ccNext != EOF) unputChar(yyscanner,resultExpr,nullptr,j,(char)ccNext);
2965 }
2966 else // take first char from remainder
2967 {
2968 ccNext=restExpr.at(0);
2969 }
2970 // don't add whitespace before a colon
2971 QCString rightSpace = ccNext!=':' && ccNext!=' ' ? " " : "";
2972 //printf("ccPrev='%c' ccNext='%c' p=%d expr=%zu restExpr='%s' left='%s' right='%s'\n",
2973 // ccPrev,ccNext,pos,expr.length(),qPrint(restExpr),qPrint(leftSpace),qPrint(rightSpace));
2974 resultExpr=leftSpace+resultExpr+rightSpace;
2975 }
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
static int getNextChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos)
Definition pre.l:3867
static void unputChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char c)
Definition pre.l:3913
2976}

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

Referenced by expandExpression().

◆ addTillEndOfString()

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

Definition at line 2587 of file pre.l.

2589{
2590 int cc;
2591 while ((cc=getNextChar(yyscanner,expr,rest,pos))!=EOF && cc!=0)
2592 {
2593 if (cc=='\\')
2594 {
2595 arg+=(char)cc;
2596 cc=getNextChar(yyscanner,expr,rest,pos);
2597 }
2598 else if (cc==term)
2599 {
2600 return;
2601 }
2602 arg+=(char)cc;
2603 }
#define term(fmt,...)
Definition message.h:137
2604}

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 2275 of file pre.l.

2276{
2277 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2278 alreadyProcessed = FALSE;
2279 std::unique_ptr<FileState> fs;
2280 //printf("checkAndOpenFile(%s)\n",qPrint(fileName));
2281 FileInfo fi(fileName.str());
2282 if (fi.exists() && fi.isFile())
2283 {
2284 const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
2285 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
#define FALSE
Definition qcstring.h:34
bool patternMatch(const FileInfo &fi, const StringVector &patList)
Definition util.cpp:5640
2286
2287 QCString absName = fi.absFilePath();
2288
2289 // global guard
2290 if (state->curlyCount==0) // not #include inside { ... }
2291 {
2292 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
2293 if (g_defineManager.alreadyProcessed(absName.str()))
2294 {
2295 alreadyProcessed = TRUE;
2296 //printf(" already included 1\n");
2297 return 0; // already done
2298 }
2299 }
2300 // check include stack for absName
static std::mutex g_globalDefineMutex
Definition pre.l:234
static DefineManager g_defineManager
Definition pre.l:236
2301
2302 alreadyProcessed = std::any_of(
2303 state->includeStack.begin(),
2304 state->includeStack.end(),
2305 [absName](const std::unique_ptr<FileState> &lfs)
2306 { return lfs->fileName==absName; }
2307 );
2308
2309 if (alreadyProcessed)
2310 {
2311 //printf(" already included 2\n");
2312 return nullptr;
2313 }
2314 //printf("#include %s\n",qPrint(absName));
2315
2316 fs = std::make_unique<FileState>();
2317 if (!readInputFile(absName,fs->fileBuf))
2318 { // error
2319 //printf(" error reading\n");
2320 fs.reset();
2321 }
2322 else
2323 {
2324 addTerminalCharIfMissing(fs->fileBuf,'\n');
2325 fs->oldFileBuf = state->inputBuf;
2326 fs->oldFileBufPos = state->inputBufPos;
2327 }
2328 }
2329 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:5486
2330}

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

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 3451 of file pre.l.

3452{
3453 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3454 QCString e=expr;
3455 QCString ee=expr;
3456 ee = removeMarkers(ee);
3457 state->expanded.clear();
3458 expandExpression(yyscanner,e,nullptr,0,0);
3459 //printf("after expansion '%s'\n",qPrint(e));
3460 e = removeIdsAndMarkers(e);
3461 if (e.isEmpty()) return FALSE;
3462 //printf("parsing '%s'\n",qPrint(e));
3463 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:2982
static QCString removeIdsAndMarkers(const QCString &s)
Definition pre.l:3185
static QCString removeMarkers(const QCString &s)
Definition pre.l:3380
3464}

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

◆ decrLevel()

void decrLevel ( yyscan_t yyscanner)
static

Definition at line 2240 of file pre.l.

2241{
2242 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2243 //printf("%s line %d: decrLevel %d\n",qPrint(state->fileName),state->yyLineNr,state->levelGuard.size());
2244 if (!state->levelGuard.empty())
2245 {
2246 state->levelGuard.pop();
2247 }
2248 else
2249 {
2250 warn(state->fileName,state->yyLineNr,"More #endif's than #if's found.");
2251 }
#define warn(file, line, fmt,...)
Definition message.h:97
2252}

References warn.

Referenced by Markdown::Private::writeBlockQuote().

◆ determineBlockName()

void determineBlockName ( yyscan_t yyscanner)
static

Definition at line 3605 of file pre.l.

3606{
3607 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3608 yyextra->fenceSize=0;
3609 char c=0;
3610 if (yytext[1]=='f' && ((c=yytext[2])=='[' || c=='{' || c=='(' || c=='$'))
3611 {
3612 switch (c)
3613 {
3614 case '[': yyextra->blockName="]"; break;
3615 case '{': yyextra->blockName="}"; break;
3616 case '(': yyextra->blockName=")"; break;
3617 case '$': yyextra->blockName="$"; break;
3618 default: break;
3619 }
3620 yyextra->blockName=yyextra->blockName.stripWhiteSpace();
3621 }
3622 else
3623 {
3624 QCString bn=QCString(&yytext[1]).stripWhiteSpace();
3625 if (bn=="startuml")
3626 {
3627 yyextra->blockName="uml";
3628 }
3629 else
3630 {
3631 int i = bn.find('{'); // for \code{.c}
3632 if (i!=-1) bn=bn.left(i).stripWhiteSpace();
3633 yyextra->blockName=bn;
3634 }
3635 }
3636}

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

◆ endCondSection()

void endCondSection ( yyscan_t yyscanner)
static

Definition at line 3805 of file pre.l.

3806{
3807 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3808 if (state->condStack.empty())
3809 {
3810 warn(state->fileName,state->yyLineNr,"the \\endcond does not have a corresponding \\cond in this file");
3811 state->skip=FALSE;
3812 }
3813 else
3814 {
3815 const std::unique_ptr<preYY_CondCtx> &ctx = state->condStack.top();
3816 state->skip=ctx->skip;
3817 state->condStack.pop();
3818 }
3819 //printf("endCondSection: skip=%d stack=%d\n",state->skip,state->condStack.count());
3820}

References FALSE, and warn.

◆ escapeAt()

QCString escapeAt ( const QCString & text)
static

Definition at line 3832 of file pre.l.

3833{
3834 QCString result;
3835 if (!text.isEmpty())
3836 {
3837 char c = 0;
3838 const char *p=text.data();
3839 while ((c=*p++))
3840 {
3841 if (c=='@') result+="@@"; else result+=c;
3842 }
3843 }
3844 return result;
3845}

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 2982 of file pre.l.

2983{
2984 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2985 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2986 //printf(">expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos, level);
2987 if (expr.isEmpty())
2988 {
2989 //printf("<expandExpression: empty\n");
2990 return TRUE;
2991 }
2992 if (state->expanded.find(expr.str())!=state->expanded.end() &&
2993 level>MAX_EXPANSION_DEPTH) // check for too deep recursive expansions
2994 {
2995 //printf("<expandExpression: already expanded expr='%s'\n",qPrint(expr));
2996 return FALSE;
2997 }
2998 else
2999 {
3000 state->expanded.insert(expr.str());
3001 }
3002 QCString macroName;
3003 QCString expMacro;
3004 bool definedTest=FALSE;
3005 int i=pos, l=0, p=0, len=0;
3006 int startPos = pos;
3007 int samePosCount=0;
3008 while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name
3009 {
3010 bool replaced=FALSE;
3011 macroName=expr.mid(p,l);
3012 //printf(" p=%d macroName=%s\n",p,qPrint(macroName));
3013 if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker?
3014 {
3015 if (state->expandedDict.find(macroName.str())==state->expandedDict.end()) // expand macro
3016 {
3017 bool expanded=false;
3018 Define *def=isDefined(yyscanner,macroName);
3019 // In case EXPAND_ONLY_PREDEF is enabled prevent expansion unless the macro was explicitly
3020 // predefined
3021 if (yyextra->expandOnlyPredef && def && !def->isPredefined) def=nullptr;
3022 if (macroName=="defined")
3023 {
3024 //printf("found defined inside macro definition '%s'\n",qPrint(expr.right(expr.length()-p)));
3025 definedTest=TRUE;
3026 }
3027 else if (definedTest) // macro name was found after defined
3028 {
3029 if (def) expMacro = " 1 "; else expMacro = " 0 ";
3030 replaced=TRUE;
3031 len=l;
3032 definedTest=FALSE;
3033 }
3034 else if (def && def->nargs==-1) // simple macro
3035 {
3036 // substitute the definition of the macro
3037 expMacro=def->definition.stripWhiteSpace();
3038 //expMacro=def->definition.stripWhiteSpace();
3039 replaced=TRUE;
3040 len=l;
3041 //printf("simple macro expansion='%s'->'%s'\n",qPrint(macroName),qPrint(expMacro));
3042 }
3043 else if (def && def->nargs>=0) // function macro
3044 {
3045 //printf(" >>>> call replaceFunctionMacro expr='%s'\n",qPrint(expr));
3046 replaced=replaceFunctionMacro(yyscanner,expr,rest,p+l,len,def,expMacro,level);
3047 //printf(" <<<< call replaceFunctionMacro: replaced=%d\n",replaced);
3048 len+=l;
3049 }
3050 else if (macroName=="__VA_OPT__")
3051 {
3052 // expr='( something __VA_OPT__(value) )' or '( something __VA_OPT__(value) something_else )'
3053 static const reg::Ex re(R"(__VA_OPT__\‍((.*)\)(.*)\))");
3054 reg::Match m;
3055 std::string s = expr.mid(p).str();
3056 if (reg::search(s,m,re))
3057 {
3058 assert(m.size()==3);
3059 std::string value = m[1].str();
3060 std::string remainder = m[2].str();
3061 //printf("value='%s' remainder='%s'\n",qPrint(value),qPrint(remainder));
3062 expMacro = stripWhiteSpace(remainder).empty() ? std::string() : value;
3063 expanded=true;
3064 replaced=true;
3065 len+=l+2+m[1].str().length();
3066 }
3067 else
3068 {
3069 //printf("no match for '%s'\n",qPrint(expr));
3070 }
3071 }
3072 //printf(" macroName='%s' expMacro='%s' replaced=%d expanded=%d\n",qPrint(macroName),qPrint(expMacro),replaced,expanded);
Class representing a regular expression.
Definition regex.h:39
Object representing the matching results.
Definition regex.h:151
size_t size() const
Returns the number of sub matches available in this match.
Definition regex.h:181
std::string str() const
Return a string representing the matching part.
Definition regex.h:163
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:844
#define MAX_EXPANSION_DEPTH
Definition pre.l:2948
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:3937
static int getNextId(const QCString &expr, int p, int *l)
Definition pre.l:2894
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:2644
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:72
3073
3074 if (replaced) // expand the macro and rescan the expression
3075 {
3076 //printf(" replacing '%s'->'%s'\n",qPrint(expr.mid(p,len)),qPrint(expMacro));
3077 QCString resultExpr=expMacro;
3078 QCString restExpr=expr.right(expr.length()-len-p);
3079 addSeparatorsIfNeeded(yyscanner,expr,resultExpr,restExpr,p);
3080 processConcatOperators(resultExpr);
3081 //printf(" macroName=%s restExpr='%s' def->nonRecursive=%d\n",qPrint(macroName),qPrint(restExpr),def ? def->nonRecursive : false);
3082 if (def && !def->nonRecursive)
3083 {
3084 state->expandedDict.emplace(toStdString(macroName),def);
3085 expanded = expandExpression(yyscanner,resultExpr,&restExpr,0,level+1);
3086 state->expandedDict.erase(toStdString(macroName));
3087 }
3088 else if (def && def->nonRecursive)
3089 {
3090 expanded = true;
3091 }
3092 if (expanded)
3093 {
3094 //printf("expanded '%s' + '%s' + '%s'\n",qPrint(expr.left(p)),qPrint(resultExpr),qPrint(restExpr));
3095 expr=expr.left(p)+resultExpr+restExpr;
3096 i=p;
3097 }
3098 else
3099 {
3100 //printf("not expanded '%s' + @- '%s'\n",qPrint(expr.left(p)),qPrint(expr.right(expr.length()-p)));
3101 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3102 i=p+l+2;
3103 }
3104 }
3105 else // move to the next macro name
3106 {
3107 //printf(" moving to the next macro old i=%d new i=%d\n",i,p+l);
3108 i=p+l;
3109 }
3110 }
3111 else // move to the next macro name
3112 {
3113 expr=expr.left(p)+"@-"+expr.right(expr.length()-p);
3114 //printf("macro already expanded, moving to the next macro expr=%s\n",qPrint(expr));
3115 i=p+l+2;
3116 //i=p+l;
3117 }
3118 // check for too many inplace expansions without making progress
3119 if (i==startPos)
3120 {
3121 samePosCount++;
3122 }
3123 else
3124 {
3125 startPos=i;
3126 samePosCount=0;
3127 }
3128 if (samePosCount>MAX_EXPANSION_DEPTH)
3129 {
3130 break;
3131 }
3132 }
3133 else // no re-scan marker found, skip the macro name
3134 {
3135 //printf("skipping marked macro\n");
3136 i=p+l;
3137 }
3138 }
3139 //printf("<expandExpression(expr='%s',rest='%s',pos=%d,level=%d)\n",qPrint(expr),rest ? qPrint(*rest) : "", pos,level);
3140 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:2950
static void processConcatOperators(QCString &expr)
Definition pre.l:2534
std::string toStdString(const QCString &s)
Definition qcstring.h:702
3141}

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

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 3470 of file pre.l.

3471{
3472 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
3473 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3474 state->prevChar = yyscanner->yytext_r > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ? *(yyscanner->yytext_r-1) : 0;
3475 QCString n=name;
3476 state->expanded.clear();
3477 expandExpression(yyscanner,n,nullptr,0,0);
3478 n=removeMarkers(n);
3479 state->prevChar=0;
3480 //printf("expandMacro '%s'->'%s'\n",qPrint(name),qPrint(n));
3481 return n;
void clear()
Definition qcstring.h:182
3482}

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

◆ extractTrailingComment()

QCString extractTrailingComment ( const QCString & s)
static

Definition at line 2406 of file pre.l.

2407{
2408 if (s.isEmpty()) return "";
2409 int i=(int)s.length()-1;
2410 while (i>=0)
2411 {
2412 char c=s[i];
2413 switch (c)
2414 {
2415 case '/':
2416 {
2417 i--;
2418 if (i>=0 && s[i]=='*') // end of a comment block
2419 {
2420 i--;
2421 while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--;
2422 if (i==0)
2423 {
2424 i++;
2425 }
2426 // only /*!< ... */ or /**< ... */ are treated as a comment for the macro name,
2427 // otherwise the comment is treated as part of the macro definition
2428 return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : "";
2429 }
2430 else
2431 {
2432 return "";
2433 }
2434 }
2435 break;
2436 // whitespace or line-continuation
2437 case ' ':
2438 case '\t':
2439 case '\r':
2440 case '\n':
2441 case '\\':
2442 break;
2443 default:
2444 return "";
2445 }
2446 i--;
2447 }
2448 return "";
2449}

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

◆ extraSpacing()

void extraSpacing ( yyscan_t yyscanner)
inlinestatic

Definition at line 3592 of file pre.l.

3593{
3594 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3595 if (!yyextra->defContinue) return;
3596 for (int i=0; i< (int)yyleng; i++)
3597 {
3598 if (yytext[i] == '\t')
3599 yyextra->defExtraSpacing+='\t';
3600 else
3601 yyextra->defExtraSpacing+=' ';
3602 }
3603}

◆ findFile()

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

Definition at line 2332 of file pre.l.

2333{
2334 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2335 //printf("** findFile(%s,%d) state->fileName=%s\n",qPrint(fileName),localInclude,qPrint(state->fileName));
2336 if (Portable::isAbsolutePath(fileName))
2337 {
2338 auto fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed);
2339 if (fs)
2340 {
2341 setFileName(yyscanner,fileName);
2342 state->yyLineNr=1;
2343 return fs;
2344 }
2345 else if (alreadyProcessed)
2346 {
2347 return nullptr;
2348 }
2349 }
2350 if (localInclude && !state->fileName.isEmpty())
2351 {
2352 FileInfo fi(state->fileName.str());
2353 if (fi.exists())
2354 {
2355 QCString absName = QCString(fi.dirPath(TRUE))+"/"+fileName;
2356 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2357 if (fs)
2358 {
2359 setFileName(yyscanner,absName);
2360 state->yyLineNr=1;
2361 return fs;
2362 }
2363 else if (alreadyProcessed)
2364 {
2365 return nullptr;
2366 }
2367 }
2368 }
2369 if (state->pathList.empty())
2370 {
2371 return nullptr;
2372 }
2373 for (auto path : state->pathList)
2374 {
2375 QCString absName = path+"/"+fileName;
2376 //printf(" Looking for %s in %s\n",fileName,qPrint(path));
2377 auto fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed);
2378 if (fs)
2379 {
2380 setFileName(yyscanner,absName);
2381 state->yyLineNr=1;
2382 //printf(" -> found it\n");
2383 return fs;
2384 }
2385 else if (alreadyProcessed)
2386 {
2387 return nullptr;
2388 }
2389 }
2390 bool ambig = false;
2392 if (fd && !ambig) // fallback in case the file is uniquely named in the input, use that one
2393 {
2394 auto fs = checkAndOpenFile(yyscanner,fd->absFilePath(),alreadyProcessed);
2395 if (fs)
2396 {
2397 setFileName(yyscanner,fd->absFilePath());
2398 state->yyLineNr=1;
2399 //printf(" -> found it\n");
2400 return fs;
2401 }
2402 }
2403 return nullptr;
static FileNameLinkedMap * inputNameLinkedMap
Definition doxygen.h:105
A model of a file symbol.
Definition filedef.h:99
virtual QCString absFilePath() const =0
bool isAbsolutePath(const QCString &fileName)
Definition portable.cpp:498
static void setFileName(yyscan_t yyscanner, const QCString &name)
Definition pre.l:2212
static std::unique_ptr< FileState > checkAndOpenFile(yyscan_t yyscanner, const QCString &fileName, bool &alreadyProcessed)
Definition pre.l:2275
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:2839
2404}

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

◆ forceEndCondSection()

void forceEndCondSection ( yyscan_t yyscanner)
static

Definition at line 3822 of file pre.l.

3823{
3824 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3825 while (!state->condStack.empty())
3826 {
3827 state->condStack.pop();
3828 }
3829 state->skip=FALSE;
3830}

References FALSE.

Referenced by Preprocessor::processFile().

◆ getCurrentChar()

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

Definition at line 3890 of file pre.l.

3891{
3892 //printf("getCurrentChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3893 if (pos<expr.length())
3894 {
3895 //printf("%c=expr()\n",expr.at(pos));
3896 return expr.at(pos);
3897 }
3898 else if (rest && !rest->isEmpty())
3899 {
3900 int cc=rest->at(0);
3901 //printf("%c=rest\n",cc);
3902 return cc;
3903 }
3904 else
3905 {
3906 int cc=yyinput(yyscanner);
3907 returnCharToStream(yyscanner,(char)cc);
3908 //printf("%c=yyinput()\n",cc);
3909 return cc;
3910 }
static void returnCharToStream(yyscan_t yyscanner, char c)
Definition pre.l:2581
3911}

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

Referenced by replaceFunctionMacro(), and skipCommentMacroName().

◆ getFenceSize()

yy_size_t getFenceSize ( char * txt,
yy_size_t leng )
static

Definition at line 2201 of file pre.l.

2202{
2203 yy_size_t fenceSize = 0;
2204 for (size_t i = 0; i < leng; i++)
2205 {
2206 if (txt[i] != ' ' && txt[i] != '*' && txt[i] != '\t') break;
2207 fenceSize++;
2208 }
2209 return leng-fenceSize;
2210}

◆ getLexerFILE()

const char * getLexerFILE ( )
inlinestatic

Definition at line 352 of file pre.l.

352{return __FILE__;}

◆ getNextChar()

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

Definition at line 3867 of file pre.l.

3868{
3869 //printf("getNextChar(%s,%s,%d)\n",qPrint(expr),rest ? rest->data() : 0,pos);
3870 if (pos<expr.length())
3871 {
3872 //printf(" expr()='%c'\n",expr.at(pos));
3873 return expr.at(pos++);
3874 }
3875 else if (rest && !rest->isEmpty())
3876 {
3877 int cc=rest->at(0);
3878 *rest=rest->right(rest->length()-1);
3879 //printf(" rest='%c'\n",cc);
3880 return cc;
3881 }
3882 else
3883 {
3884 int cc=yyinput(yyscanner);
3885 //printf(" yyinput()='%c' %d\n",cc,EOF);
3886 return cc;
3887 }
3888}

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

Referenced by addSeparatorsIfNeeded(), 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 2894 of file pre.l.

2895{
2896 int n;
2897 while (p<(int)expr.length())
2898 {
2899 char c=expr.at(p++);
2900 if (isdigit(c)) // skip number
2901 {
2902 while (p<(int)expr.length() && isId(expr.at(p))) p++;
2903 }
2904 else if (isalpha(c) || c=='_') // read id
2905 {
2906 n=p-1;
2907 while (p<(int)expr.length() && isId(expr.at(p))) p++;
2908 *l=p-n;
2909 return n;
2910 }
2911 else if (c=='"') // skip string
2912 {
2913 char ppc=0,pc=c;
2914 if (p<(int)expr.length()) c=expr.at(p);
2915 while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\')))
2916 // continue as long as no " is found, but ignoring \", but not \\"
2917 {
2918 ppc=pc;
2919 pc=c;
2920 c=expr.at(p);
2921 p++;
2922 }
2923 if (p<(int)expr.length()) ++p; // skip closing quote
2924 }
2925 else if (c=='/') // skip C Comment
2926 {
2927 //printf("Found C comment at p=%d\n",p);
2928 char pc=c;
2929 if (p<(int)expr.length())
2930 {
2931 c=expr.at(p);
2932 if (c=='*') // Start of C comment
2933 {
2934 p++;
2935 while (p<(int)expr.length() && !(pc=='*' && c=='/'))
2936 {
2937 pc=c;
2938 c=expr.at(p++);
2939 }
2940 }
2941 }
2942 //printf("Found end of C comment at p=%d\n",p);
2943 }
2944 }
2945 return -1;
bool isId(int c)
Definition util.h:208
2946}

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

Referenced by expandExpression().

◆ incrLevel()

void incrLevel ( yyscan_t yyscanner)
static

Definition at line 2233 of file pre.l.

2234{
2235 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2236 state->levelGuard.push(false);
2237 //printf("%s line %d: incrLevel %d\n",qPrint(yyextra->fileName),yyextra->yyLineNr,yyextra->levelGuard.size());
2238}

◆ initPredefined()

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

Definition at line 3966 of file pre.l.

3967{
3968 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3969
3970 // add predefined macros
3971 const StringVector &predefList = Config_getList(PREDEFINED);
3972 for (const auto &ds : predefList)
3973 {
3974 size_t i_equals=ds.find('=');
3975 size_t i_obrace=ds.find('(');
3976 size_t i_cbrace=ds.find(')');
3977 bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
3978
3979 if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
3980 {
3981 continue; // no define name
3982 }
3983
3984 if (i_obrace<i_equals && i_cbrace<i_equals &&
3985 i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
3986 i_obrace<i_cbrace
3987 ) // predefined function macro definition
3988 {
3989 static const reg::Ex reId(R"(\a\w*)");
3990 std::map<std::string,int> argMap;
3991 std::string args = ds.substr(i_obrace+1,i_cbrace-i_obrace-1); // part between ( and )
3992 bool hasVarArgs = args.find("...")!=std::string::npos;
3993 //printf("predefined function macro '%s'\n",qPrint(ds));
3994 int count = 0;
3995 reg::Iterator arg_it(args,reId,0);
3996 reg::Iterator arg_end;
3997 // gather the formal arguments in a dictionary
3998 for (; arg_it!=arg_end; ++arg_it)
3999 {
4000 argMap.emplace(arg_it->str(),count++);
4001 }
4002 if (hasVarArgs) // add the variable argument if present
4003 {
4004 argMap.emplace("__VA_ARGS__",count++);
4005 }
Class to iterate through matches.
Definition regex.h:230
4006
4007 // strip definition part
4008 std::string definition;
4009 std::string in=ds.substr(i_equals+1);
4010 reg::Iterator re_it(in,reId);
4011 reg::Iterator re_end;
4012 size_t i=0;
4013 // substitute all occurrences of formal arguments by their
4014 // corresponding markers
4015 for (; re_it!=re_end; ++re_it)
4016 {
4017 const auto &match = *re_it;
4018 size_t pi = match.position();
4019 size_t l = match.length();
4020 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:855
4021
4022 auto it = argMap.find(match.str());
4023 if (it!=argMap.end())
4024 {
4025 int argIndex = it->second;
4026 QCString marker;
4027 marker.sprintf(" @%d ",argIndex);
4028 definition+=marker.str();
4029 }
4030 else
4031 {
4032 definition+=match.str();
4033 }
4034 i=pi+l;
4035 }
4036 definition+=in.substr(i);
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
4037
4038 // add define definition to the dictionary of defines for this file
4039 std::string dname = ds.substr(0,i_obrace);
4040 if (!dname.empty())
4041 {
4042 Define def;
4043 def.name = dname;
4044 def.definition = definition;
4045 def.nargs = count;
4046 def.isPredefined = TRUE;
4047 def.nonRecursive = nonRecursive;
4048 def.fileDef = state->yyFileDef;
4049 def.fileName = fileName;
4050 def.varArgs = hasVarArgs;
4051 state->contextDefines.emplace(def.name.str(),def);
4052
4053 //printf("#define '%s' '%s' #nargs=%d hasVarArgs=%d\n",
4054 // qPrint(def.name),qPrint(def.definition),def.nargs,def.varArgs);
4055 }
4056 }
4057 else if (!ds.empty()) // predefined non-function macro definition
4058 {
4059 //printf("predefined normal macro '%s'\n",qPrint(ds));
4060 Define def;
4061 if (i_equals==std::string::npos) // simple define without argument
4062 {
4063 def.name = ds;
4064 def.definition = "1"; // substitute occurrences by 1 (true)
4065 }
4066 else // simple define with argument
4067 {
4068 int ine=static_cast<int>(i_equals) - (nonRecursive ? 1 : 0);
4069 def.name = ds.substr(0,ine);
4070 def.definition = ds.substr(i_equals+1);
4071 }
4072 if (!def.name.isEmpty())
4073 {
4074 def.nargs = -1;
4075 def.isPredefined = TRUE;
4076 def.nonRecursive = nonRecursive;
4077 def.fileDef = state->yyFileDef;
4078 def.fileName = fileName;
4079 state->contextDefines.emplace(def.name.str(),def);
4080 }
4081 }
4082 }
4083}

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(), TRUE, 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 3937 of file pre.l.

3938{
3939 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3940
3941 bool undef = false;
3942 auto findDefine = [&undef,&name](DefineMap &map)
3943 {
3944 Define *d=nullptr;
3945 auto it = map.find(name.str());
3946 if (it!=map.end())
3947 {
3948 d = &it->second;
3949 if (d->undef)
3950 {
3951 undef=true;
3952 d=nullptr;
3953 }
3954 }
3955 return d;
3956 };
bool undef
Definition define.h:41
std::map< std::string, Define > DefineMap
A dictionary of managed Define objects.
Definition pre.l:109
3957
3958 Define *def = findDefine(state->localDefines);
3959 if (def==nullptr && !undef)
3960 {
3961 def = findDefine(state->contextDefines);
3962 }
3963 return def;
3964}

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

Referenced by expandExpression().

◆ otherCaseDone()

bool otherCaseDone ( yyscan_t yyscanner)
static

Definition at line 2254 of file pre.l.

2255{
2256 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2257 if (state->levelGuard.empty())
2258 {
2259 warn(state->fileName,state->yyLineNr,"Found an #else without a preceding #if.");
2260 return TRUE;
2261 }
2262 else
2263 {
2264 return state->levelGuard.top();
2265 }
2266}

References TRUE, and warn.

◆ outputArray()

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

Definition at line 3563 of file pre.l.

3564{
3565 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3566 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=std::string_view(a,len);
3567}

◆ outputChar()

void outputChar ( yyscan_t yyscanner,
char c )
inlinestatic

Definition at line 3557 of file pre.l.

3558{
3559 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3560 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=c;
3561}

Referenced by outputSpace(), and outputSpaces().

◆ outputSpace()

void outputSpace ( yyscan_t yyscanner,
char c )
inlinestatic

Definition at line 3575 of file pre.l.

3576{
3577 if (c=='\t') outputChar(yyscanner,'\t');
3578 else outputChar(yyscanner,' ');
static void outputChar(yyscan_t yyscanner, char c)
Definition pre.l:3557
3579}

References outputChar().

◆ outputSpaces()

void outputSpaces ( yyscan_t yyscanner,
char * s )
inlinestatic

Definition at line 3581 of file pre.l.

3582{
3583 const char *p=s;
3584 char c = 0;
3585 while ((c=*p++))
3586 {
3587 if (c=='\t') outputChar(yyscanner,'\t');
3588 else outputChar(yyscanner,' ');
3589 }
3590}

References outputChar().

◆ outputString()

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

Definition at line 3569 of file pre.l.

3570{
3571 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3572 if (state->includeStack.empty() || state->curlyCount>0) (*state->outputBuf)+=a.str();
3573}

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 2534 of file pre.l.

2535{
2536 if (expr.isEmpty()) return;
2537 //printf("processConcatOperators: in='%s'\n",qPrint(expr));
2538 std::string e = expr.str();
2539 static const reg::Ex r(R"(\s*##\s*)");
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
2541
2542 size_t i=0;
2543 for (;;)
2544 {
2545 reg::Iterator it(e,r,i);
2546 if (it!=end)
2547 {
2548 const auto &match = *it;
2549 size_t n = match.position();
2550 size_t l = match.length();
2551 //printf("Match: '%s'\n",qPrint(expr.mid(i)));
2552 if (n+l+1<e.length() && e[static_cast<int>(n+l)]=='@' && expr[static_cast<int>(n+l+1)]=='-')
2553 {
2554 // remove no-rescan marker after ID
2555 l+=2;
2556 }
2557 //printf("found '%s'\n",qPrint(expr.mid(n,l)));
2558 // remove the ## operator and the surrounding whitespace
2559 e=e.substr(0,n)+e.substr(n+l);
2560 int k=static_cast<int>(n)-1;
2561 while (k>=0 && isId(e[k])) k--;
2562 if (k>0 && e[k]=='-' && e[k-1]=='@')
2563 {
2564 // remove no-rescan marker before ID
2565 e=e.substr(0,k-1)+e.substr(k+1);
2566 n-=2;
2567 }
2568 i=n;
2569 }
2570 else
2571 {
2572 break;
2573 }
2574 }
2575
2576 expr = e;
2577
2578 //printf("processConcatOperators: out='%s'\n",qPrint(expr));
2579}

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 3149 of file pre.l.

3150{
3151 if (inputStr==nullptr) return inputStr;
3152 char term = *inputStr; // capture start character of the literal
3153 if (term!='\'' && term!='"') return inputStr; // not a valid literal
3154 char c=term;
3155 // output start character
3156 result+=c;
3157 inputStr++;
3158 while ((c=*inputStr)) // while inside the literal
3159 {
3160 if (c==term) // found end marker of the literal
3161 {
3162 // output end character and stop
3163 result+=c;
3164 inputStr++;
3165 break;
3166 }
3167 else if (c=='\\') // escaped character, process next character
3168 // as well without checking for end marker.
3169 {
3170 result+=c;
3171 inputStr++;
3172 c=*inputStr;
3173 if (c==0) break; // unexpected end of string after escape character
3174 }
3175 result+=c;
3176 inputStr++;
3177 }
3178 return inputStr;
3179}

References term.

Referenced by removeIdsAndMarkers(), and removeMarkers().

◆ readIncludeFile()

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

Definition at line 3638 of file pre.l.

3639{
3640 AUTO_TRACE("inc={}",inc);
3641 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3642 uint32_t i=0;
#define AUTO_TRACE(...)
Definition docnode.cpp:46
3643
3644 // find the start of the include file name
3645 while (i<inc.length() &&
3646 (inc.at(i)==' ' || inc.at(i)=='"' || inc.at(i)=='<')
3647 ) i++;
3648 uint32_t s=i;
3649
3650 // was it a local include?
3651 bool localInclude = s>0 && inc.at(s-1)=='"';
3652
3653 // find the end of the include file name
3654 while (i<inc.length() && inc.at(i)!='"' && inc.at(i)!='>') i++;
3655
3656 if (s<inc.length() && i>s) // valid include file name found
3657 {
3658 // extract include path+name
3659 QCString incFileName=inc.mid(s,i-s).stripWhiteSpace();
3660 if (incFileName.endsWith(".exe") || incFileName.endsWith(".dll") || incFileName.endsWith(".tlb"))
3661 {
3662 // skip imported binary files (e.g. M$ type libraries)
3663 return;
3664 }
bool endsWith(const char *s) const
Definition qcstring.h:524
3665
3666 QCString oldFileName = state->fileName;
3667 FileDef *oldFileDef = state->yyFileDef;
3668 int oldLineNr = state->yyLineNr;
3669 //printf("Searching for '%s'\n",qPrint(incFileName));
3670
3671 QCString absIncFileName = determineAbsoluteIncludeName(state->fileName,incFileName);
QCString determineAbsoluteIncludeName(const QCString &curFile, const QCString &incFileName)
Definition util.cpp:3542
3672
3673 // findFile will overwrite state->yyFileDef if found
3674 std::unique_ptr<FileState> fs;
3675 bool alreadyProcessed = FALSE;
3676 //printf("calling findFile(%s)\n",qPrint(incFileName));
3677 fs=findFile(yyscanner,absIncFileName,localInclude,alreadyProcessed); // see if the absolute include file can be found
3678 if (fs)
3679 {
3680 {
3681 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3682 g_defineManager.addInclude(oldFileName.str(),absIncFileName.str());
3683 }
static std::unique_ptr< FileState > findFile(yyscan_t yyscanner, const QCString &fileName, bool localInclude, bool &alreadyProcessed)
Definition pre.l:2332
3684
3685 //printf("Found include file!\n");
3687 {
3688 for (i=0;i<state->includeStack.size();i++)
3689 {
3691 }
3692 Debug::print(Debug::Preprocessor,0,"#include {}: parsing...\n",incFileName);
3693 }
@ Preprocessor
Definition debug.h:30
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
static void print(DebugMask mask, int prio, fmt::format_string< Args... > fmt, Args &&... args)
Definition debug.h:76
3694
3695 if (state->includeStack.empty() && oldFileDef)
3696 {
3697 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3698 if (ii==nullptr)
3699 {
3700 bool ambig = false;
3701 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3702 state->includeRelations.add(
3703 absIncFileName,
3704 oldFileDef,
3705 ambig ? nullptr : incFd,
3706 incFileName,
3707 localInclude,
3708 state->isImported
3709 );
3710 }
3711 }
3712
3713 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
3714 fs->bufState = YY_CURRENT_BUFFER;
3715 fs->lineNr = oldLineNr;
3716 fs->fileName = oldFileName;
3717 fs->curlyCount = state->curlyCount;
3718 //state->curlyCount = 0; // don't reset counter, see issue #10997
3719 fs->lexRulesPart = state->lexRulesPart;
3720 state->lexRulesPart = false;
3721 // push the state on the stack
3722 FileState *fs_ptr = fs.get();
3723 state->includeStack.push_back(std::move(fs));
3724 // set the scanner to the include file
3725
3726 // Deal with file changes due to
3727 // #include's within { .. } blocks
3728 QCString lineStr(state->fileName.length()+20, QCString::ExplicitSize);
3729 lineStr.sprintf("# 1 \"%s\" 1\n",qPrint(state->fileName));
3730 outputString(yyscanner,lineStr);
@ ExplicitSize
Definition qcstring.h:146
static void outputString(yyscan_t yyscanner, const QCString &s)
Definition pre.l:3569
const char * qPrint(const char *s)
Definition qcstring.h:687
3731
3732 AUTO_TRACE_ADD("Switching to include file {}",incFileName);
3733 state->expectGuard=TRUE;
3734 state->inputBuf = &fs_ptr->fileBuf;
3735 state->inputBufPos=0;
3736 yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
3737 }
3738 else
3739 {
3740 if (alreadyProcessed) // if this header was already process we can just copy the stored macros
3741 // in the local context
3742 {
3743 std::lock_guard<std::mutex> lock(g_globalDefineMutex);
3744 g_defineManager.addInclude(state->fileName.str(),absIncFileName.str());
3745 g_defineManager.retrieve(absIncFileName.str(),state->contextDefines);
3746 }
#define YY_BUF_SIZE
Definition commentcnv.l:19
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:47
std::string fileBuf
Definition pre.l:86
3747
3748 if (state->includeStack.empty() && oldFileDef)
3749 {
3750 PreIncludeInfo *ii = state->includeRelations.find(absIncFileName);
3751 if (ii==nullptr)
3752 {
3753 bool ambig = false;
3754 FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig);
3755 ii = state->includeRelations.add(absIncFileName,
3756 oldFileDef,
3757 ambig ? nullptr : incFd,
3758 incFileName,
3759 localInclude,
3760 state->isImported
3761 );
3762 }
3763 }
3764
3766 {
3767 for (i=0;i<state->includeStack.size();i++)
3768 {
3770 }
3771 if (alreadyProcessed)
3772 {
3773 Debug::print(Debug::Preprocessor,0,"#include {}: already processed! skipping...\n",incFileName);
3774 }
3775 else
3776 {
3777 Debug::print(Debug::Preprocessor,0,"#include {}: not found! skipping...\n",incFileName);
3778 }
3779 //printf("error: include file %s not found\n",yytext);
3780 }
3781 if (localInclude && !state->includeStack.empty() && state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... }
3782 {
3783 warn(state->fileName,state->yyLineNr,"include file {} not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName);
3784 }
3785 }
3786 }
3787}

References QCString::at(), AUTO_TRACE, AUTO_TRACE_ADD, determineAbsoluteIncludeName(), QCString::endsWith(), QCString::ExplicitSize, FALSE, FileState::fileBuf, findFile(), findFileDef(), g_defineManager, g_globalDefineMutex, Doxygen::inputNameLinkedMap, Debug::isFlagSet(), QCString::length(), QCString::mid(), outputString(), Debug::Preprocessor, Debug::print(), qPrint(), QCString::sprintf(), QCString::str(), QCString::stripWhiteSpace(), TRUE, 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 3185 of file pre.l.

3186{
3187 static const std::vector<std::string> signs = { "signed", "unsigned" };
3188 struct TypeInfo { std::string name; size_t size; };
3189 static const std::vector<TypeInfo> types = {
3190 { "short int", sizeof(short int) },
3191 { "long long int", sizeof(long long int) },
3192 { "long int", sizeof(long int) },
3193 { "long long", sizeof(long long) },
3194 { "long double", sizeof(long double) },
3195 { "int", sizeof(int) },
3196 { "short", sizeof(short) },
3197 { "bool", sizeof(bool) },
3198 { "long", sizeof(long) },
3199 { "char", sizeof(char) },
3200 { "float", sizeof(float) },
3201 { "double", sizeof(double) },
3202 };
3203
3204 // Check if string p starts with basic types ending with a ')', such as 'signed long)' or ' float )'
3205 // and return the pointer just past the ')' and the size of the type as a tuple.
3206 // If the pattern is not found the tuple (nullptr,0) is returned.
3207 auto process_cast_or_sizeof = [](const char *p) -> std::pair<const char *,size_t>
3208 {
3209 const char *q = p;
3210 while (*q==' ' || *q=='\t') q++;
3211 bool found=false;
3212 size_t size = sizeof(int); // '(signed)' or '(unsigned)' is an int type
3213 for (const auto &sgn : signs)
3214 {
3215 if (qstrncmp(q,sgn.c_str(),sgn.length())==0) { q+=sgn.length(); found=true; }
3216 }
3217 if (!found || *q==' ' || *q=='\t' || *q==')') // continue searching
3218 {
3219 while (*q==' ' || *q=='\t') q++;
3220 for (const auto &t : types)
3221 {
3222 if (qstrncmp(q,t.name.c_str(),t.name.length())==0)
3223 {
3224 q += t.name.length();
3225 size = t.size;
3226 break;
3227 }
3228 }
3229 while (*q==' ' || *q=='\t') q++;
3230 if (*q==')') return std::make_pair(++q,size);
3231 }
3232 return std::make_pair(nullptr,0);
3233 };
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition qcstring.h:75
3234
3235 //printf("removeIdsAndMarkers(%s)\n",qPrint(s));
3236 if (s.isEmpty()) return s;
3237 const char *p=s.data();
3238 bool inNum=FALSE;
3239 QCString result;
3240 if (p)
3241 {
3242 char c = 0;
3243 while ((c=*p))
3244 {
3245 if (c=='(') // potential cast, ignore it
3246 {
3247 const char *q = process_cast_or_sizeof(p+1).first;
3248 //printf("potential cast:\nin: %s\nout: %s\n",p,q);
3249 if (q)
3250 {
3251 p=q;
3252 continue;
3253 }
3254 }
3255 else if (c=='s' && literal_at(p,"sizeof")) // sizeof(...)
3256 {
3257 const char *q = p+6;
3258 while (*q==' ' || *q=='\t') q++;
3259 if (*q=='(')
3260 {
3261 auto r = process_cast_or_sizeof(q+1);
3262 //printf("sizeof:\nin: %s\nout: %zu%s\n--> sizeof=%zu\n",p,r.second,r.first,r.second);
3263 if (r.first)
3264 {
3265 result+=QCString().setNum(r.second);
3266 p=r.first;
3267 continue;
3268 }
3269 }
3270 }
QCString & setNum(short n)
Definition qcstring.h:459
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
3271
3272 if (c=='@') // replace @@ with @ and remove @E
3273 {
3274 if (*(p+1)=='@')
3275 {
3276 result+=c;
3277 }
3278 else if (*(p+1)=='E')
3279 {
3280 // skip
3281 }
3282 p+=2;
3283 }
3284 else if (isdigit(c)) // number
3285 {
3286 result+=c;
3287 p++;
3288 inNum=TRUE;
3289 }
3290 else if (c=='\'') // quoted character
3291 {
3292 p = processUntilMatchingTerminator(p,result);
3293 }
3294 else if (c=='d' && !inNum) // identifier starting with a 'd'
3295 {
3296 if (literal_at(p,"defined ") || literal_at(p,"defined("))
3297 // defined keyword
3298 {
3299 p+=7; // skip defined
3300 }
3301 else
3302 {
3303 result+="0L";
3304 p++;
3305 while ((c=*p) && isId(c)) p++;
3306 }
3307 }
3308 else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L
3309 {
3310 result+="0L";
3311 p++;
3312 while ((c=*p) && isId(c)) p++;
3313 while ((c=*p) && isspace((uint8_t)c)) p++;
3314 if (*p=='(') // undefined function macro
3315 {
3316 p++;
3317 int count=1;
3318 while ((c=*p++))
3319 {
3320 if (c=='(') count++;
3321 else if (c==')')
3322 {
3323 count--;
3324 if (count==0) break;
3325 }
3326 else if (c=='/')
3327 {
3328 char pc=c;
3329 c=*++p;
3330 if (c=='*') // start of C comment
3331 {
3332 while (*p && !(pc=='*' && c=='/')) // search end of comment
3333 {
3334 pc=c;
3335 c=*++p;
3336 }
3337 p++;
3338 }
3339 }
3340 }
3341 }
3342 }
3343 else if (c=='/') // skip C comments
3344 {
3345 char pc=c;
3346 c=*++p;
3347 if (c=='*') // start of C comment
3348 {
3349 while (*p && !(pc=='*' && c=='/')) // search end of comment
3350 {
3351 pc=c;
3352 c=*++p;
3353 }
3354 p++;
3355 }
3356 else // oops, not comment but division
3357 {
3358 result+=pc;
3359 goto nextChar;
3360 }
3361 }
3362 else
3363 {
static const char * processUntilMatchingTerminator(const char *inputStr, QCString &result)
Process string or character literal.
Definition pre.l:3149
3364nextChar:
3365 result+=c;
3366 char lc=(char)tolower(c);
3367 if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE;
3368 p++;
3369 }
3370 }
3371 }
3372 //printf("removeIdsAndMarkers(%s)=%s\n",s,qPrint(result));
3373 return result;
3374}

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

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 3380 of file pre.l.

3381{
3382 if (s.isEmpty()) return s;
3383 const char *p=s.data();
3384 QCString result;
3385 if (p)
3386 {
3387 char c = 0;
3388 while ((c=*p))
3389 {
3390 switch(c)
3391 {
3392 case '@': // replace @@ with @
3393 {
3394 if (*(p+1)=='@')
3395 {
3396 result+=c;
3397 }
3398 p+=2;
3399 }
3400 break;
3401 case '/': // skip C comments
3402 {
3403 result+=c;
3404 char pc=c;
3405 c=*++p;
3406 if (c=='*') // start of C comment
3407 {
3408 while (*p && !(pc=='*' && c=='/')) // search end of comment
3409 {
3410 if (*p=='@' && *(p+1)=='@')
3411 {
3412 result+=c;
3413 p++;
3414 }
3415 else
3416 {
3417 result+=c;
3418 }
3419 pc=c;
3420 c=*++p;
3421 }
3422 if (*p)
3423 {
3424 result+=c;
3425 p++;
3426 }
3427 }
3428 }
3429 break;
3430 case '"': // skip string literals
3431 case '\'': // skip char literals
3432 p = processUntilMatchingTerminator(p,result);
3433 break;
3434 default:
3435 {
3436 result+=c;
3437 p++;
3438 }
3439 break;
3440 }
3441 }
3442 }
3443 //printf("RemoveMarkers(%s)=%s\n",s,qPrint(result));
3444 return result;
3445}

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 2644 of file pre.l.

2645{
2646 //printf(">replaceFunctionMacro(expr='%s',rest='%s',pos=%d,def='%s') level=%zu\n",qPrint(expr),rest ? qPrint(*rest) : 0,pos,qPrint(def->name),state->levelGuard.size());
2647 uint32_t j=pos;
2648 len=0;
2649 result.clear();
2650 int cc;
2651
2652 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:2606
2653
2654 if (cc!='(')
2655 {
2656 if (cc!=':') // don't add spaces for colons
2657 {
2658 unputChar(yyscanner,expr,rest,j,' ');
2659 }
2660 return FALSE;
2661 }
2662 getNextChar(yyscanner,expr,rest,j); // eat the '(' character
2663
2664 std::map<std::string,std::string> argTable; // list of arguments
2665 QCString arg;
2666 int argCount=0;
2667 bool done=FALSE;
2668
2669 // PHASE 1: read the macro arguments
2670 if (def->nargs==0)
2671 {
2672 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2673 {
2674 char c = (char)cc;
2675 if (c==')') break;
2676 }
2677 }
2678 else
2679 {
2680 while (!done && (argCount<def->nargs || def->varArgs) &&
2681 ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2682 )
2683 {
2684 char c=(char)cc;
2685 if (c=='(') // argument is a function => search for matching )
2686 {
2687 int lvl=1;
2688 arg+=c;
2689 //char term='\0';
2690 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2691 {
2692 c=(char)cc;
2693 //printf("processing %c: term=%c (%d)\n",c,term,term);
2694 if (c=='\'' || c=='\"') // skip ('s and )'s inside strings
2695 {
2696 arg+=c;
2697 addTillEndOfString(yyscanner,expr,rest,j,c,arg);
2698 }
2699 if (c==')')
2700 {
2701 lvl--;
2702 arg+=c;
2703 if (lvl==0) break;
2704 }
2705 else if (c=='(')
2706 {
2707 lvl++;
2708 arg+=c;
2709 }
2710 else
2711 arg+=c;
2712 }
2713 }
2714 else if (c==')' || c==',') // last or next argument found
2715 {
2716 if (c==',' && argCount==def->nargs-1 && def->varArgs)
2717 {
2718 arg=arg.stripWhiteSpace();
2719 arg+=',';
2720 }
2721 else
2722 {
2723 QCString argKey;
2724 argKey.sprintf("@%d",argCount++); // key name
2725 arg=arg.stripWhiteSpace();
2726 // add argument to the lookup table
2727 argTable.emplace(toStdString(argKey), toStdString(arg));
2728 arg.clear();
2729 if (c==')') // end of the argument list
2730 {
2731 done=TRUE;
2732 }
2733 }
2734 }
2735 else if (c=='\"') // append literal strings
2736 {
2737 arg+=c;
2738 bool found=FALSE;
2739 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2740 {
2741 found = cc=='"';
2742 if (cc=='\\')
2743 {
2744 c=(char)cc;
2745 arg+=c;
2746 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2747 }
2748 c=(char)cc;
2749 arg+=c;
2750 }
2751 }
2752 else if (c=='\'') // append literal characters
2753 {
2754 arg+=c;
2755 bool found=FALSE;
2756 while (!found && (cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2757 {
2758 found = cc=='\'';
2759 if (cc=='\\')
2760 {
2761 c=(char)cc;
2762 arg+=c;
2763 if ((cc=getNextChar(yyscanner,expr,rest,j))==EOF || cc==0) break;
2764 }
2765 c=(char)cc;
2766 arg+=c;
2767 }
2768 }
2769 else if (c=='/') // possible start of a comment
2770 {
2771 char prevChar = '\0';
2772 arg+=c;
2773 if ((cc=getCurrentChar(yyscanner,expr,rest,j)) == '*') // we have a comment
2774 {
2775 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2776 {
2777 c=(char)cc;
2778 arg+=c;
2779 if (c == '/' && prevChar == '*') break; // we have an end of comment
2780 prevChar = c;
2781 }
2782 }
2783 }
2784 else // append other characters
2785 {
2786 arg+=c;
2787 }
2788 }
2789 }
static int getCurrentChar(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t pos)
Definition pre.l:3890
static void addTillEndOfString(yyscan_t yyscanner, const QCString &expr, QCString *rest, uint32_t &pos, char term, QCString &arg)
Definition pre.l:2587
2790
2791 // PHASE 2: apply the macro function
2792 if (argCount==def->nargs || // same number of arguments
2793 (argCount>=def->nargs-1 && def->varArgs)) // variadic macro with at least as many
2794 // params as the non-variadic part (see bug731985)
2795 {
2796 uint32_t k=0;
2797 // substitution of all formal arguments
2798 QCString resExpr;
2799 const QCString d=def->definition.stripWhiteSpace();
2800 //printf("Macro definition: '%s'\n",qPrint(d));
2801 bool inString=FALSE;
2802 while (k<d.length())
2803 {
2804 if (d.at(k)=='@') // maybe a marker, otherwise an escaped @
2805 {
2806 if (d.at(k+1)=='@') // escaped @ => copy it (is unescaped later)
2807 {
2808 k+=2;
2809 resExpr+="@@"; // we unescape these later
2810 }
2811 else if (d.at(k+1)=='-') // no-rescan marker
2812 {
2813 k+=2;
2814 resExpr+="@-";
2815 }
2816 else // argument marker => read the argument number
2817 {
2818 QCString key="@";
2819 bool hash=FALSE;
2820 int l=k-1;
2821 // search for ## backward
2822 if (l>=0 && d.at(l)=='"') l--;
2823 while (l>=0 && d.at(l)==' ') l--;
2824 if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE;
2825 k++;
2826 // scan the number
2827 while (k<d.length() && d.at(k)>='0' && d.at(k)<='9') key+=d.at(k++);
2828 if (!hash)
2829 {
2830 // search for ## forward
2831 l=k;
2832 if (l<(int)d.length() && d.at(l)=='"') l++;
2833 while (l<(int)d.length() && d.at(l)==' ') l++;
2834 if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE;
2835 }
2836 //printf("request key %s result %s\n",qPrint(key),argTable[key]->data());
2837 auto it = argTable.find(key.str());
2838 if (it!=argTable.end())
2839 {
2840 QCString substArg = it->second;
2841 //printf("substArg='%s'\n",qPrint(substArg));
2842 // only if no ## operator is before or after the argument
2843 // marker we do macro expansion.
2844 if (!hash)
2845 {
2846 expandExpression(yyscanner,substArg,nullptr,0,level+1);
2847 }
2848 if (inString)
2849 {
2850 //printf("'%s'=stringize('%s')\n",qPrint(stringize(*subst)),subst->data());
2851
2852 // if the marker is inside a string (because a # was put
2853 // before the macro name) we must escape " and \ characters
2854 resExpr+=stringize(substArg);
2855 }
2856 else
2857 {
2858 if (hash && substArg.isEmpty())
2859 {
2860 resExpr+="@E"; // empty argument will be remove later on
2861 }
2862 resExpr+=substArg;
2863 }
2864 }
2865 }
2866 }
2867 else // no marker, just copy
2868 {
2869 if (!inString && d.at(k)=='\"')
2870 {
2871 inString=TRUE; // entering a literal string
2872 }
2873 else if (k>2 && inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\'))
2874 {
2875 inString=FALSE; // leaving a literal string
2876 }
2877 resExpr+=d.at(k++);
2878 }
2879 }
2880 len=j-pos;
2881 result=resExpr;
2882 //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),state->levelGuard.size());
2883 return TRUE;
2884 }
2885 //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),state->levelGuard.size());
2886 return FALSE;
static QCString stringize(const QCString &s)
Definition pre.l:2456
2887}

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

Referenced by expandExpression().

◆ resolveTrigraph()

char resolveTrigraph ( char c)
static

Definition at line 3847 of file pre.l.

3848{
3849 switch (c)
3850 {
3851 case '=': return '#';
3852 case '/': return '\\';
3853 case '\'': return '^';
3854 case '(': return '[';
3855 case ')': return ']';
3856 case '!': return '|';
3857 case '<': return '{';
3858 case '>': return '}';
3859 case '-': return '~';
3860 }
3861 return '?';
3862}

◆ returnCharToStream()

void returnCharToStream ( yyscan_t yyscanner,
char c )
static

Definition at line 2581 of file pre.l.

2582{
2583 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
2584 unput(c);
2585}

Referenced by getCurrentChar(), and unputChar().

◆ setCaseDone()

void setCaseDone ( yyscan_t yyscanner,
bool value )
static

Definition at line 2268 of file pre.l.

2269{
2270 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2271 state->levelGuard.top()=value;
2272}

◆ setFileName()

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

Definition at line 2212 of file pre.l.

2213{
2214 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2215 bool ambig = false;
2216 FileInfo fi(name.str());
2217 state->fileName=fi.absFilePath();
2218 state->yyFileDef=findFileDef(Doxygen::inputNameLinkedMap,state->fileName,ambig);
2219 if (state->yyFileDef==nullptr) // if this is not an input file check if it is an include file
2220 {
2221 state->yyFileDef=findFileDef(Doxygen::includeNameLinkedMap,state->fileName,ambig);
2222 }
2223 //printf("setFileName(%s) state->fileName=%s state->yyFileDef=%p\n",
2224 // name,qPrint(state->fileName),state->yyFileDef);
2225 if (state->yyFileDef && state->yyFileDef->isReference()) state->yyFileDef=nullptr;
2226 state->insideIDL = getLanguageFromFileName(state->fileName)==SrcLangExt::IDL;
2227 state->insideCS = getLanguageFromFileName(state->fileName)==SrcLangExt::CSharp;
2228 state->insideFtn = getLanguageFromFileName(state->fileName)==SrcLangExt::Fortran;
2229 EntryType section = guessSection(state->fileName);
2230 state->isSource = section.isHeader() || section.isSource();
static FileNameLinkedMap * includeNameLinkedMap
Definition doxygen.h:102
Wrapper class for the Entry type.
Definition types.h:813
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5147
EntryType guessSection(const QCString &name)
Definition util.cpp:340
2231}

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 2606 of file pre.l.

2608{
2609 bool changed = false;
2610
2611 do
2612 {
2613 changed = false;
2614 while ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc!='\n' && isspace(cc))
2615 {
2616 len++;
2617 getNextChar(yyscanner,expr,rest,j);
2618 }
2619
2620 if (cc=='/') // possible start of a comment
2621 {
2622 int prevChar = '\0';
2623 getNextChar(yyscanner,expr,rest,j);
2624 if ((cc=getCurrentChar(yyscanner,expr,rest,j))!=EOF && cc == '*') // we have a comment
2625 {
2626 while ((cc=getNextChar(yyscanner,expr,rest,j))!=EOF && cc!=0)
2627 {
2628 if (cc == '/' && prevChar == '*') break; // we have an end of comment
2629 prevChar = cc;
2630 }
2631 if (cc != EOF) changed = true;
2632 }
2633 }
2634 } while (changed);
2635}

References getCurrentChar(), and getNextChar().

Referenced by replaceFunctionMacro().

◆ startCondSection()

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

Definition at line 3791 of file pre.l.

3792{
3793 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
3794 //printf("startCondSection: skip=%d stack=%d\n",state->skip,state->condStack.size());
3795 CondParser prs;
3796 bool expResult = prs.parse(state->fileName.data(),state->yyLineNr,sectId.data());
3797 state->condStack.emplace(std::make_unique<preYY_CondCtx>(state->fileName,state->yyLineNr,sectId,state->skip));
3798 if (!expResult)
3799 {
3800 state->skip=TRUE;
3801 }
3802 //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.
3803}

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

◆ stateToString()

const char * stateToString ( int state)
static

◆ stringize()

QCString stringize ( const QCString & s)
static

Definition at line 2456 of file pre.l.

2457{
2458 QCString result;
2459 uint32_t i=0;
2460 bool inString=FALSE;
2461 bool inChar=FALSE;
2462 char c,pc;
2463 while (i<s.length())
2464 {
2465 if (!inString && !inChar)
2466 {
2467 while (i<s.length() && !inString && !inChar)
2468 {
2469 c=s.at(i++);
2470 if (c=='"')
2471 {
2472 result+="\\\"";
2473 inString=TRUE;
2474 }
2475 else if (c=='\'')
2476 {
2477 result+=c;
2478 inChar=TRUE;
2479 }
2480 else
2481 {
2482 result+=c;
2483 }
2484 }
2485 }
2486 else if (inChar)
2487 {
2488 while (i<s.length() && inChar)
2489 {
2490 c=s.at(i++);
2491 if (c=='\'')
2492 {
2493 result+='\'';
2494 inChar=FALSE;
2495 }
2496 else if (c=='\\')
2497 {
2498 result+="\\\\";
2499 }
2500 else
2501 {
2502 result+=c;
2503 }
2504 }
2505 }
2506 else
2507 {
2508 pc=0;
2509 while (i<s.length() && inString)
2510 {
2511 c=s.at(i++);
2512 if (c=='"')
2513 {
2514 result+="\\\"";
2515 inString= pc=='\\';
2516 }
2517 else if (c=='\\')
2518 result+="\\\\";
2519 else
2520 result+=c;
2521 pc=c;
2522 }
2523 }
2524 }
2525 //printf("stringize '%s'->'%s'\n",qPrint(s),qPrint(result));
2526 return result;
2527}

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

Referenced by replaceFunctionMacro().

◆ unputChar()

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

Definition at line 3913 of file pre.l.

3914{
3915 //printf("unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
3916 if (pos<expr.length())
3917 {
3918 pos++;
3919 }
3920 else if (rest)
3921 {
3922 //printf(" prepending '%c' to rest!\n",c);
3923 char cs[2];cs[0]=c;cs[1]='\0';
3924 rest->prepend(cs);
3925 }
3926 else
3927 {
3928 //printf(" yyunput()='%c'\n",c);
3929 returnCharToStream(yyscanner,c);
3930 }
3931 //printf("result: unputChar(%s,%s,%d,%c)\n",qPrint(expr),rest ? rest->data() : 0,pos,c);
QCString & prepend(const char *s)
Definition qcstring.h:422
3932}

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

Referenced by addSeparatorsIfNeeded(), and replaceFunctionMacro().

◆ yylex()

int yylex ( yyscan_t yyscanner)

Definition at line 485 of file pre.l.

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

◆ yyread()

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

Definition at line 2191 of file pre.l.

2192{
2193 YY_EXTRA_TYPE state = preYYget_extra(yyscanner);
2194 int bytesInBuf = static_cast<int>(state->inputBuf->size())-state->inputBufPos;
2195 int bytesToCopy = std::min(max_size,bytesInBuf);
2196 memcpy(buf,state->inputBuf->data()+state->inputBufPos,bytesToCopy);
2197 state->inputBufPos+=bytesToCopy;
2198 return bytesToCopy;
2199}

Variable Documentation

◆ g_debugMutex

std::mutex g_debugMutex
static

Definition at line 233 of file pre.l.

Referenced by Preprocessor::processFile().

◆ g_defineManager

DefineManager g_defineManager
static

Definition at line 236 of file pre.l.

Referenced by checkAndOpenFile(), and readIncludeFile().

◆ g_globalDefineMutex

std::mutex g_globalDefineMutex
static

Definition at line 234 of file pre.l.

Referenced by checkAndOpenFile(), and readIncludeFile().

◆ g_updateGlobals

std::mutex g_updateGlobals
static

Definition at line 235 of file pre.l.

Referenced by Preprocessor::processFile().