/* * pasmpp.c * * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /*=========================================================================== * Copyright (c) Texas Instruments Inc 2010-12 * * Use of this software is controlled by the terms and conditions found in the * license agreement under which this software has been supplied or provided. * ============================================================================ */ /*=========================================================================== // PASM - PRU Assembler //--------------------------------------------------------------------------- // // File : pasmpp.c // // Description: // Assembler pre-processor. This module's operation is independent // of the rest of the assembler. It contains no PRU specific // functionality. // - Preprocessor handles all source file opening and reading // - Initial source parsing // - Processes all '#' commands (#include and #define) // - Handles equate creation, matching, and expansion // //--------------------------------------------------------------------------- // Revision: // 21-Jun-13: 0.84 - Open source version ============================================================================*/ #include #include #include #if !defined(__APPLE__) && !defined(__FreeBSD__) #include #else #include #endif #include #include "pasm.h" #include "path_utils.h" /* Local Strcuture Types */ /* Equate Record */ typedef struct _EQUATE { struct _EQUATE *pPrev; /* Previous in EQUATE list */ struct _EQUATE *pNext; /* Next in EQUATE list */ int Busy; /* Is this record busy? */ char name[EQUATE_NAME_LEN]; size_t data_len; char *data; } EQUATE; static EQUATE * allocEQUATE() { EQUATE * p = (EQUATE*)malloc( sizeof(EQUATE) ); memset(p, 0, sizeof(EQUATE)); p->data = (char*) malloc( EQUATE_DATA_LEN ); p->data_len = EQUATE_DATA_LEN; return p; } static void freeEQUATE( EQUATE * p ) { free( p->data ); free( p ); } static void reallocEQUATE( EQUATE * p, const size_t len ) { if ( p->data_len >= len ) return; p->data = (char*)realloc( p->data, len ); p->data_len = len; } /* Local Support Funtions */ static int ReadCharacter( SOURCEFILE *ps ); static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF ); static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen ); static int LoadInclude( SOURCEFILE *ps, char *Src ); static int EquateProcess( SOURCEFILE *ps, char *Src ); static int UndefProcess( SOURCEFILE *ps, char *Src ); static EQUATE *EquateFind( char *name ); static void EquateDestroy( EQUATE *peq ); static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue ); static int ElseProcess( SOURCEFILE *ps, char *Src ); static int EndifProcess( SOURCEFILE *ps, char *Src ); int OpenFiles=0; /* Total number of open files */ EQUATE *pEqList=0; /* List of installed equates */ SOURCEFILE sfArray[SOURCEFILE_MAX]; unsigned int sfIndex = 0; #define CC_MAX_DEPTH 8 uint ccDepth = 0; uint ccStateFlags[CC_MAX_DEPTH]; #define CCSTATEFLG_TRUE 1 // Currently accepting code #define CCSTATEFLG_ELSE 2 // Else has been used /*=================================================================== // // Public Functions // ====================================================================*/ /* // InitSourceFile // // Initializes all the fields in SOURCEFILE, and attempts to to open the // file. // // Returns 1 on success, 0 on error */ SOURCEFILE *InitSourceFile( SOURCEFILE *pParent, char *filename, int use_include_path ) { SOURCEFILE *ps; int i; char SourceName[SOURCE_NAME]; char SourceBaseDir[SOURCE_BASE_DIR]; /* Put a reasonable cap on #include depth */ if( OpenFiles==15 ) { Report(pParent,REP_FATAL,"Too many open files"); return(0); } if ( use_include_path ) if ( !is_definite(filename) ) { switch ( get_absolute( filename, SOURCE_BASE_DIR ) ) { case -1: Report(pParent,REP_FATAL, "Could not find '%s' in include paths",filename); goto FILEOP_ERROR; case 1: Report(pParent,REP_FATAL, "Absolute pathname too long in [include-dirs]/'%s'", filename); goto FILEOP_ERROR; } } /* I don't imagine these test should ever fail at this point, but... */ if ( get_dirname(filename, SourceBaseDir, SOURCE_BASE_DIR) ) { Report(pParent,REP_FATAL,"Dirname too long in '%s'",filename); goto FILEOP_ERROR; } if ( get_basename(filename, SourceName, SOURCE_NAME) ) { Report(pParent,REP_FATAL,"base filename too long in '%s'",filename); goto FILEOP_ERROR; } if( Options & OPTION_DEBUG ) printf("Base source directory: '%s'\n",SourceBaseDir); /* // See if this file was used before, or allocate a new record */ for( i=0; i<(int)sfIndex; i++ ) { if( !sfArray[i].InUse && !strcmp(SourceName, sfArray[i].SourceName) && !strcmp(SourceBaseDir, sfArray[i].SourceBaseDir) ) break; } if( i<(int)sfIndex ) ps = &sfArray[i]; else { /* Allocate a new file */ if( sfIndex==SOURCEFILE_MAX ) { Report(pParent,REP_FATAL,"Max source files exceeded"); return(0); } ps = &sfArray[sfIndex]; i = sfIndex++; } /* // Fill in file record */ memset( ps, 0, sizeof(SOURCEFILE) ); if( Options & OPTION_DEBUG ) printf("New source file: '%s'\n",filename); /* Init the base fields */ ps->pParent = 0; ps->LastChar = 0; ps->CurrentLine = 1; ps->CurrentColumn = 1; ps->ccDepthIn = ccDepth; ps->InUse = 1; ps->FileIndex = i; strcpy( ps->SourceName, SourceName ); strcpy( ps->SourceBaseDir, SourceBaseDir ); /* Open the file */ ps->FilePtr = fopen(filename,"rb"); if (!ps->FilePtr) { Report(pParent,REP_FATAL,"Can't open source file '%s'",filename); goto FILEOP_ERROR; } OpenFiles++; if( OpenFiles > 10 ) Report(pParent,REP_WARN1,"%d open files - possible #include recursion",OpenFiles); return(ps); FILEOP_ERROR: return(0); } /* // CloseSourceFile // // Close the source file and free the block. // // void */ void CloseSourceFile( SOURCEFILE *ps ) { OpenFiles--; ps->InUse = 0; fclose( ps->FilePtr ); } /* // GetSourceLine // // Get a new line of source code. // // This module also processes: // '#' directives // #define expansion // Comments // // Returns length of line, 0 on EOF, -1 on Error */ #define RAW_SOURCE_MAX 16384 #define _RETURN(i) { free(Src); return (i); } int GetSourceLine( SOURCEFILE *ps, char *Dst, int MaxLen ) { char c,word[TOKEN_MAX_LEN]; char* Src = (char*)malloc(RAW_SOURCE_MAX); int i,idx; int len,eof; NEXT_LINE: do { if( !GetTextLine(ps, Src, RAW_SOURCE_MAX, &len, &eof) ) _RETURN(-1); } while( !len && !eof ); if( !len && eof ) { if( ps->ccDepthIn != ccDepth ) { Report(ps,REP_ERROR,"#endif mismatch in file"); _RETURN(0); } _RETURN(0); } /* // Process any '#' directives */ if( Src[0]=='#' ) { idx = 1; c = Src[idx++]; if( (c<'A'||c>'Z') && (c<'a'||c>'z') ) { Report(ps,REP_ERROR,"Expected {a-z} after #"); _RETURN(-1); } i=0; word[i++]=c; while( i<(TOKEN_MAX_LEN-1) ) { c = Src[idx++]; if( c==' ' || c==0x9 || !c ) break; word[i++]=c; } word[i]=0; /* Make sure the process functions see the final NULL */ if( !c ) idx--; if( !stricmp( word, "ifdef" ) ) { if( !IfDefProcess( ps, Src+idx, 1 ) ) _RETURN(-1); goto NEXT_LINE; } if( !stricmp( word, "ifndef" ) ) { if( !IfDefProcess( ps, Src+idx, 0 ) ) _RETURN(-1); goto NEXT_LINE; } if( !stricmp( word, "else" ) ) { if( !ElseProcess( ps, Src+idx ) ) _RETURN(-1); goto NEXT_LINE; } if( !stricmp( word, "endif" ) ) { if( !EndifProcess( ps, Src+idx ) ) _RETURN(-1); goto NEXT_LINE; } if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) goto NEXT_LINE; if( !stricmp( word, "error" ) ) { Report(ps,REP_ERROR,"%s",Src+idx); goto NEXT_LINE; } if( !stricmp( word, "warn" ) ) { Report(ps,REP_WARN1,"%s",Src+idx); goto NEXT_LINE; } if( !stricmp( word, "note" ) ) { Report(ps,REP_INFO,"%s",Src+idx); goto NEXT_LINE; } if( !stricmp( word, "include" ) ) { if( !LoadInclude( ps, Src+idx ) ) _RETURN(-1); goto NEXT_LINE; } if( !stricmp( word, "define" ) ) { EquateProcess( ps, Src+idx ); goto NEXT_LINE; } if( !stricmp( word, "undef" ) ) { UndefProcess( ps, Src+idx ); goto NEXT_LINE; } Report(ps,REP_ERROR,"Unknown # directive"); _RETURN(-1); } /* // Not '#' directive, process as string */ if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) goto NEXT_LINE; idx = 0; if( !ParseSource( ps, Src, Dst, &idx, MaxLen ) ) _RETURN(0); Dst[idx] = 0; _RETURN(idx); } #undef _RETURN /* // ppCleanup // // Clean up the pre-processor environment // // void */ void ppCleanup() { ccDepth = 0; while( pEqList ) EquateDestroy( pEqList ); } /* // EquateCreate // // Creates an equate record // // Returns 0 on success, -1 on error */ int EquateCreate( SOURCEFILE *ps, char *Name, char *Value ) { EQUATE *pd; /* Make sure this name is OK to use */ if( !CheckName(ps,Name) ) return(-1); /* Make sure its not a too long */ if( strlen(Name)>=EQUATE_NAME_LEN ) { Report(ps,REP_ERROR,"Equate name '%s' too long",Name); return(-1); } if( strlen(Value)>=EQUATE_DATA_LEN ) { Report(ps,REP_ERROR,"Equate data '%s' too long",Value); return(-1); } /* Allocate a new record */ pd = allocEQUATE(); if( !pd ) { Report(ps,REP_ERROR,"Memory allocation failed"); return(-1); } /* Load in the name and data */ strcpy( pd->name, Name ); strcpy( pd->data, Value ); /* Put this equate in the master list */ pd->Busy = 0; pd->pPrev = 0; pd->pNext = pEqList; if( pEqList ) pEqList->pPrev = pd; pEqList = pd; if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : DEFINE : '%s' = '%s'\n", ps->SourceName,ps->CurrentLine,pd->name,pd->data); return(0); } /* // CheckEquate // // Searches for an equate by name. // // Returns 1 on success, 0 on error */ int CheckEquate( char *name ) { if( EquateFind(name) ) return(1); return(0); } /*=================================================================== // // Private Functions // ====================================================================*/ /* // ReadCharacter // // Read a charater from the source file and track line and column // // Returns character or -1 on error */ static int ReadCharacter( SOURCEFILE *ps ) { int i; char c; AGAIN: i = fread( &c, 1, 1, ps->FilePtr ); if( i != 1 ) return(-1); if( c == 0xd ) goto AGAIN; if( ps->LastChar == 0xa ) { ps->CurrentLine++; ps->CurrentColumn=1; } else ps->CurrentColumn++; ps->LastChar = c; return(c); } /* // GetTextLine // // Gets a line of text from the source file without # directive // processing, or processing past a EOL. // // Returns 1 on success, 0 on error */ static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF ) { int c; int idx; int commentFlag,quoteFlag, continueFlag; /* Remove leading white space */ do { c = ReadCharacter( ps ); } while( c==' ' || c==0x9 || c==0xa ); /* // Process line watching for comments and quotes */ idx=0; commentFlag=0; quoteFlag=0; continueFlag=0; for(;;) { /* Process quotes and comments */ if( c=='"' ) quoteFlag^=1; if( quoteFlag ) commentFlag=0; if( (commentFlag && c=='/') || (!quoteFlag && c==';') ) { if( c=='/' && idx>0 ) idx--; while( c!=0 && c!=-1 && c!=0xa ) c = ReadCharacter( ps ); break; } else if( commentFlag && c=='*' ) { if( idx>0 ) --idx; while ( 1 ) { while( c!=-1 && c!='*' ) c = ReadCharacter( ps ); c = ReadCharacter( ps ); if ( c == '/' ) break; } c = ReadCharacter( ps ); commentFlag = 0; continue; // Just skip the comment as if it weren't there } else if ( continueFlag && c=='\n' ) { if( idx>0 ) --idx; c = ReadCharacter( ps ); continueFlag = 0; continue; // Just skip the endline as if it weren't there } if( c=='/' ) commentFlag=1; else commentFlag=0; if ( c == '\\' ) continueFlag = 1; else continueFlag = 0; /* If this character terminated the line, break now */ if( c==0 || c==-1 || c==0xa ) break; /* We didn't consume this charater */ if( idx<(MaxLen-1) ) { if ( !(continueFlag && c == '\n' ) ) Dst[idx++]=c; } else { Report(ps,REP_ERROR,"Line too long"); return(0); } c = ReadCharacter( ps ); } /* Back off white space */ while( idx>0 && (Dst[idx-1]==' ' || Dst[idx-1]==0x9) ) idx--; /* Null terminate the output */ Dst[idx] = 0; if( quoteFlag ) Report(ps,REP_ERROR,"Open Quotes"); if( pLength ) *pLength = idx; if( pEOF ) { if( idx || c!=-1 ) *pEOF=0; else *pEOF=1; } return(1); } /* // ParseSource // // Parses the source string, expanding any equates // // Returns 1 on success, 0 on error */ #define WF_READY 0 #define WF_NONLABEL 1 #define WF_QUOTED 2 #define WF_LABEL 3 static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen ) { char c,word[TOKEN_MAX_LEN]; int i,srcIdx,dstIdx,wordIdx; int wordFlag; srcIdx = 0; dstIdx = *pIdx; wordIdx = 0; wordFlag=WF_READY; for(;;) { c = Src[srcIdx++]; /* See if we go into label or non-label mode */ if( wordFlag==WF_READY ) { if( c=='"' ) wordFlag=WF_QUOTED; else if( LabelChar(c,1) ) { wordFlag=WF_LABEL; wordIdx=0; word[wordIdx++]=c; continue; } else if( LabelChar(c,0) ) wordFlag=WF_NONLABEL; } /* See if we fall out of non-label mode */ else if( wordFlag==WF_NONLABEL ) { if( c=='"' ) wordFlag=WF_QUOTED; else if( !LabelChar(c,0) ) wordFlag=WF_READY; } /* See if we fall out of label mode */ else if( wordFlag==WF_LABEL ) { if( (wordIdx>=(TOKEN_MAX_LEN-1)) || !LabelChar(c,0) ) { /* Here we are teminating the word and checking it */ EQUATE *peq; if( c=='"' ) wordFlag=WF_QUOTED; else wordFlag=WF_READY; word[wordIdx]=0; peq = EquateFind(word); /* See if equate exists and is free */ if( peq && !peq->Busy ) { /* Mark as busy, process, then mark as free */ peq->Busy=1; i = ParseSource( ps, peq->data, Dst, &dstIdx, MaxLen ); peq->Busy=0; /* If there was an error, return now */ if( !i ) return(0); } else { /* The word is not a EQUATE */ for(i=0;iSourceBaseDir ); idx = strlen(NewFileName); NewFileName[idx++] = '/'; NewFileName[idx] = '\0'; } else if( c=='<' ) { term = '>'; idx=0; } else { Report(ps,REP_ERROR,"Expected \" or < after #include"); return(0); } /* Read in the filename to the terminating character */ // Check for include paths that start with "/" or "\" // (assume an absolute path) if( Src[srcIdx]=='/' || Src[srcIdx]=='\\' ) idx = 0; oldidx = idx; for(;;) { c = Src[srcIdx++]; // Check for include paths that include a ":" // (assume a driver letter preceeded) if( c==':' && idx>0 ) { NewFileName[0]=NewFileName[idx-1]; idx = 1; oldidx = idx; } if( c==term ) break; if( !c ) { Report(ps,REP_ERROR,"Bad filename in #include"); return(0); } if( idx >= (SOURCE_BASE_DIR-1) ) { Report(ps,REP_ERROR,"Filename too long in #include"); return(0); } NewFileName[idx++]=c; } /* The line should be done now */ if( Src[srcIdx] ) { Report(ps,REP_ERROR,"Expected EOL after '%s'",NewFileName); return(0); } /* Null terminate the filename and make sure something got copied */ NewFileName[idx]=0; if( idx == oldidx ) { Report(ps,REP_ERROR,"Null filename in #include"); return(0); } /* Open the new file */ if( !(psNew=InitSourceFile(ps, NewFileName, term == '>')) ) return(0); /* Process the new file */ rc = ProcessSourceFile( psNew ); /* Free the file block */ CloseSourceFile( psNew ); if( !rc && Pass==2 ) return(0); else return(1); } /* // EquateProcess // // Processes a #define command // // Returns 1 on success, 0 on error */ static int EquateProcess( SOURCEFILE *ps, char *Src ) { EQUATE *pd,*pdTmp; char c; int idx,srcIdx; /* Allocate a new record */ pd = allocEQUATE(); if( !pd ) { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } srcIdx=0; /* Remove leading white space */ do { c = Src[srcIdx++]; } while( c==' ' || c==0x9 ); /* Character must be a legal label */ if( !LabelChar(c,1) ) { Report(ps,REP_ERROR,"Illegal label"); freeEQUATE(pd); return(0); } /* The name can only be delimited by a white space */ /* Note: We now allow a NULL for a #define with no value */ idx=0; for(;;) { pd->name[idx++]=c; c = Src[srcIdx++]; if( !c || c==' ' || c==0x9 ) break; if( !LabelChar(c,0) ) { Report(ps,REP_ERROR,"Illegal #define"); freeEQUATE(pd); return(0); } if( idx >= (EQUATE_NAME_LEN-1) ) { Report(ps,REP_ERROR,"Label too long"); freeEQUATE(pd); return(0); } } pd->name[idx]=0; /* Make sure this name is OK to use */ if( !CheckName(ps,pd->name) ) { freeEQUATE(pd); return(0); } /* Remove leading white space (unless we already hit EOL) */ if( c ) do { c = Src[srcIdx++]; } while( c==' ' || c==0x9 ); /* Load in the text part of the equate (defaul to "1" if no value) */ if( !c ) strcpy( pd->data, "1" ); else { size_t len = strlen( Src + srcIdx-1 ) + 1; // +1 for \000 reallocEQUATE( pd, len ); memcpy( pd->data, Src+srcIdx-1, len ); } /* Check for dedefinition, but ignore exact duplicates */ if( (pdTmp = EquateFind(pd->name)) != 0 ) { idx = strcmp( pd->data, pdTmp->data ); if( !idx ) { freeEQUATE(pd); return(1); } EquateDestroy(pdTmp); Report(ps,REP_WARN1,"Redefinition of equate '%s'",pd->name); } /* Put this equate in the master list */ pd->Busy = 0; pd->pPrev = 0; pd->pNext = pEqList; if( pEqList ) pEqList->pPrev = pd; pEqList = pd; if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : DEFINE : '%s' = '%s'\n", ps->SourceName,ps->CurrentLine,pd->name,pd->data); return(1); } /* // UndefProcess // // Processes a #undef command // // Returns 1 on success, 0 on error */ static int UndefProcess( SOURCEFILE *ps, char *Src ) { EQUATE *pdTmp; char c,name[EQUATE_NAME_LEN]; int idx,srcIdx; srcIdx=0; /* Remove leading white space */ do { c = Src[srcIdx++]; } while( c==' ' || c==0x9 ); /* Character must be a legal label */ if( !LabelChar(c,1) ) { Report(ps,REP_ERROR,"Illegal label"); return(0); } /* The name is delimited by EOL */ idx=0; for(;;) { name[idx++]=c; c = Src[srcIdx++]; if( !c ) break; if( c==' ' || c==0x9 ) { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } if( !LabelChar(c,0) ) { Report(ps,REP_ERROR,"Illegal name"); return(0); } if( idx >= (EQUATE_NAME_LEN-1) ) { Report(ps,REP_ERROR,"Label too long"); return(0); } } name[idx]=0; /* Check for dedefinition */ if( !(pdTmp = EquateFind(name)) ) { Report(ps,REP_WARN1,"Undef attempt on undfined '%s'",name); return(1); } EquateDestroy(pdTmp); if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : UNDEF : '%s'\n", ps->SourceName,ps->CurrentLine,name); return(1); } /* // EquateFind // // Searches for an equate by name. If found, returns the record pointer. // // Returns EQUATE * on success, 0 on error */ static EQUATE *EquateFind( char *name ) { EQUATE *peq; peq = pEqList; while( peq ) { if( !strcmp( name, peq->name ) ) break; peq = peq->pNext; } return(peq); } /* // EquateDestroy // // Frees an equate record. // // void */ static void EquateDestroy( EQUATE *peq ) { if( !peq->pPrev ) pEqList = peq->pNext; else peq->pPrev->pNext = peq->pNext; if( peq->pNext ) peq->pNext->pPrev = peq->pPrev; freeEQUATE(peq); } /* // IfDefProcess // // Processes a #ifdef command // // Returns 1 on success, 0 on error */ static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue ) { char c,name[EQUATE_NAME_LEN]; int idx,srcIdx; /* Check depth */ if( ccDepth==CC_MAX_DEPTH ) { Report(ps,REP_ERROR,"Conditional nesting limit exceeded"); return(0); } /* If we are already in a false if, just create another false here to track nesting */ if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) { ccStateFlags[ccDepth++] = 0; if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : IFDEF : \n",ps->SourceName,ps->CurrentLine); return(1); } srcIdx=0; /* Remove leading white space */ do { c = Src[srcIdx++]; } while( c==' ' || c==0x9 ); /* Character must be a legal label */ if( !LabelChar(c,1) ) { Report(ps,REP_ERROR,"Illegal label"); return(0); } /* The name is delimited by EOL */ idx=0; for(;;) { name[idx++]=c; c = Src[srcIdx++]; if( !c ) break; if( c==' ' || c==0x9 ) { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } if( !LabelChar(c,0) ) { Report(ps,REP_ERROR,"Illegal name"); return(0); } if( idx >= (EQUATE_NAME_LEN-1) ) { Report(ps,REP_ERROR,"Label too long"); return(0); } } name[idx]=0; ccStateFlags[ccDepth] = 0; /* Check for dedefinition */ if( EquateFind(name) ) ccStateFlags[ccDepth] = CCSTATEFLG_TRUE; /* Toggle the state for ifndef */ if( !fTrue ) ccStateFlags[ccDepth] ^= CCSTATEFLG_TRUE; ccDepth++; if( Pass==1 && (Options & OPTION_DEBUG) ) { if( fTrue ) printf("%s(%5d) : IFDEF : '%s' (Result=%d)\n", ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]); else printf("%s(%5d) : IFNDEF : '%s' (Result=%d)\n", ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]); } return(1); } /* // ElseProcess // // Processes a #else command // // Returns 1 on success, 0 on error */ static int ElseProcess( SOURCEFILE *ps, char *Src ) { int i; if( *Src ) { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } /* Make sure #else is legal here */ if( !ccDepth || (ccStateFlags[ccDepth-1]&CCSTATEFLG_ELSE) ) { Report(ps,REP_ERROR,"Multiple #else or use without corresponding #if"); return(0); } /* Mark it as used */ ccStateFlags[ccDepth-1] |= CCSTATEFLG_ELSE; /* Toggle the TRUE state */ ccStateFlags[ccDepth-1] ^= CCSTATEFLG_TRUE; /* If we are already in a nested false if, keep expession false */ for( i=0; i<(int)(ccDepth-1); i++ ) if( !(ccStateFlags[i]&CCSTATEFLG_TRUE) ) ccStateFlags[ccDepth-1] &= ~CCSTATEFLG_TRUE; if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : ELSE : (Result=%d)\n", ps->SourceName,ps->CurrentLine,ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE); return(1); } /* // EndifProcess // // Processes a #endif command // // Returns 1 on success, 0 on error */ static int EndifProcess( SOURCEFILE *ps, char *Src ) { if( *Src ) { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } /* Make sure #else is legal here */ if( !ccDepth ) { Report(ps,REP_ERROR,"#endif without corresponding #if"); return(0); } ccDepth--; if( Pass==1 && (Options & OPTION_DEBUG) ) printf("%s(%5d) : ENDIF :\n", ps->SourceName,ps->CurrentLine); return(1); }