1 /*
2  * pasmpp.c
3  *
4  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
5  *
6  *
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions
9  *  are met:
10  *
11  *    Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  *    Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the
17  *    distribution.
18  *
19  *    Neither the name of Texas Instruments Incorporated nor the names of
20  *    its contributors may be used to endorse or promote products derived
21  *    from this software without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35 */
36 
37 /*===========================================================================
38  * Copyright (c) Texas Instruments Inc 2010-12
39  *
40  * Use of this software is controlled by the terms and conditions found in the
41  * license agreement under which this software has been supplied or provided.
42  * ============================================================================
43  */
44 
45 /*===========================================================================
46 // PASM - PRU Assembler
47 //---------------------------------------------------------------------------
48 //
49 // File     : pasmpp.c
50 //
51 // Description:
52 //     Assembler pre-processor. This module's operation is independent
53 //     of the rest of the assembler. It contains no PRU specific
54 //     functionality.
55 //         - Preprocessor handles all source file opening and reading
56 //         - Initial source parsing
57 //         - Processes all '#' commands (#include and #define)
58 //         - Handles equate creation, matching, and expansion
59 //
60 //---------------------------------------------------------------------------
61 // Revision:
62 //     21-Jun-13: 0.84 - Open source version
63 ============================================================================*/
64 
65 #include <stdio.h>
66 #include <stdarg.h>
67 #include <string.h>
68 #if !defined(__APPLE__) && !defined(__FreeBSD__)
69 #include <malloc.h>
70 #else
71 #include <stdlib.h>
72 #endif
73 #include <ctype.h>
74 #include "pasm.h"
75 
76 /* Local Strcuture Types */
77 
78 /* Equate Record */
79 typedef struct _EQUATE {
80     struct _EQUATE  *pPrev;         /* Previous in EQUATE list */
81     struct _EQUATE  *pNext;         /* Next in EQUATE list */
82     int             Busy;           /* Is this record busy? */
83     char            name[EQUATE_NAME_LEN];
84     char            data[EQUATE_DATA_LEN];
85 } EQUATE;
86 
87 /* Local Support Funtions */
88 static int ReadCharacter( SOURCEFILE *ps );
89 static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF );
90 static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen );
91 static int LoadInclude( SOURCEFILE *ps, char *Src );
92 static int EquateProcess( SOURCEFILE *ps, char *Src );
93 static int UndefProcess( SOURCEFILE *ps, char *Src );
94 static EQUATE *EquateFind( char *name );
95 static void EquateDestroy( EQUATE *peq );
96 
97 static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue );
98 static int ElseProcess( SOURCEFILE *ps, char *Src );
99 static int EndifProcess( SOURCEFILE *ps, char *Src );
100 
101 int     OpenFiles=0;        /* Total number of open files */
102 EQUATE  *pEqList=0;         /* List of installed equates */
103 
104 SOURCEFILE      sfArray[SOURCEFILE_MAX];
105 unsigned int    sfIndex = 0;
106 
107 #define CC_MAX_DEPTH            8
108 uint    ccDepth = 0;
109 uint    ccStateFlags[CC_MAX_DEPTH];
110 #define CCSTATEFLG_TRUE         1       // Currently accepting code
111 #define CCSTATEFLG_ELSE         2       // Else has been used
112 
113 
114 /*===================================================================
115 //
116 // Public Functions
117 //
118 ====================================================================*/
119 
120 /*
121 // InitSourceFile
122 //
123 // Initializes all the fields in SOURCEFILE, and attempts to to open the
124 // file.
125 //
126 // Returns 1 on success, 0 on error
127 */
InitSourceFile(SOURCEFILE * pParent,char * filename)128 SOURCEFILE *InitSourceFile( SOURCEFILE *pParent, char *filename )
129 {
130     SOURCEFILE *ps;
131     int i,j,k;
132     char SourceName[SOURCE_NAME];
133     char SourceBaseDir[SOURCE_BASE_DIR];
134 
135     /* Put a reasonable cap on #include depth */
136     if( OpenFiles==15 )
137     {
138         Report(pParent,REP_FATAL,"Too many open files");
139         return(0);
140     }
141 
142     /*
143     // Create a base directory for this file
144     //
145     // The base directory is used for any #include contained in the source
146     */
147     strcpy( SourceBaseDir, "./" );
148     i=0;
149     j=-1;
150     k=0;
151     while( filename[i] )
152     {
153         if( filename[i]==':' )
154         {
155             if(k)
156             {
157                 Report(pParent,REP_FATAL,"Illegal source file name '%s'",filename);
158                 goto FILEOP_ERROR;
159             }
160             j=i;
161             k=1;
162         }
163         if( filename[i]=='/' || filename[i]=='\\' )
164             j=i;
165         i++;
166     }
167     if( j>=(SOURCE_BASE_DIR-4) )
168     {
169         Report(pParent,REP_FATAL,"Pathname too long in '%s'",filename);
170         goto FILEOP_ERROR;
171     }
172     if( j>0 )
173     {
174         if(k)
175         {
176             memcpy( SourceBaseDir, filename, j+1 );
177             SourceBaseDir[j+1]='.';
178             SourceBaseDir[j+2]='/';
179             SourceBaseDir[j+3]=0;
180         }
181         else
182         {
183             if((filename[0]=='.' && filename[1]=='/') || filename[0]=='/' || filename[0]=='\\')
184             {
185                 memcpy( SourceBaseDir, filename, j );
186                 SourceBaseDir[j]='/';
187                 SourceBaseDir[j+1]=0;
188             }
189             else
190             {
191                 memcpy( SourceBaseDir+2, filename, j );
192                 SourceBaseDir[j+2]='/';
193                 SourceBaseDir[j+3]=0;
194             }
195         }
196     }
197     if( Options & OPTION_DEBUG )
198         printf("Base source directory: '%s'\n",SourceBaseDir);
199 
200     /* Create the "friendly" filename for output messages */
201     i=strlen(filename)-j;
202     if( i>SOURCE_NAME )
203     {
204         Report(pParent,REP_FATAL,"Basename too long in '%s'",filename);
205         goto FILEOP_ERROR;
206     }
207     memcpy( SourceName, filename+j+1, i );
208 
209     /*
210     // See if this file was used before, or allocate a new record
211     */
212     for( i=0; i<(int)sfIndex; i++ )
213     {
214         if( !sfArray[i].InUse &&
215                 !strcmp(SourceName, sfArray[i].SourceName) &&
216                 !strcmp(SourceBaseDir, sfArray[i].SourceBaseDir) )
217             break;
218     }
219 
220     if( i<(int)sfIndex )
221         ps = &sfArray[i];
222     else
223     {
224         /* Allocate a new file */
225         if( sfIndex==SOURCEFILE_MAX )
226             { Report(pParent,REP_FATAL,"Max source files exceeded"); return(0); }
227 
228         ps = &sfArray[sfIndex];
229         i = sfIndex++;
230     }
231 
232     /*
233     // Fill in file record
234     */
235     memset( ps, 0, sizeof(SOURCEFILE) );
236 
237     if( Options & OPTION_DEBUG )
238         printf("New source file: '%s'\n",filename);
239 
240     /* Init the base fields */
241     ps->pParent       = 0;
242     ps->LastChar      = 0;
243     ps->CurrentLine   = 1;
244     ps->CurrentColumn = 1;
245     ps->ccDepthIn     = ccDepth;
246     ps->InUse         = 1;
247     ps->FileIndex     = i;
248 
249     strcpy( ps->SourceName, SourceName );
250     strcpy( ps->SourceBaseDir, SourceBaseDir );
251 
252 
253     /* Open the file */
254     ps->FilePtr = fopen(filename,"rb");
255     if (!ps->FilePtr)
256     {
257         Report(pParent,REP_FATAL,"Can't open source file '%s'",filename);
258         goto FILEOP_ERROR;
259     }
260     OpenFiles++;
261     if( OpenFiles > 10 )
262         Report(pParent,REP_WARN1,"%d open files - possible #include recursion",OpenFiles);
263     return(ps);
264 
265 FILEOP_ERROR:
266     return(0);
267 }
268 
269 
270 /*
271 // CloseSourceFile
272 //
273 // Close the source file and free the block.
274 //
275 // void
276 */
CloseSourceFile(SOURCEFILE * ps)277 void CloseSourceFile( SOURCEFILE *ps )
278 {
279     OpenFiles--;
280     ps->InUse = 0;
281     fclose( ps->FilePtr );
282 }
283 
284 
285 /*
286 // GetSourceLine
287 //
288 // Get a new line of source code.
289 //
290 // This module also processes:
291 //    '#' directives
292 //    #define expansion
293 //    Comments
294 //
295 // Returns length of line, 0 on EOF, -1 on Error
296 */
297 #define RAW_SOURCE_MAX  255
GetSourceLine(SOURCEFILE * ps,char * Dst,int MaxLen)298 int GetSourceLine( SOURCEFILE *ps, char *Dst, int MaxLen )
299 {
300     char c,Src[RAW_SOURCE_MAX],word[TOKEN_MAX_LEN];
301     int  i,idx;
302     int  len,eof;
303 
304 NEXT_LINE:
305     do
306     {
307         if( !GetTextLine(ps, Src, RAW_SOURCE_MAX, &len, &eof) )
308             return(-1);
309     } while( !len && !eof );
310 
311     if( !len && eof )
312     {
313         if( ps->ccDepthIn != ccDepth )
314             { Report(ps,REP_ERROR,"#endif mismatch in file"); return(0); }
315         return(0);
316     }
317 
318     /*
319     // Process any '#' directives
320     */
321     if( Src[0]=='#' )
322     {
323         idx = 1;
324         c = Src[idx++];
325         if( (c<'A'||c>'Z') && (c<'a'||c>'z') )
326             { Report(ps,REP_ERROR,"Expected {a-z} after #"); return(-1); }
327         i=0;
328         word[i++]=c;
329         while( i<(TOKEN_MAX_LEN-1) )
330         {
331             c = Src[idx++];
332             if( c==' ' || c==0x9 || !c )
333                 break;
334             word[i++]=c;
335         }
336         word[i]=0;
337 
338         /* Make sure the process functions see the final NULL */
339         if( !c )
340             idx--;
341 
342         if( !stricmp( word, "ifdef" ) )
343         {
344             if( !IfDefProcess( ps, Src+idx, 1 ) )
345                 return(-1);
346             goto NEXT_LINE;
347         }
348         if( !stricmp( word, "ifndef" ) )
349         {
350             if( !IfDefProcess( ps, Src+idx, 0 ) )
351                 return(-1);
352             goto NEXT_LINE;
353         }
354         if( !stricmp( word, "else" ) )
355         {
356             if( !ElseProcess( ps, Src+idx ) )
357                 return(-1);
358             goto NEXT_LINE;
359         }
360         if( !stricmp( word, "endif" ) )
361         {
362             if( !EndifProcess( ps, Src+idx ) )
363                 return(-1);
364             goto NEXT_LINE;
365         }
366 
367         if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) )
368             goto NEXT_LINE;
369 
370         if( !stricmp( word, "error" ) )
371         {
372             Report(ps,REP_ERROR,"%s",Src+idx);
373             goto NEXT_LINE;
374         }
375         if( !stricmp( word, "warn" ) )
376         {
377             Report(ps,REP_WARN1,"%s",Src+idx);
378             goto NEXT_LINE;
379         }
380         if( !stricmp( word, "note" ) )
381         {
382             Report(ps,REP_INFO,"%s",Src+idx);
383             goto NEXT_LINE;
384         }
385         if( !stricmp( word, "include" ) )
386         {
387             if( !LoadInclude( ps, Src+idx ) )
388                 return(-1);
389             goto NEXT_LINE;
390         }
391         if( !stricmp( word, "define" ) )
392         {
393             EquateProcess( ps, Src+idx );
394             goto NEXT_LINE;
395         }
396         if( !stricmp( word, "undef" ) )
397         {
398             UndefProcess( ps, Src+idx );
399             goto NEXT_LINE;
400         }
401         Report(ps,REP_ERROR,"Unknown # directive");
402         return(-1);
403     }
404 
405     /*
406     // Not '#' directive, process as string
407     */
408 
409     if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) )
410         goto NEXT_LINE;
411 
412     idx = 0;
413     if( !ParseSource( ps, Src, Dst, &idx, MaxLen ) )
414         return(0);
415 
416     Dst[idx] = 0;
417     return(idx);
418 }
419 
420 /*
421 // ppCleanup
422 //
423 // Clean up the pre-processor environment
424 //
425 // void
426 */
ppCleanup()427 void ppCleanup()
428 {
429     ccDepth = 0;
430     while( pEqList )
431         EquateDestroy( pEqList );
432 }
433 
434 
435 /*
436 // EquateCreate
437 //
438 // Creates an equate record
439 //
440 // Returns 0 on success, -1 on error
441 */
EquateCreate(SOURCEFILE * ps,char * Name,char * Value)442 int EquateCreate( SOURCEFILE *ps, char *Name, char *Value )
443 {
444     EQUATE *pd;
445 
446     /* Make sure this name is OK to use */
447     if( !CheckName(ps,Name) )
448         return(-1);
449 
450     /* Make sure its not a too long */
451     if( strlen(Name)>=EQUATE_NAME_LEN )
452         { Report(ps,REP_ERROR,"Equate name '%s' too long",Name); return(-1); }
453     if( strlen(Value)>=EQUATE_DATA_LEN )
454         { Report(ps,REP_ERROR,"Equate data '%s' too long",Value); return(-1); }
455 
456     /* Allocate a new record */
457     pd = malloc(sizeof(EQUATE));
458     if( !pd )
459         { Report(ps,REP_ERROR,"Memory allocation failed"); return(-1); }
460 
461     /* Load in the name and data */
462     strcpy( pd->name, Name );
463     strcpy( pd->data, Value );
464 
465     /* Put this equate in the master list */
466     pd->Busy  = 0;
467     pd->pPrev = 0;
468     pd->pNext = pEqList;
469     if( pEqList )
470         pEqList->pPrev = pd;
471     pEqList   = pd;
472 
473     if( Pass==1 && (Options & OPTION_DEBUG) )
474         printf("%s(%5d) : DEFINE : '%s' = '%s'\n",
475                             ps->SourceName,ps->CurrentLine,pd->name,pd->data);
476 
477     return(0);
478 }
479 
480 
481 /*
482 // CheckEquate
483 //
484 // Searches for an equate by name.
485 //
486 // Returns 1 on success, 0 on error
487 */
CheckEquate(char * name)488 int CheckEquate( char *name )
489 {
490     if( EquateFind(name) )
491         return(1);
492     return(0);
493 }
494 
495 
496 /*===================================================================
497 //
498 // Private Functions
499 //
500 ====================================================================*/
501 
502 /*
503 // ReadCharacter
504 //
505 // Read a charater from the source file and track line and column
506 //
507 // Returns character or -1 on error
508 */
ReadCharacter(SOURCEFILE * ps)509 static int ReadCharacter( SOURCEFILE *ps )
510 {
511     int i;
512     char c;
513 
514 AGAIN:
515     i = fread( &c, 1, 1, ps->FilePtr );
516     if( i != 1 )
517         return(-1);
518     if( c == 0xd )
519         goto AGAIN;
520     if( ps->LastChar == 0xa )
521     {
522         ps->CurrentLine++;
523         ps->CurrentColumn=1;
524     }
525     else
526         ps->CurrentColumn++;
527     ps->LastChar = c;
528 
529     return(c);
530 }
531 
532 
533 /*
534 // GetTextLine
535 //
536 // Gets a line of text from the source file without # directive
537 // processing, or processing past a EOL.
538 //
539 // Returns 1 on success, 0 on error
540 */
GetTextLine(SOURCEFILE * ps,char * Dst,int MaxLen,int * pLength,int * pEOF)541 static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF )
542 {
543     int c;
544     int  idx;
545     int  commentFlag,quoteFlag;
546 
547     /* Remove leading white space */
548     do
549     {
550         c = ReadCharacter( ps );
551     } while( c==' ' || c==0x9 || c==0xa );
552 
553     /*
554     // Process line watching for comments and quotes
555     */
556     idx=0;
557     commentFlag=0;
558     quoteFlag=0;
559     for(;;)
560     {
561         /* Process quotes and comments */
562         if( c=='"' )
563             quoteFlag^=1;
564 
565         if( quoteFlag )
566             commentFlag=0;
567 
568         if( (commentFlag && c=='/') || (!quoteFlag && c==';') )
569         {
570             if( c=='/' && idx>0 )
571                 idx--;
572             while( c!=0 && c!=-1 && c!=0xa )
573                 c = ReadCharacter( ps );
574             break;
575         }
576 
577         if( c=='/' )
578             commentFlag=1;
579         else
580             commentFlag=0;
581 
582         /* If this character terminated the line, break now */
583         if( c==0 || c==-1 || c==0xa )
584             break;
585 
586         /* We didn't consume this charater */
587         if( idx<(MaxLen-1) )
588             Dst[idx++]=c;
589         else
590             { Report(ps,REP_ERROR,"Line too long"); return(0); }
591 
592         c = ReadCharacter( ps );
593     }
594 
595     /* Back off white space */
596     while( idx>0 && (Dst[idx-1]==' ' || Dst[idx-1]==0x9) )
597         idx--;
598 
599     /* Null terminate the output */
600     Dst[idx] = 0;
601 
602     if( quoteFlag )
603         Report(ps,REP_ERROR,"Open Quotes");
604 
605     if( pLength )
606         *pLength = idx;
607 
608     if( pEOF )
609     {
610         if( idx || c!=-1 )
611             *pEOF=0;
612         else
613             *pEOF=1;
614     }
615 
616     return(1);
617 }
618 
619 
620 /*
621 // ParseSource
622 //
623 // Parses the source string, expanding any equates
624 //
625 // Returns 1 on success, 0 on error
626 */
627 #define WF_READY    0
628 #define WF_NONLABEL 1
629 #define WF_QUOTED   2
630 #define WF_LABEL    3
ParseSource(SOURCEFILE * ps,char * Src,char * Dst,int * pIdx,int MaxLen)631 static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen )
632 {
633     char c,word[TOKEN_MAX_LEN];
634     int  i,srcIdx,dstIdx,wordIdx;
635     int  wordFlag;
636 
637     srcIdx = 0;
638     dstIdx = *pIdx;
639     wordIdx = 0;
640 
641     wordFlag=WF_READY;
642     for(;;)
643     {
644         c = Src[srcIdx++];
645 
646         /* See if we go into label or non-label mode */
647         if( wordFlag==WF_READY )
648         {
649             if( c=='"' )
650                 wordFlag=WF_QUOTED;
651             else if( LabelChar(c,1) )
652             {
653                 wordFlag=WF_LABEL;
654                 wordIdx=0;
655                 word[wordIdx++]=c;
656                 continue;
657             }
658             else if( LabelChar(c,0) )
659                 wordFlag=WF_NONLABEL;
660         }
661         /* See if we fall out of non-label mode */
662         else if( wordFlag==WF_NONLABEL )
663         {
664             if( c=='"' )
665                 wordFlag=WF_QUOTED;
666             else if( !LabelChar(c,0) )
667                 wordFlag=WF_READY;
668         }
669         /* See if we fall out of label mode */
670         else if( wordFlag==WF_LABEL )
671         {
672             if( (wordIdx>=(TOKEN_MAX_LEN-1)) || !LabelChar(c,0) )
673             {
674                 /* Here we are teminating the word and checking it */
675                 EQUATE *peq;
676                 if( c=='"' )
677                     wordFlag=WF_QUOTED;
678                 else
679                     wordFlag=WF_READY;
680                 word[wordIdx]=0;
681                 peq = EquateFind(word);
682                 /* See if equate exists and is free */
683                 if( peq && !peq->Busy )
684                 {
685                     /* Mark as busy, process, then mark as free */
686                     peq->Busy=1;
687                     i = ParseSource( ps, peq->data, Dst, &dstIdx, MaxLen );
688                     peq->Busy=0;
689 
690                     /* If there was an error, return now */
691                     if( !i )
692                         return(0);
693                 }
694                 else
695                 {
696                     /* The word is not a EQUATE */
697                     for(i=0;i<wordIdx;i++)
698                     {
699                         if( dstIdx<(MaxLen-1) )
700                             Dst[dstIdx++]=word[i];
701                         else
702                             { Report(ps,REP_ERROR,"Line too long"); return(0); }
703                     }
704                 }
705             }
706             else
707             {
708                 /* Here we are building the word */
709                 word[wordIdx++]=c;
710                 continue;
711             }
712         }
713         /* See if we fall out of quoted mode */
714         else if( wordFlag==WF_QUOTED )
715         {
716             if( c=='"' )
717                 wordFlag=WF_READY;
718         }
719 
720         /* If this character terminated the line, break now */
721         if( !c )
722         {
723             if( wordFlag==WF_QUOTED )
724                 Report(ps,REP_ERROR,"Non-terminated string");
725             break;
726         }
727 
728         /* We didn't consume this charater */
729         if( dstIdx<(MaxLen-1) )
730             Dst[dstIdx++]=c;
731         else
732             { Report(ps,REP_ERROR,"Line too long"); return(0); }
733     }
734 
735     *pIdx = dstIdx;
736     return(1);
737 }
738 
739 
740 /*
741 // LoadInclude
742 //
743 // Processes a #include command
744 //
745 // Returns 1 on success, 0 on error
746 */
LoadInclude(SOURCEFILE * ps,char * Src)747 static int LoadInclude( SOURCEFILE *ps, char *Src )
748 {
749     char c,term;
750     char NewFileName[SOURCE_BASE_DIR];
751     int  rc,idx,oldidx,srcIdx;
752     SOURCEFILE *psNew;
753 
754     srcIdx=0;
755 
756     /* Remove leading white space */
757     do
758     {
759         c = Src[srcIdx++];
760     } while( c==' ' || c==0x9 );
761 
762     /* Charater must be '"' or '<' */
763     if( c=='"' )
764     {
765         term = '"';
766         strcpy( NewFileName, ps->SourceBaseDir );
767         idx = strlen(NewFileName);
768     }
769     else if( c=='<' )
770     {
771         term = '>';
772         idx=0;
773     }
774     else
775         { Report(ps,REP_ERROR,"Expected \" or < after #include"); return(0); }
776 
777     /* Read in the filename to the terminating character */
778     // Check for include paths that start with "/" or "\"
779     // (assume an absolute path)
780     if( Src[srcIdx]=='/' || Src[srcIdx]=='\\' )
781         idx = 0;
782     oldidx = idx;
783     for(;;)
784     {
785         c = Src[srcIdx++];
786         // Check for include paths that include a ":"
787         // (assume a driver letter preceeded)
788         if( c==':' && idx>0 )
789         {
790             NewFileName[0]=NewFileName[idx-1];
791             idx = 1;
792             oldidx = idx;
793         }
794         if( c==term )
795             break;
796         if( !c )
797             { Report(ps,REP_ERROR,"Bad filename in #include"); return(0); }
798         if( idx >= (SOURCE_BASE_DIR-1) )
799             { Report(ps,REP_ERROR,"Filename too long in #include"); return(0); }
800         NewFileName[idx++]=c;
801     }
802 
803     /* The line should be done now */
804     if( Src[srcIdx] )
805         { Report(ps,REP_ERROR,"Expected EOL after '%s'",NewFileName); return(0); }
806 
807     /* Null terminate the filename and make sure something got copied */
808     NewFileName[idx]=0;
809     if( idx == oldidx )
810         { Report(ps,REP_ERROR,"Null filename in #include"); return(0); }
811 
812     /* Open the new file */
813     if( !(psNew=InitSourceFile(ps, NewFileName)) )
814         return(0);
815 
816     /* Process the new file */
817     rc = ProcessSourceFile( psNew );
818 
819     /* Free the file block */
820     CloseSourceFile( psNew );
821 
822     if( !rc && Pass==2 )
823         return(0);
824     else
825         return(1);
826 }
827 
828 /*
829 // EquateProcess
830 //
831 // Processes a #define command
832 //
833 // Returns 1 on success, 0 on error
834 */
EquateProcess(SOURCEFILE * ps,char * Src)835 static int EquateProcess( SOURCEFILE *ps, char *Src )
836 {
837     EQUATE *pd,*pdTmp;
838     char c;
839     int  idx,srcIdx;
840 
841     /* Allocate a new record */
842     pd = malloc(sizeof(EQUATE));
843     if( !pd )
844         { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); }
845 
846     srcIdx=0;
847 
848     /* Remove leading white space */
849     do
850     {
851         c = Src[srcIdx++];
852     } while( c==' ' || c==0x9 );
853 
854     /* Character must be a legal label */
855     if( !LabelChar(c,1) )
856         { Report(ps,REP_ERROR,"Illegal label"); free(pd); return(0); }
857 
858     /* The name can only be delimited by a white space */
859     /* Note: We now allow a NULL for a #define with no value */
860     idx=0;
861     for(;;)
862     {
863         pd->name[idx++]=c;
864         c = Src[srcIdx++];
865         if( !c || c==' ' || c==0x9 )
866             break;
867         if( !LabelChar(c,0) )
868             { Report(ps,REP_ERROR,"Illegal #define"); free(pd); return(0); }
869         if( idx >= (EQUATE_NAME_LEN-1) )
870             { Report(ps,REP_ERROR,"Label too long"); free(pd); return(0); }
871     }
872     pd->name[idx]=0;
873 
874     /* Make sure this name is OK to use */
875     if( !CheckName(ps,pd->name) )
876     {
877         free(pd);
878         return(0);
879     }
880 
881     /* Remove leading white space (unless we already hit EOL) */
882     if( c )
883         do
884         {
885             c = Src[srcIdx++];
886         } while( c==' ' || c==0x9 );
887 
888     /* Load in the text part of the equate (defaul to "1" if no value) */
889     if( !c )
890         strcpy( pd->data, "1" );
891     else
892         strcpy( pd->data, Src+srcIdx-1 );
893 
894     /* Check for dedefinition, but ignore exact duplicates */
895     if( (pdTmp = EquateFind(pd->name)) != 0 )
896     {
897         idx = strcmp( pd->data, pdTmp->data );
898         if( !idx )
899         {
900             free(pd);
901             return(1);
902         }
903         EquateDestroy(pdTmp);
904         Report(ps,REP_WARN1,"Redefinition of equate '%s'",pd->name);
905     }
906 
907     /* Put this equate in the master list */
908     pd->Busy  = 0;
909     pd->pPrev = 0;
910     pd->pNext = pEqList;
911     if( pEqList )
912         pEqList->pPrev = pd;
913     pEqList   = pd;
914 
915     if( Pass==1 && (Options & OPTION_DEBUG) )
916         printf("%s(%5d) : DEFINE : '%s' = '%s'\n",
917                             ps->SourceName,ps->CurrentLine,pd->name,pd->data);
918 
919     return(1);
920 }
921 
922 
923 /*
924 // UndefProcess
925 //
926 // Processes a #undef command
927 //
928 // Returns 1 on success, 0 on error
929 */
UndefProcess(SOURCEFILE * ps,char * Src)930 static int UndefProcess( SOURCEFILE *ps, char *Src )
931 {
932     EQUATE *pdTmp;
933     char c,name[EQUATE_NAME_LEN];
934     int  idx,srcIdx;
935 
936     srcIdx=0;
937 
938     /* Remove leading white space */
939     do
940     {
941         c = Src[srcIdx++];
942     } while( c==' ' || c==0x9 );
943 
944     /* Character must be a legal label */
945     if( !LabelChar(c,1) )
946         { Report(ps,REP_ERROR,"Illegal label"); return(0); }
947 
948     /* The name is delimited by EOL */
949     idx=0;
950     for(;;)
951     {
952         name[idx++]=c;
953         c = Src[srcIdx++];
954         if( !c )
955             break;
956         if( c==' ' || c==0x9 )
957             { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); }
958         if( !LabelChar(c,0) )
959             { Report(ps,REP_ERROR,"Illegal name"); return(0); }
960         if( idx >= (EQUATE_NAME_LEN-1) )
961             { Report(ps,REP_ERROR,"Label too long"); return(0); }
962     }
963     name[idx]=0;
964 
965     /* Check for dedefinition */
966     if( !(pdTmp = EquateFind(name)) )
967         { Report(ps,REP_WARN1,"Undef attempt on undfined '%s'",name); return(1); }
968 
969     EquateDestroy(pdTmp);
970 
971     if( Pass==1 && (Options & OPTION_DEBUG) )
972         printf("%s(%5d) : UNDEF  : '%s'\n",
973                             ps->SourceName,ps->CurrentLine,name);
974 
975     return(1);
976 }
977 
978 
979 /*
980 // EquateFind
981 //
982 // Searches for an equate by name. If found, returns the record pointer.
983 //
984 // Returns EQUATE * on success, 0 on error
985 */
EquateFind(char * name)986 static EQUATE *EquateFind( char *name )
987 {
988     EQUATE *peq;
989 
990     peq = pEqList;
991     while( peq )
992     {
993         if( !strcmp( name, peq->name ) )
994             break;
995         peq = peq->pNext;
996     }
997     return(peq);
998 }
999 
1000 
1001 /*
1002 // EquateDestroy
1003 //
1004 // Frees an equate record.
1005 //
1006 // void
1007 */
EquateDestroy(EQUATE * peq)1008 static void EquateDestroy( EQUATE *peq )
1009 {
1010     if( !peq->pPrev )
1011         pEqList = peq->pNext;
1012     else
1013         peq->pPrev->pNext = peq->pNext;
1014 
1015     if( peq->pNext )
1016         peq->pNext->pPrev = peq->pPrev;
1017 
1018     free(peq);
1019 }
1020 
1021 
1022 /*
1023 // IfDefProcess
1024 //
1025 // Processes a #ifdef command
1026 //
1027 // Returns 1 on success, 0 on error
1028 */
IfDefProcess(SOURCEFILE * ps,char * Src,int fTrue)1029 static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue )
1030 {
1031     char c,name[EQUATE_NAME_LEN];
1032     int  idx,srcIdx;
1033 
1034     /* Check depth */
1035     if( ccDepth==CC_MAX_DEPTH )
1036         { Report(ps,REP_ERROR,"Conditional nesting limit exceeded"); return(0); }
1037 
1038     /* If we are already in a false if, just create another false here to track nesting */
1039     if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) )
1040     {
1041         ccStateFlags[ccDepth++] = 0;
1042 
1043         if( Pass==1 && (Options & OPTION_DEBUG) )
1044             printf("%s(%5d) : IFDEF  : <skipped>\n",ps->SourceName,ps->CurrentLine);
1045 
1046         return(1);
1047     }
1048 
1049     srcIdx=0;
1050 
1051     /* Remove leading white space */
1052     do
1053     {
1054         c = Src[srcIdx++];
1055     } while( c==' ' || c==0x9 );
1056 
1057     /* Character must be a legal label */
1058     if( !LabelChar(c,1) )
1059         { Report(ps,REP_ERROR,"Illegal label"); return(0); }
1060 
1061     /* The name is delimited by EOL */
1062     idx=0;
1063     for(;;)
1064     {
1065         name[idx++]=c;
1066         c = Src[srcIdx++];
1067         if( !c )
1068             break;
1069         if( c==' ' || c==0x9 )
1070             { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); }
1071         if( !LabelChar(c,0) )
1072             { Report(ps,REP_ERROR,"Illegal name"); return(0); }
1073         if( idx >= (EQUATE_NAME_LEN-1) )
1074             { Report(ps,REP_ERROR,"Label too long"); return(0); }
1075     }
1076     name[idx]=0;
1077 
1078     ccStateFlags[ccDepth] = 0;
1079 
1080     /* Check for dedefinition */
1081     if( EquateFind(name) )
1082         ccStateFlags[ccDepth] = CCSTATEFLG_TRUE;
1083 
1084     /* Toggle the state for ifndef */
1085     if( !fTrue )
1086         ccStateFlags[ccDepth] ^= CCSTATEFLG_TRUE;
1087 
1088     ccDepth++;
1089 
1090     if( Pass==1 && (Options & OPTION_DEBUG) )
1091     {
1092         if( fTrue )
1093             printf("%s(%5d) : IFDEF  : '%s' (Result=%d)\n",
1094                                 ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]);
1095         else
1096             printf("%s(%5d) : IFNDEF : '%s' (Result=%d)\n",
1097                                 ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]);
1098     }
1099 
1100     return(1);
1101 }
1102 
1103 
1104 /*
1105 // ElseProcess
1106 //
1107 // Processes a #else command
1108 //
1109 // Returns 1 on success, 0 on error
1110 */
ElseProcess(SOURCEFILE * ps,char * Src)1111 static int ElseProcess( SOURCEFILE *ps, char *Src )
1112 {
1113     int i;
1114 
1115     if( *Src )
1116         { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); }
1117 
1118     /* Make sure #else is legal here */
1119     if( !ccDepth || (ccStateFlags[ccDepth-1]&CCSTATEFLG_ELSE) )
1120         { Report(ps,REP_ERROR,"Multiple #else or use without corresponding #if"); return(0); }
1121 
1122     /* Mark it as used */
1123     ccStateFlags[ccDepth-1] |= CCSTATEFLG_ELSE;
1124 
1125     /* Toggle the TRUE state */
1126     ccStateFlags[ccDepth-1] ^= CCSTATEFLG_TRUE;
1127 
1128     /* If we are already in a nested false if, keep expession false */
1129     for( i=0; i<(int)(ccDepth-1); i++ )
1130         if( !(ccStateFlags[i]&CCSTATEFLG_TRUE) )
1131             ccStateFlags[ccDepth-1] &= ~CCSTATEFLG_TRUE;
1132 
1133     if( Pass==1 && (Options & OPTION_DEBUG) )
1134         printf("%s(%5d) : ELSE   : (Result=%d)\n",
1135                             ps->SourceName,ps->CurrentLine,ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE);
1136 
1137     return(1);
1138 }
1139 
1140 
1141 /*
1142 // EndifProcess
1143 //
1144 // Processes a #endif command
1145 //
1146 // Returns 1 on success, 0 on error
1147 */
EndifProcess(SOURCEFILE * ps,char * Src)1148 static int EndifProcess( SOURCEFILE *ps, char *Src )
1149 {
1150     if( *Src )
1151         { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); }
1152 
1153     /* Make sure #else is legal here */
1154     if( !ccDepth  )
1155         { Report(ps,REP_ERROR,"#endif without corresponding #if"); return(0); }
1156 
1157     ccDepth--;
1158 
1159     if( Pass==1 && (Options & OPTION_DEBUG) )
1160         printf("%s(%5d) : ENDIF  :\n",
1161                             ps->SourceName,ps->CurrentLine);
1162 
1163     return(1);
1164 }
1165 
1166