/****************************************************************************** * * $Id$ * * Copyright (C) 1997-1999 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * All output generated with Doxygen is not covered by this license. * */ %{ /* * includes */ #include #include #include #include #include #include #include #include #include #include #include #include "constexp.h" #include "define.h" #include "doxygen.h" #include "message.h" #include "util.h" #if defined(_MSC_VER) #define popen _popen #define pclose _pclose #endif #define YY_NEVER_INTERACTIVE 1 #define DUMP_OUTPUT 0 // set this to one to see what the preprocessor // produces. #define SHOW_INCLUDES 0 // set this to one to list all parsed include files struct FileState { int lineNr; FILE *filePtr; YY_BUFFER_STATE bufState; QString fileName; }; /* ----------------------------------------------------------------- * * statics */ static int yyLineNr = 1; static QString yyFileName; static int ifcount = 0; static QStrList *pathList = 0; static QStack includeStack; static QDict *argDict; static int defArgs = 0; static QString defName; static QString defText; static QString defArgsStr; static bool defVarArgs; static int level; static int lastCContext; static int lastCPPContext; static QArray levelGuard; static QString guardExpr; static BufStr *outputBuf; //static DefineCache *fileDefineCache; static int roundCount; //static const Define *expandDefine; static bool quoteArg; static DefineDict *fileDefineDict; static DefineDict *expandedDict; static int findDefArgContext; static void incrLevel() { level++; levelGuard.resize(level); levelGuard[level-1]=FALSE; //printf("%s line %d: incrLevel %d\n",yyFileName.data(),yyLineNr,level); } static void decrLevel() { //printf("%s line %d: decrLevel %d\n",yyFileName.data(),yyLineNr,level); if (level > 0) { level--; levelGuard.resize(level); } else { err("Error: More #endif's than #if's found.\n"); } } static bool otherCaseDone() { return levelGuard[level-1]; } static void setCaseDone(bool value) { levelGuard[level-1]=value; } static Define *isDefined(const char *name) { if (name) { Define *def; //if ((def=fileDefineCache->findDefine(yyFileName,name)) && !def->undef) // return def; if ((def=fileDefineDict->find(name)) && !def->undef) return def; } return 0; } static FILE *findFile(const char *fileName) { if (pathList==0) { return 0; } char *s=pathList->first(); while (s) { QString absName=(QString)s+"/"+fileName; QFileInfo fi(absName); if (fi.exists()) { FILE *f; if (!inputFilter.isEmpty()) { QString cmd = inputFilter+" "+absName; f=popen(cmd,"r"); if (!f) warn("Warning: could not execute filter %s\n",cmd.data()); } else { f=fopen(absName,"r"); if (!f) warn("Warning: could not open file %s for reading\n",absName.data()); } if (f) { yyFileName=absName; yyLineNr=1; return f; } } s=pathList->next(); } return 0; } static int getNextChar(const QString &expr,QString *rest,uint &pos); static int getCurrentChar(const QString &expr,QString *rest,uint pos); static void unputChar(const QString &expr,QString *rest,uint &pos,char c); static void expandExpression(QString &expr,QString *rest,int pos); static QString stringize(const QString &s) { QString result; uint i=0; bool inString=FALSE; bool inChar=FALSE; char c,pc; while (i`%s'\n",s.data(),result.data()); return result; } /*! 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. */ static void processConcatOperators(QString &expr) { QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); int l,n,i=0; while ((n=r.match(expr,i,&l))!=-1) { if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-') { // remove no-rescan marker after ID l+=2; } // remove the ## operator and the surrounding whitespace expr=expr.left(n)+expr.right(expr.length()-n-l); int k=n-1; while (k>=0 && isId(expr.at(k))) k--; if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@') { // remove no-rescan marker before ID expr=expr.left(k-1)+expr.right(expr.length()-k-1); n-=2; } i=n+l; } } /*! replaces the function macro \a def whose argument list starts at * \a pos in expression \a expr. * Notice that this routine may scan beyond the \a expr string if needed. * The characters from the input file will be read. * The replacement string will be returned in \a result and the * length of the (unexpanded) argument list is stored in \a len. */ static bool replaceFunctionMacro(const QString &expr,QString *rest,int pos,int &len,const Define *def,QString &result) { //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),level); //bool replaced=FALSE; uint j=pos; len=0; result.resize(0); int cc; // TODO: use a checkNextChar function. //while ((cc=getNextChar(expr,rest,j))!=EOF && cc==' ') len++; //if (cc!='(') return FALSE; while ((cc=getCurrentChar(expr,rest,j))!=EOF && cc==' ') { len++; getNextChar(expr,rest,j); } if (cc!='(') { unputChar(expr,rest,j,' '); return FALSE; } getNextChar(expr,rest,j); // eat the `(' character //while (j argTable; // list of arguments argTable.setAutoDelete(TRUE); QString arg; int argCount=0; bool done=FALSE; // FASE 1: read the macro arguments while ((argCountnargs || def->varArgs) && ((cc=getNextChar(expr,rest,j))!=EOF) && !done ) { char c=(char)cc; if (c=='(') // argument is a function => search for matching ) { int level=1; arg+=c; char term='\0'; while ((cc=getNextChar(expr,rest,j))!=EOF) { char c=(char)cc; if (c=='\'' || c=='\"') // skip ('s and )'s inside strings { if (term!='\0') { if (c==term && expr.at(j-2)!='\\') term='\0'; } else { term=c; } } if (term=='\0' && c==')') { level--; arg+=c; if (level==0) break; } else if (term=='\0' && c=='(') { level++; arg+=c; } else arg+=c; } } else if (c==')' || c==',') // last or next argument found { if (c==',' && argCount==def->nargs-1 && def->varArgs) { arg=arg.stripWhiteSpace(); arg+=','; } else { QString argKey; argKey.sprintf("@%d",argCount++); // key name arg=arg.stripWhiteSpace(); // add argument to the lookup table argTable.insert(argKey, new QString(arg)); arg.resize(0); if (c==')') // end of the argument list { done=TRUE; } } } else if (c=='\"') // append literal strings { arg+=c; char pc=c; bool found=FALSE; while (!found && (cc=getNextChar(expr,rest,j))!=EOF) { found = pc!='\\' && cc=='"'; c=(char)cc; pc=c; arg+=c; } } else if (c=='\'') // append literal characters { arg+=c; char pc=c; bool found=FALSE; while (!found && (cc=getNextChar(expr,rest,j))!=EOF) { found = pc!='\\' && cc=='\''; c=(char)cc; pc=c; arg+=c; } } else // append other characters { arg+=c; } } // FASE 2: apply the macro function if (argCount==def->nargs || (argCount>def->nargs && def->varArgs)) // matching parameters lists { uint k=0; // substitution of all formal arguments QString resExpr; const QString d=def->definition.stripWhiteSpace(); bool inString=FALSE; while (k copy it (is unescaped later) { k+=2; resExpr+="@@"; // we unescape these later } else if (d.at(k+1)=='-') // no-rescan marker { k+=2; resExpr+="@-"; } else // argument marker => read the argument number { QString key="@"; QString *subst=0; bool hash=FALSE; int l=k-1; // search for ## backward if (l>=0 && d.at(l)=='"') l--; while (l>=0 && d.at(l)==' ') l--; if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE; k++; // scan the number while (k='0' && d.at(k)<='9') key+=d.at(k++); if (!hash) { // search for ## forward l=k; if (l<(int)d.length() && d.at(l)=='"') l++; while (l<(int)d.length() && d.at(l)==' ') l++; if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE; } //printf("request key %s result %s\n",key.data(),args[key]->data()); if (key.length()>1 && (subst=argTable[key])) { QString substArg=*subst; // only if no ## operator is before or after the argument // marker we do macro expansion. if (!hash) expandExpression(substArg,0,0); if (inString) { //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data()); // if the marker is inside a string (because a # was put // before the macro name) we must escape " and \ characters resExpr+=stringize(substArg); } else { resExpr+=substArg; } } } } else // no marker, just copy { if (!inString && d.at(k)=='\"') { inString=TRUE; // entering a literal string } else if (inString && d.at(k)=='\"' && d.at(k-1)!='\\') { inString=FALSE; // leaving a literal string } resExpr+=d.at(k++); } } len=j-pos; result=resExpr; //printf("result after substitution `%s' expr=`%s'\n", // result.data(),expr.mid(pos,len).data()); return TRUE; } else { return FALSE; } } /*! returns the next identifier in string \a expr by starting at position \a p. * The position of the identifier is returned (or -1 if nothing is found) * and \a l is its length. Any quoted strings are skipping during the search. */ static int getNextId(const QString &expr,int p,int *l) { int n; while (p<(int)expr.length()) { char c=expr.at(p++); if (isalpha(c) || c=='_') // read id { n=p-1; while (p<(int)expr.length() && isId(expr.at(p)) ) p++; *l=p-n; return n; } else if (c=='"') // skip string { char pc=c; if (p<(int)expr.length()) c=expr.at(p); while (p<(int)expr.length() && (c!='"' || pc=='\\')) { pc=c; c=expr.at(p); p++; } } } return -1; } /*! preforms recursive macro expansion on the string \a expr * starting at position \a pos. * May read additional characters from the input while re-scanning! * If \a expandAll is \c TRUE then all macros in the expression are * expanded, otherwise only the first is expanded. */ static void expandExpression(QString &expr,QString *rest,int pos) { //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0); QString macroName; QString expMacro; int i=pos,l,p,len; while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name { bool replaced=FALSE; macroName=expr.mid(p,l); //printf("macroName %s found\n",macroName.data()); if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker? { if (expandedDict->find(macroName)==0) // expand macro { Define *def=isDefined(macroName); //printf("name is not an expanded macro def=%s\n",def ? def->name.data() : 0); if (def && def->nargs==0) // simple macro { // substitute the definition of the macro expMacro=def->definition.stripWhiteSpace(); replaced=TRUE; len=l; //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data()); } else if (def && def->nargs>0) // function macro { replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro); len+=l; } if (replaced) // expand the macro and rescan the expression { //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data()); QString resultExpr=expMacro; QString restExpr=expr.right(expr.length()-len-p); processConcatOperators(resultExpr); expandedDict->insert(macroName,def); expandExpression(resultExpr,&restExpr,0); expandedDict->remove(macroName); expr=expr.left(p)+resultExpr+restExpr; i=p; //printf("new expression: %s\n",expr.data()); } else // move to the next macro name { //printf("moving to the next macro old=%d new=%d\n",i,p+l); i=p+l; } } else // move to the next macro name { expr=expr.left(p)+"@-"+expr.right(expr.length()-p); //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data()); i=p+l+2; //i=p+l; } } else // no re-scan marker found, skip the macro name { //printf("skipping marked macro\n"); i=p+l; } } } /*! replaces all occurrences of @@ in \a s by @ * All identifiers found are replaced by 0L * \par assumption: * \a s only contains pairs of @@'s. */ QString removeIdsAndMarkers(const char *s) { //printf("removeIdsAndMarkers(%s)\n",s); const char *p=s; char c; bool inNum=FALSE; QString result; if (p) { while ((c=*p)) { if (c=='@') // replace @@ with @ { if (*(p+1)=='@') { result+=c; } p+=2; } else if (isdigit(c)) { result+=c; p++; inNum=TRUE; } else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L { result+="0L"; p++; while ((c=*p) && isId(c)) p++; } else { result+=c; char lc=tolower(c); if (lc!='l' && lc!='u') inNum=FALSE; p++; } } } return result; } /*! replaces all occurrences of @@ in \a s by @ * \par assumption: * \a s only contains pairs of @@'s */ QString removeMarkers(const char *s) { const char *p=s; char c; QString result; if (p) { while ((c=*p)) { if (c=='@') // replace @@ with @ { if (*(p+1)=='@') { result+=c; } p+=2; } else { result+=c; p++; } } } return result; } /*! compute the value of the expression in string \a expr. * If needed the function may read additional characters from the input. */ bool computeExpression(const QString &expr) { QString e=expr; expandExpression(e,0,0); e = removeIdsAndMarkers(e); if (e.length()==0) return FALSE; //printf("computeExpession(%s)\n",e.data()); return parseCppExpression(e); } /*! expands the macro definition in \a name * If needed the function may read additional characters from the input */ QString expandMacro(const QString &name) { QString n=name; expandExpression(n,0,0); n=removeMarkers(n); //printf("expandMacro `%s'->`%s'\n",name.data(),n.data()); return n; } Define *newDefine() { Define *def=new Define; def->name = defName; def->definition = defText.stripWhiteSpace(); def->nargs = defArgs; def->fileName = yyFileName; def->lineNr = yyLineNr; def->varArgs = defVarArgs; return def; } void addDefine() { bool ambig; FileDef *fd=findFileDef(&inputNameDict,yyFileName,ambig); MemberDef *md=new MemberDef("#define",defName,defArgsStr,0, Public,Normal,FALSE,FALSE,MemberDef::Define,0,0); md->setDefFile(yyFileName); md->setDefLine(yyLineNr); md->setFileDef(fd); md->setDefinition("#define "+defName+defArgsStr); MemberName *mn=functionNameDict[defName]; if (mn==0) { mn = new MemberName(defName); functionNameList.inSort(mn); functionNameDict.insert(defName,mn); } mn->append(md); if (fd) fd->insertMember(md); Define *d; if ((d=defineDict[defName])==0) defineDict.insert(defName,newDefine()); } static void outputChar(char c) { if (includeStack.isEmpty()) outputBuf->addChar(c); } static void outputArray(const char *a,int len) { if (includeStack.isEmpty()) outputBuf->addArray(a,len); } static void readIncludeFile(const QString &inc) { if (!searchIncludeFlag) return; // do not read include files uint i=0; // find the start of the include file name while (is) // valid include file name found { QString incFileName=inc.mid(s,i-s).stripWhiteSpace(); FILE *f; QString oldFileName=yyFileName.copy(); if ((f=findFile(incFileName))) // see if the include file can be found { #if SHOW_INCLUDES for (i=0;ibufState=YY_CURRENT_BUFFER; fs->lineNr=yyLineNr; fs->fileName=oldFileName; fs->filePtr=f; // push the state on the stack includeStack.push(fs); // set the scanner to the include file preYYin=f; yy_switch_to_buffer(yy_create_buffer(preYYin, YY_BUF_SIZE)); } else { #if SHOW_INCLUDES msg("#include %s: not found! skipping...\n",incFileName.data()); //printf("Error: include file %s not found\n",yytext); #endif } } } /* ----------------------------------------------------------------- */ %} ID [a-z_A-Z][a-z_A-Z0-9]* B [ \t] BN [ \t\r\n] %x Start %x Command %x SkipCommand %x SkipLine %x CopyLine %x Include %x IncludeID %x DefineName %x DefineArg %x DefineText %x SkipCPPBlock %x Ifdef %x Ifndef %x SkipCComment %x SkipCPPComment %x RemoveCComment %x RemoveCPPComment %x Guard %x DefinedExpr1 %x DefinedExpr2 %x SkipDoubleQuote %x SkipSingleQuote %x UndefName %x IgnoreLine %x FindDefineArgs %x ReadString %% <*>\x06 <*>\x00 <*>\r /* ^{B}*([^ \t#\n\/][^\n]*)?"\n" { //printf("%s line %d: %s",yyFileName.data(),yyLineNr,yytext); if (includeStack.isEmpty()) { //preprocessedFile+=yytext; //char *s=yytext,c; //if (s) while ((c=*s++)) *dataPtr++=c; outputBuf->addArray(yytext,yyleng); } yyLineNr++; } */ ^{B}*"#" { BEGIN(Command); } ^{B}*/[^#] { outputArray(yytext,yyleng); BEGIN(CopyLine); } /* [^\n/]+ { outputArray(yytext,yyleng); } */ {ID}/{BN}*"(" { if (includeStack.isEmpty() && macroExpansionFlag && /* (expandDefine=fileDefineCache->findDefine(yyFileName,yytext)) */ fileDefineDict->find(yytext) ) { roundCount=0; defArgsStr=yytext; findDefArgContext = CopyLine; BEGIN(FindDefineArgs); } else { outputArray(yytext,yyleng); } } {ID} { Define *def=0; if (includeStack.isEmpty() && macroExpansionFlag && (def=fileDefineDict->find(yytext)) && def->nargs==0 ) { QString name=yytext; QString result=expandMacro(name); outputArray(result,result.length()); } else { outputArray(yytext,yyleng); } } . { outputChar(*yytext); } \n { outputChar('\n'); BEGIN(Start); yyLineNr++; } "(" { defArgsStr+='('; roundCount++; } ")" { defArgsStr+=')'; roundCount--; if (roundCount==0) { QString result=expandMacro(defArgsStr); if (findDefArgContext==CopyLine) { outputArray(result,result.length()); BEGIN(findDefArgContext); } else // findDefArgContext==IncludeID { readIncludeFile(result); BEGIN(Start); } } } /* ")"{B}*"(" { defArgsStr+=yytext; } */ "\"" { defArgsStr+=*yytext; BEGIN(ReadString); } \n { yyLineNr++; outputChar('\n'); } "@" { defArgsStr+="@@"; } . { defArgsStr+=*yytext; } "\\\"" { defArgsStr+=yytext; } "\"" { defArgsStr+=*yytext; BEGIN(FindDefineArgs); } . { defArgsStr+=*yytext; } "include"{B}*/{ID} { if (macroExpansionFlag) BEGIN(IncludeID); } "include"{B}*[<"] { BEGIN(Include); } "define"{B}+ { //printf("!!!DefineName\n"); BEGIN(DefineName); } "ifdef"/{B}*"(" { incrLevel(); guardExpr.resize(0); BEGIN(DefinedExpr2); } "ifdef"/{B}+ { //printf("Pre.l: ifdef\n"); incrLevel(); guardExpr.resize(0); BEGIN(DefinedExpr1); } "ifndef"/{B}*"(" { incrLevel(); guardExpr="! "; BEGIN(DefinedExpr2); } "ifndef"/{B}+ { incrLevel(); guardExpr="! "; BEGIN(DefinedExpr1); } "if"/[ \t(] { incrLevel(); guardExpr.resize(0); BEGIN(Guard); } "elif"/[ \t(] { if (!otherCaseDone()) { guardExpr.resize(0); BEGIN(Guard); } else { ifcount=0; BEGIN(SkipCPPBlock); } } "else"/[^a-z_A-Z0-9] { //printf("else levelGuard[%d]=%d\n",level-1,levelGuard[level-1]); if (otherCaseDone()) { ifcount=0; BEGIN(SkipCPPBlock); } else { setCaseDone(TRUE); //levelGuard[level-1]=TRUE; } } "undef"{B}+ { BEGIN(UndefName); } "elif"/[ \t(] { if (!otherCaseDone()) { guardExpr.resize(0); BEGIN(Guard); } } "endif"/[^a-z_A-Z0-9] { //printf("Pre.l: #endif\n"); decrLevel(); } \n { outputChar('\n'); BEGIN(Start); yyLineNr++; } {ID} { // unknown directive BEGIN(IgnoreLine); } . . {ID} { Define *def; if ((def=isDefined(yytext))) { //printf("undefining %s\n",yytext); def->undef=TRUE; } BEGIN(Start); } \\\n { outputChar('\n'); guardExpr+=' '; yyLineNr++; } "defined"/{B}*"(" { BEGIN(DefinedExpr2); } "defined"/{B}+ { BEGIN(DefinedExpr1); } . { guardExpr+=*yytext; } \n { outputChar('\n'); yyLineNr++; //printf("Guard: `%s'\n", // guardExpr.data()); bool guard=computeExpression(guardExpr); setCaseDone(guard); //printf("if levelGuard[%d]=%d\n",level-1,levelGuard[level-1]); if (guard) { BEGIN(Start); } else { ifcount=0; BEGIN(SkipCPPBlock); } } \\\n { yyLineNr++; outputChar('\n'); } {ID} { if (isDefined(yytext)) guardExpr+=" 1L "; else guardExpr+=" 0L "; BEGIN(Guard); } {ID} { if (isDefined(yytext)) guardExpr+=" 1L "; else guardExpr+=" 0L "; } \n { // should not happen, handle anyway ifcount=0; BEGIN(SkipCPPBlock); } ")" { BEGIN(Guard); } . ^{B}*"#" { BEGIN(SkipCommand); } ^{B}*/[^#] { BEGIN(SkipLine); } . "if"(("n")?("def"))?/[ \t(] { incrLevel(); ifcount++; //printf("#if... depth=%d\n",ifcount); } "else"/[^a-z_A-Z0-9] { //printf("Else! ifcount=%d otherCaseDone=%d\n",ifcount,otherCaseDone()); if (ifcount==0 && !otherCaseDone()) { setCaseDone(TRUE); //outputChar('\n'); BEGIN(Start); } } "elif"/[ \t(] { if (ifcount==0) { if (!otherCaseDone()) { guardExpr.resize(0); BEGIN(Guard); } else { BEGIN(Start); } } } "endif"/[^a-z_A-Z0-9] { decrLevel(); if (--ifcount<0) { //outputChar('\n'); BEGIN(Start); } } \n { outputChar('\n'); yyLineNr++; BEGIN(SkipCPPBlock); } {ID} { // unknown directive BEGIN(SkipLine); } . [^/\n]+ . "//" { lastCPPContext=YY_START; BEGIN(RemoveCPPComment); } "/*" { lastCContext=YY_START; BEGIN(RemoveCComment); } \n { outputChar('\n'); yyLineNr++; BEGIN(SkipCPPBlock); } {ID}{B}*/"(" { roundCount=0; defArgsStr=yytext; findDefArgContext = IncludeID; BEGIN(FindDefineArgs); } {ID} { readIncludeFile(expandMacro(yytext)); BEGIN(Start); } [^\">\n]+[\">] { QString incName=yytext; //int l=incName.length(); //QString incFileName=incName.left(l-1); //if (fileDefineCache->fileCached(incFileName)) //{ // printf("file already cached!\n"); // fileDefineCache->merge(incFileName,yyFileName); //} //else if ((f=findFile(incFileName))) readIncludeFile(incName); BEGIN(Start); } {ID}/"(" { //printf("Define() `%s'\n",yytext); argDict = new QDict(31); argDict->setAutoDelete(TRUE); defArgs = 0; defArgsStr.resize(0); defText.resize(0); defName = yytext; defVarArgs = FALSE; BEGIN(DefineArg); } {ID}/{B}* { //printf("Define `%s'\n",yytext); argDict = 0; defArgs = 0; defArgsStr.resize(0); defText.resize(0); defName = yytext; defVarArgs = FALSE; QString tmp=(QString)"#define "+defName+defArgsStr; outputArray(tmp.data(),tmp.length()); quoteArg=FALSE; BEGIN(DefineText); } ","{B}* { defArgsStr+=yytext; } "("{B}* { defArgsStr+=yytext; } ")"{B}* { defArgsStr+=yytext; QString tmp=(QString)"#define "+defName+defArgsStr; outputArray(tmp.data(),tmp.length()); quoteArg=FALSE; BEGIN(DefineText); } {ID}("..."?) { //printf("Define addArg(%s)\n",yytext); QString argName=yytext; defVarArgs = yytext[yyleng-1]=='.'; if (defVarArgs) argName=argName.left(argName.length()-3); defArgsStr+=yytext; argDict->insert(argName,new int(defArgs)); defArgs++; } "/*" { outputChar('/');outputChar('*'); defText+=' '; lastCContext=YY_START; BEGIN(SkipCComment); } "//" { outputChar('/');outputChar('/'); lastCPPContext=YY_START; BEGIN(SkipCPPComment); } "*/" { outputChar('*');outputChar('/'); BEGIN(lastCContext); } "//" { outputChar('/');outputChar('/'); } "/*" { outputChar('/');outputChar('*'); } [^*\n]+ { outputArray(yytext,yyleng); } \n { yyLineNr++; outputChar('\n'); } . { outputChar(*yytext); } "*/" { BEGIN(lastCContext); } "//" "/*" [^*\n]+ \n { yyLineNr++; outputChar('\n'); } . \n { unput(*yytext); BEGIN(lastCPPContext); } "/*" { outputChar('/');outputChar('*'); } "//" { outputChar('/');outputChar('/'); } [^\n]+ { outputArray(yytext,yyleng); } . { outputChar(*yytext); } "/*" "//" [^\n]+ . "#" { quoteArg=TRUE; } {ID} { //bool quote=FALSE; //char *p=yytext; //if (p[0]=='#') //{ // p++; // quote=TRUE; // defText+="\""; //} if (quoteArg) { defText+="\""; } if (defArgs>0) { int *n; if ((n=(*argDict)[yytext])) { if (!quoteArg) defText+=' '; defText+='@'; QString numStr; numStr.setNum(*n); defText+=numStr; if (!quoteArg) defText+=' '; } else { defText+=yytext; } } else { defText+=yytext; } if (quoteArg) { defText+="\""; } quoteArg=FALSE; } \\\n { outputChar('\n'); defText += ' '; yyLineNr++; } \n { outputChar('\n'); Define *def=0; //printf("Define name=`%s' text=`%s'\n",defName.data(),defText.data()); if (includeStack.isEmpty()) addDefine(); if (!onlyPredefinedFlag && (def=fileDefineDict->find(defName))==0) { fileDefineDict->insert(defName,newDefine()); } //if ((def=fileDefineCache->findDefine(yyFileName,defName))==0) //{ // printf("define is not found\n"); // fileDefineCache->insertDefine(yyFileName,defName,newDefine()); //} else if (def)// name already exists { //printf("define found\n"); if (def->undef) // undefined name { def->undef = FALSE; def->name = defName; def->definition = defText.stripWhiteSpace(); def->nargs = defArgs; def->fileName = yyFileName; def->lineNr = yyLineNr; } else { //printf("Error: define %s is defined more than once!\n",defName.data()); } } delete argDict; yyLineNr++; BEGIN(Start); } {B}* { defText += ' '; } {B}*"##"{B}* { defText += "##"; } "@" { defText += "@@"; } \" { defText += *yytext; BEGIN(SkipDoubleQuote); } \' { defText += *yytext; BEGIN(SkipSingleQuote); } \" { defText += *yytext; BEGIN(DefineText); } \' { defText += *yytext; BEGIN(DefineText); } . { defText += *yytext; } . { defText += *yytext; } . { defText += *yytext; } <> { //printf("End of include file\n"); //printf("Include stack depth=%d\n",includeStack.count()); if (includeStack.isEmpty()) { //printf("Terminating scanner!\n"); yyterminate(); } else { FileState *fs=includeStack.pop(); //fileDefineCache->merge(yyFileName,fs->fileName); if (inputFilter.isEmpty()) fclose(fs->filePtr); else pclose(fs->filePtr); YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; yy_switch_to_buffer( fs->bufState ); yy_delete_buffer( oldBuf ); yyLineNr=fs->lineNr; yyFileName=fs->fileName.copy(); //printf("######## FileName %s\n",yyFileName.data()); delete fs; } } <*>"/*" { outputChar('/');outputChar('*'); lastCContext=YY_START; BEGIN(SkipCComment); } <*>"//" { outputChar('/');outputChar('/'); lastCPPContext=YY_START; BEGIN(SkipCPPComment); } <*>\n { outputChar('\n'); yyLineNr++; } <*>. { outputChar(*yytext); } %% /*@ ---------------------------------------------------------------------------- */ static int getNextChar(const QString &expr,QString *rest,uint &pos) { //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); if (poslength()>0) { int cc=rest->at(0); *rest=rest->right(rest->length()-1); //printf("%c=rest\n",cc); return cc; } else { int cc=yyinput(); //printf("%c=yyinput()\n",cc); return cc; } } static int getCurrentChar(const QString &expr,QString *rest,uint pos) { //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); if (poslength()>0) { int cc=rest->at(0); //printf("%c=rest\n",cc); return cc; } else { int cc=yyinput();unput(cc); //printf("%c=yyinput()\n",cc); return cc; } } static void unputChar(const QString &expr,QString *rest,uint &pos,char c) { //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); if (posprepend(cs); } else { unput(c); } //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); } void addSearchDir(const char *dir) { QFileInfo fi(dir); if (fi.isDir()) pathList->append(fi.absFilePath()); } void initPreprocessor() { pathList = new QStrList; addSearchDir("."); //defineNameList.setAutoDelete(TRUE); //defineNameList.clear(); defineDict.clear(); //fileDefineCache = new DefineCache(1009); expandedDict = new DefineDict(17); fileDefineDict = new DefineDict(1009); } void cleanupPreprocessor() { //delete fileDefineCache; delete fileDefineDict; delete expandedDict; delete pathList; } void preprocessFile(const char *fileName,BufStr &output) { #if DUMP_OUTPUT uint orgOffset=output.curPos(); #endif outputBuf=&output; includeStack.setAutoDelete(TRUE); includeStack.clear(); fileDefineDict->setAutoDelete(TRUE); fileDefineDict->clear(); expandedDict->setAutoDelete(FALSE); expandedDict->clear(); // add predefined macros char *defStr = predefined.first(); while (defStr) { QString ds = defStr; int i; if ((i=ds.find('='))==-1) { if (ds.length()>0) { Define *def = new Define; def->name = ds; def->definition = "1"; def->nargs = 0; fileDefineDict->insert(ds,def); } } else { if (i>0 && (int)ds.length()>i) { Define *def = new Define; def->name = ds.left(i); def->definition = ds.right(ds.length()-i-1); def->nargs = 0; fileDefineDict->insert(ds.left(i),def); } } defStr=predefined.next(); } if (inputFilter.isEmpty()) { preYYin = fopen(fileName,"r"); if (!preYYin) { err("Error: could not open file %s\n",fileName); return; } } else { QString cmd = inputFilter+" "+fileName; preYYin = popen(cmd,"r"); if (!preYYin) { err("Error: could not execute filter %s\n",cmd.data()); return; } } yyLineNr = 1; level = 0; yyFileName = fileName; BEGIN( Start ); preYYlex(); if (inputFilter.isEmpty()) fclose(preYYin); else pclose(preYYin); #if DUMP_OUTPUT char *orgPos=output.data()+orgOffset; char *newPos=output.data()+output.curPos(); printf("Resulting size: %d bytes\n",newPos-orgPos); int line=1; printf("---------\n00001 "); while (orgPos