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