1 /* preprocessor routines for bcc */
3 /* Copyright (C) 1992 Bruce Evans */
15 /* blanksident() - return nonzero if at blanks followed by an identifier */
17 PUBLIC bool_pt
blanksident()
26 #define MAX__LINE__ 10 /* enough for 32-bit source unsigneds */
28 #define MAX_PARAM 127 /* max char with no sign on all machines */
30 /* Definition types. These are kept in the 'storage' member of struct
31 * symstruct and must be distinct from 'LOCAL' because dumplocs() doesn't
36 DEF_LINE
, /* __LINE__ keyword */
37 DEF_NONE
/* nothing special */
53 struct symstruct
*symptr
;
56 PRIVATE
char dummyparam
[] = { EOL
, 0 };
57 PRIVATE fastin_t iflevel
; /* depends on zero init */
58 PRIVATE
struct ifstruct ifstate
;
59 /* elseflag depends on zero init */
60 PRIVATE
struct ifstruct ifstack
[MAX_IF
];
62 PRIVATE
struct macroposition macrostack
[MAX_MACRO
];
64 FORWARD
void asmcontrol
P((void));
65 FORWARD
void warningcntl
P((void));
66 FORWARD
void errorcntl
P((void));
67 FORWARD
void control
P((void));
68 FORWARD
void defineorundefinestring
P((char *str
, bool_pt defineflag
));
69 FORWARD
void elifcontrol
P((void));
70 FORWARD
void elsecontrol
P((void));
71 FORWARD
void endif
P((void));
72 FORWARD fastin_pt getparnames
P((void));
73 FORWARD
void ifcontrol
P((sym_pt ifcase
));
74 FORWARD
void undef
P((void));
76 /* asmcontrol() - process #asm */
78 PRIVATE
void asmcontrol()
81 char treasure
; /* to save at least one leading blank */
107 if (SYMOFCHAR(ch
) == SPECIALCHAR
)
110 if (SYMOFCHAR(ch
) == WHITESPACE
)
123 while (*lptr
++ != EOL
) /* XXX - handle COEOL too */
136 while (ch
!= EOL
) /* XXX - handle COEOL too */
148 outnstr("!BCC_ENDASM");
151 PUBLIC
void checknotinif()
156 eofin("true #conditional");
158 eofin("false #conditional");
163 /* warningcntl() - process #warning */
165 PRIVATE
void warningcntl()
167 char estr
[256], *ep
= estr
;
170 *ep
++ = '%'; *ep
++ = 'w';
173 if (ep
< estr
+sizeof(estr
)-2 )
187 /* errorcntl() - process #error */
189 PRIVATE
void errorcntl()
191 char estr
[256], *ep
= estr
;
194 if (ep
< estr
+sizeof(estr
)-2 )
208 /* control() - select and switch to control statement */
210 PRIVATE
void control()
212 char sname
[NAMESIZE
+ 1];
214 struct symstruct
*symptr
;
215 if (ctext
&& asmmode
)
218 outudec(input
.linenumber
);
223 sname
[0] = '#'; /* prepare for bad control */
225 while (blanksident())
227 if ((gsymptr
= findlorg(gsname
)) == NULL
||
228 gsymptr
->flags
!= DEFINITION
)
230 strcat(sname
, gsname
);
235 if (sname
[1] == 0 && ch
== EOL
)
237 if (SYMOFCHAR(ch
) == INTCONST
)
238 { linecontol(); return; }
239 if ((symptr
= findlorg(sname
)) == NULL
)
242 error(" bad control");
245 ctlcase
= symptr
->offset
.offsym
;
246 if (ifstate
.ifflag
== FALSE
&&
247 (ctlcase
< ELIFCNTL
|| ctlcase
> IFNDEFCNTL
))
255 error(" bad control");
273 error(" bad control");
283 ifcontrol(symptr
->offset
.offsym
);
289 { linecontol(); break; }
302 /* define() - process #define */
306 A symbol recording the macro name is added to the symbol table.
307 This overrides all current scopes of the name (put at head of hash chain).
308 The flags are set to DEFINITION.
309 The indcount is 0 if no parameters, else 1 + number of parameters.
310 The offset field points to the macro string.
311 The macro string is null-terminated but EOL-sentineled.
312 It consists of EOL-terminated substrings followed by parameter numbers,
313 e.g., junk(x,y)=-x+y is stored as '-', EOL, 1, '+', EOL, 2, EOL, 0.
314 Here 1 is for the 1st parameter (start at 1 so 0 can terminate).
315 EOL acts as a sentinel for the scanner.
316 This choice works well because EOL cannot occur in a macro string.
321 char sname
[NAMESIZE
];
323 struct symstruct
**hashptr
;
324 struct symstruct
*locmark
= NULL
; /* for -Wall */
328 struct symstruct
*symptr
;
332 error("illegal macro name");
335 strcpy(sname
, gsname
); /* will overwrite gsname if parameters */
339 newlevel(); /* temp storage for parameter names */
340 nparnames
= getparnames() + 1;
349 if (charptr
>= char1top
) /* check room for char and end of string */
350 macstring
= growobject(macstring
, 2);
351 if (nparnames
&& isident())
353 if ((symptr
= findlorg(gsname
)) != NULL
&&
354 symptr
->level
== level
)
357 ++ts_n_macstring_param
;
360 *charptr
++ = EOL
; /* end current string */
361 *charptr
++ = symptr
->indcount
; /* param to insert */
365 if (charptr
+ strlen(gsname
) >= chartop
) /* null too */
366 macstring
= growobject(macstring
, strlen(gsname
) + 1);
368 ++ts_n_macstring_ident
;
369 ts_s_macstring
+= strlen(gsname
);;
371 strcpy(charptr
, gsname
);
372 charptr
+= strlen(gsname
); /* discard null */
382 ++ts_n_macstring_quoted
;
394 else if (ch
== '"' || ch
== '\'')
398 if (SYMOFCHAR(*(lineptr
+ 1)) == SPECIALCHAR
)
401 ch
= *--lineptr
= '/'; /* pushback */
403 if (*(lineptr
+ 1) == '*')
408 /* comment is space in modern cpp's but they have '##' too */
409 ch
= *--lineptr
= ' ';
416 ++ts_n_macstring_ordinary
;
425 /* strip trailing blanks, but watch out for parameters */
427 rcp
> macstring
&& SYMOFCHAR(*(rcp
- 1)) == WHITESPACE
428 && (--rcp
== macstring
|| *(rcp
- 1) != EOL
); )
431 if (charptr
+1 >= char1top
)
432 macstring
= growobject(macstring
, 3);
434 ++ts_n_macstring_term
;
437 *charptr
++ = ' '; /* Added to prevent tail recursion on expansion */
445 /* if (asmmode) equ(sname, macstring); */
447 if ((symptr
= findlorg(sname
)) != NULL
&& symptr
->flags
== DEFINITION
)
449 if (strcmp(macstring
, oldstring
= symptr
->offset
.offp
) != 0)
450 error("%wredefined macro");
451 if (strlen(macstring
) > strlen(oldstring
= symptr
->offset
.offp
))
452 symptr
->offset
.offp
= macstring
;
455 strcpy(oldstring
, macstring
); /* copy if == to avoid test */
460 symptr
= qmalloc(sizeof (struct symstruct
) + strlen(sname
));
463 ts_s_defines
+= sizeof (struct symstruct
) + strlen(sname
);
465 addsym(sname
, vtype
, symptr
);
466 symptr
->storage
= DEF_NONE
;
467 symptr
->indcount
= nparnames
;
468 symptr
->flags
= DEFINITION
;
469 symptr
->level
= GLBLEVEL
;
470 symptr
->offset
.offp
= macstring
;
471 if (*(hashptr
= gethashptr(sname
)) != NULL
)
473 symptr
->next
= *hashptr
;
474 symptr
->next
->prev
= &symptr
->next
;
477 symptr
->prev
= hashptr
;
480 PRIVATE
void defineorundefinestring(str
, defineflag
)
481 char *str
; /* "name[=def]" or "name def" */
489 strcpy(fakeline
= (char *) ourmalloc(3 + len
+ 2 + 2) + 3, str
);
490 /* 3 pushback, 2 + 2 guards */
492 ts_s_fakeline
+= 3 + len
+ 2 + 2;
493 ts_s_fakeline_tot
+= 3 + len
+ 2 + 2;
496 register char *endfakeline
;
498 endfakeline
= fakeline
+ len
;
499 endfakeline
[0] = EOL
; /* guards any trailing backslash */
500 endfakeline
[1] = EOL
; /* line ends here or before */
503 eofile
= TRUE
; /* valid after first EOL */
504 ch
= *(lineptr
= fakeline
);
507 if (blanksident()) /* if not, let define() produce error */
518 lptr
[1] = '1'; /* 2 extra were allocated for this & EOL */
522 ch
= *(lineptr
= fakeline
);
529 ts_s_fakeline_tot
-= len
+ 2 + 2;
531 ourfree(fakeline
- 3);
534 PUBLIC
void definestring(str
)
535 char *str
; /* "name[=def]" or "name def" */
537 defineorundefinestring(str
, TRUE
);
540 /* docontrol() - process control statement, loop till "#if" is true */
542 PUBLIC
void docontrol()
566 /* elifcontrol() - process #elif */
568 PRIVATE
void elifcontrol()
572 error("elif without if");
575 if (ifstate
.elseflag
) {
576 register struct ifstruct
*ifptr
;
578 ifptr
= &ifstack
[(int)--iflevel
];
579 ifstate
.elseflag
= ifptr
->elseflag
;
580 ifstate
.ifflag
= ifptr
->ifflag
;
584 ifstate
.ifflag
= ifstate
.elseflag
;
585 ifstate
.elseflag
= FALSE
;
589 /* elsecontrol() - process #else */
591 PRIVATE
void elsecontrol()
595 error("else without if");
598 ifstate
.ifflag
= ifstate
.elseflag
;
599 ifstate
.elseflag
= FALSE
;
602 /* endif() - process #endif */
608 error("endif without if");
612 register struct ifstruct
*ifptr
;
614 ifptr
= &ifstack
[(int)--iflevel
];
615 ifstate
.elseflag
= ifptr
->elseflag
;
616 ifstate
.ifflag
= ifptr
->ifflag
;
620 /* entermac() - switch line ptr to macro string */
622 PUBLIC
void entermac()
625 struct symstruct
*symptr
;
632 if (maclevel
>= MAX_MACRO
)
634 limiterror("macros nested too deeply (33 levels)");
638 symptr
->name
.namea
[0] |= 0x80; /* SMUDGE macro definition */
641 if (symptr
->indcount
!= 0)
643 nparleft
= symptr
->indcount
- 1;
647 paramhead
= ourmalloc(sizeof *paramlist
* nparleft
);
648 paramlist
= paramhead
;
651 ts_s_macparam
+= sizeof *paramlist
* nparleft
;
652 ts_s_macparam_tot
+= sizeof *paramlist
* nparleft
;
655 while (ch
== EOL
&& !eofile
)
662 if (nparleft
> 0) /* macro has params, doesn't match bare word */
664 symptr
->name
.namea
[0] &= 0x7f; /* UnSMUDGE macro definition */
665 outstr(symptr
->name
.namea
);
668 error("missing '('");
677 *(paramlist
++) = charptr
;
685 if (charptr
>= char1top
)
686 *(paramlist
- 1) = growobject(*(paramlist
- 1), 2);
688 ++ts_n_macparam_string_quoted
;
689 ++ts_s_macparam_string
;
690 ++ts_s_macparam_string_tot
;
699 else if (ch
== '"' || ch
== '\'')
703 if (SYMOFCHAR(*(lineptr
+ 1)) == SPECIALCHAR
)
706 ch
= *--lineptr
= '/'; /* pushback */
708 if (*(lineptr
+ 1) == '*')
712 ch
= *--lineptr
= ' '; /* pushback */
717 else if ((ch
== ')' && --lpcount
== 0) ||
718 (ch
== ',' && lpcount
== 1))
722 if (charptr
>= char1top
)
723 *(paramlist
- 1) = growobject(*(paramlist
- 1), 2);
725 ++ts_n_macparam_string_ordinary
;
726 ++ts_s_macparam_string
;
727 ++ts_s_macparam_string_tot
;
732 skipeol(); /* macro case disposed of already */
733 if (SYMOFCHAR(ch
) == SPECIALCHAR
)
742 ++ts_n_macparam_string_term
;
743 ++ts_s_macparam_string
;
744 ++ts_s_macparam_string_tot
;
748 register char *newparam
;
749 register char *oldparam
;
752 oldparam
= *(paramlist
- 1);
753 size
= (/* size_t */ unsigned) (charptr
- oldparam
);
754 newparam
= ourmalloc(size
);
756 ts_s_macparam_string_alloced
+= size
;
757 ts_s_macparam_string_alloced_tot
+= size
;
759 memcpy(newparam
, oldparam
, size
);
760 *(paramlist
- 1) = newparam
;
762 ts_s_macparam_string_tot
-= charptr
- oldparam
;
773 while (ch
== EOL
&& !eofile
)
779 eofin("macro parameter expansion");
782 error("too few macro parameters");
784 *(paramlist
++) = dummyparam
;
791 error("too many macro parameters");
793 /* XXX - should read and discard extra parameters. Also check
809 error("missing ')'");
812 if (symptr
->storage
== DEF_LINE
)
816 str
= pushudec(symptr
->offset
.offp
+ MAX__LINE__
, input
.linenumber
);
817 memcpy(symptr
->offset
.offp
, str
, /* size_t */
818 (unsigned) (symptr
->offset
.offp
+ MAX__LINE__
+ 1 + 1 - str
));
822 register struct macroposition
*mpptr
;
824 mpptr
= ¯ostack
[maclevel
];
825 mpptr
->paramlist
= paramhead
;
826 mpptr
->maclineptr
= lineptr
;
827 ch
= *(lineptr
= symptr
->offset
.offp
);
828 mpptr
->inparam
= FALSE
;
829 mpptr
->nparam
= ngoodparams
;
830 mpptr
->symptr
= symptr
;
831 mpptr
->symptr
->name
.namea
[0] |= 0x80; /* SMUDGE macro definition */
836 outstr("MACRO (level ");
837 outudec((unsigned) maclevel);
843 /* getparnames() - get parameter names during macro definition, return count */
845 PRIVATE fastin_pt
getparnames()
848 struct symstruct
*symptr
;
852 while (blanksident())
854 if ((symptr
= findlorg(gsname
)) != NULL
&&
855 symptr
->level
== level
)
856 error("repeated parameter");
857 symptr
= addloc(gsname
, itype
);
858 if (nparnames
>= MAX_PARAM
)
859 limiterror("too many macro parameters (128)");
861 ++nparnames
; /* number params from 1 */
862 symptr
->indcount
= nparnames
; /* param number */
868 error("missing ')'");
874 /* ifcontrol - process #if, #ifdef, #ifndef */
876 PRIVATE
void ifcontrol(ifcase
)
880 struct symstruct
*symptr
;
882 if (iflevel
>= MAX_IF
)
884 limiterror("#if's nested too deeply (33 levels)");
888 register struct ifstruct
*ifptr
;
890 ifptr
= &ifstack
[(int)iflevel
++];
891 ifptr
->elseflag
= ifstate
.elseflag
;
892 ifptr
->ifflag
= ifstate
.ifflag
;
893 ifstate
.elseflag
= FALSE
; /* prepare for !(if now)||(if future)*/
897 if ((sym_t
) ifcase
!= IFCNTL
)
900 if (blanksident() && (symptr
= findlorg(gsname
)) != NULL
&&
901 symptr
->flags
== DEFINITION
)
908 iftrue
= constexpression() != 0;
911 if ((!iftrue
&& (sym_t
) ifcase
!= IFNDEFCNTL
) ||
912 (iftrue
&& (sym_t
) ifcase
== IFNDEFCNTL
))
914 ifstate
.elseflag
= TRUE
;
915 ifstate
.ifflag
= FALSE
;
920 /* ifinit() - initialise if state */
924 ifstate
.ifflag
= TRUE
;
929 return (ifstate
.ifflag
== TRUE
);
932 /* leavemac() - leave current and further macro substrings till not at end */
934 PUBLIC
void leavemac()
936 register struct macroposition
*mpptr
;
940 mpptr
= ¯ostack
[maclevel
- 1];
943 lineptr
= ++mpptr
->paramspot
;
944 mpptr
->inparam
= FALSE
;
948 mpptr
->symptr
->name
.namea
[0] &= 0x7F;/* UnSMUDGE macro definition */
949 ch
= *++lineptr
; /* gch1() would mess up next param == EOL-1 */
952 mpptr
->paramspot
= lineptr
;
953 lineptr
= mpptr
->paramlist
[ch
- 1];
954 mpptr
->inparam
= TRUE
;
958 lineptr
= mpptr
->maclineptr
;
959 if (mpptr
->nparam
!= 0)
961 register char **paramlist
;
964 ts_s_macparam_tot
-= sizeof *paramlist
* mpptr
->nparam
;
966 paramlist
= mpptr
->paramlist
;
970 ts_s_macparam_string_alloced_tot
-= strchr(*paramlist
, EOL
) - *paramlist
+ 1;
972 ourfree(*paramlist
++);
974 while (--mpptr
->nparam
!= 0);
975 ourfree(mpptr
->paramlist
);
981 while ((ch
= *lineptr
) == EOL
&& maclevel
!= 0);
984 PUBLIC
void predefine()
986 definestring("__BCC__ 1");
987 definestring("__LINE__ 0123456789"); /* MAX__LINE__ digits */
988 findlorg("__LINE__")->storage
= DEF_LINE
;
991 PUBLIC
char *savedlineptr()
993 return macrostack
[0].maclineptr
;
996 PUBLIC
void skipcomment()
998 /* Skip current char, then everything up to '*' '/' or eof. */
1006 register char *reglineptr
;
1008 reglineptr
= lineptr
;
1009 symofchar
['*'] = SPECIALCHAR
;
1010 while (SYMOFCHAR(*reglineptr
) != SPECIALCHAR
)
1012 symofchar
['*'] = STAR
;
1013 lineptr
= reglineptr
;
1014 if (*reglineptr
== '*')
1039 /* skipline() - skip rest of line */
1041 PUBLIC
void skipline()
1051 if (ch
== EOL
) /* XXX - I think blanks() eats \EOL */
1053 gch1(); /* XXX - escape() better? */
1055 else if (ch
== '"' || ch
== '\'')
1057 stringorcharconst();
1058 charptr
= constant
.value
.s
;
1065 /* undef() - process #undef */
1067 PRIVATE
void undef()
1069 struct symstruct
*symptr
;
1071 if (blanksident() && (symptr
= findlorg(gsname
)) != NULL
&&
1072 symptr
->flags
== DEFINITION
)
1076 PUBLIC
void undefinestring(str
)
1079 defineorundefinestring(str
, FALSE
);