852 lines
20 KiB
C
852 lines
20 KiB
C
|
/************************************************************************/
|
||
|
/* */
|
||
|
/* RCPP - Resource Compiler Pre-Processor for NT system */
|
||
|
/* */
|
||
|
/* P0PREPRO.C - Main Preprocessor */
|
||
|
/* */
|
||
|
/* 27-Nov-90 w-BrianM Update for NT from PM SDK RCPP */
|
||
|
/* */
|
||
|
/************************************************************************/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include "rcpptype.h"
|
||
|
#include "rcppdecl.h"
|
||
|
#include "rcppext.h"
|
||
|
#include "p0defs.h"
|
||
|
#include "charmap.h"
|
||
|
#include "grammar.h"
|
||
|
#include "trees.h"
|
||
|
#include "p1types.h"
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* Internal constants */
|
||
|
/************************************************************************/
|
||
|
#define GOT_IF 1 /* last nesting command was an if.. */
|
||
|
#define GOT_ELIF 2 /* last nesting command was an if.. */
|
||
|
#define GOT_ELSE 3 /* last nesting command was an else */
|
||
|
#define GOT_ENDIF 4 /* found endif */
|
||
|
#define ELSE_OR_ENDIF 5 /* skip to either #else or #endif */
|
||
|
#define ENDIF_ONLY 6 /* skip to #endif -- #else is an error*/
|
||
|
|
||
|
int ifstack[IFSTACK_SIZE];
|
||
|
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* Local Function Prototypes */
|
||
|
/************************************************************************/
|
||
|
void chk_newline(PCHAR);
|
||
|
void in_standard(void);
|
||
|
int incr_ifstack(void);
|
||
|
token_t next_control(void);
|
||
|
void pragma(void);
|
||
|
int skipto(int);
|
||
|
void skip_quoted(int);
|
||
|
PUCHAR sysinclude(void);
|
||
|
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* incr_ifstack - Increment the IF nesting stack */
|
||
|
/************************************************************************/
|
||
|
|
||
|
int incr_ifstack(void)
|
||
|
{
|
||
|
if(++Prep_ifstack >= IFSTACK_SIZE) {
|
||
|
Msg_Temp = GET_MSG (1052);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1052);
|
||
|
}
|
||
|
return(Prep_ifstack);
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
* SYSINCLUDE - process a system include : #include <foo>
|
||
|
*
|
||
|
* ARGUMENTS - none
|
||
|
*
|
||
|
* RETURNS - none
|
||
|
*
|
||
|
* SIDE EFFECTS - none
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Get the system include file name. Since the name is not a "string",
|
||
|
* the name must be built much the same as the -E option rebuilds the text
|
||
|
* by using the Tokstring expansion for tokens with no expansion already
|
||
|
*
|
||
|
* NOTE : IS THIS ANSI? note we're just reading chars, and not expanding
|
||
|
* any macros. NO, it's not. it must expand the macros.
|
||
|
* TODO : have it call yylex() unless and until it finds a '>' or a newline.
|
||
|
* (probably have to set On_pound_line to have yylex return the newline.)
|
||
|
*
|
||
|
* AUTHOR
|
||
|
* Ralph Ryan Sep. 1982
|
||
|
*
|
||
|
* MODIFICATIONS - none
|
||
|
*
|
||
|
*
|
||
|
************************************************************************/
|
||
|
PUCHAR sysinclude(void)
|
||
|
{
|
||
|
REG int c;
|
||
|
REG char *p_fname;
|
||
|
|
||
|
p_fname = Reuse_1;
|
||
|
c = skip_cwhite();
|
||
|
if( c == '\n' ) {
|
||
|
UNGETCH();
|
||
|
Msg_Temp = GET_MSG (2012);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
error(2012); /* missing name after '<' */
|
||
|
return(NULL);
|
||
|
}
|
||
|
while( c != '>' && c != '\n' ) {
|
||
|
*p_fname++ = (UCHAR)c; /* check for buffer overflow ??? */
|
||
|
c = get_non_eof();
|
||
|
}
|
||
|
if( c == '\n' ) {
|
||
|
UNGETCH();
|
||
|
Msg_Temp = GET_MSG (2013);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
error(2013); /* missing '>' */
|
||
|
return(NULL);
|
||
|
}
|
||
|
if(p_fname != Reuse_1) {
|
||
|
p_fname--;
|
||
|
while((p_fname >= Reuse_1) && isspace(*p_fname)) {
|
||
|
p_fname--;
|
||
|
}
|
||
|
p_fname++;
|
||
|
}
|
||
|
*p_fname = '\0';
|
||
|
return(Reuse_1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
** preprocess : the scanner found a # which was the first non-white char
|
||
|
** on a line.
|
||
|
************************************************************************/
|
||
|
void preprocess(void)
|
||
|
{
|
||
|
REG UCHAR c;
|
||
|
long eval;
|
||
|
int condition;
|
||
|
token_t deftok;
|
||
|
hln_t identifier;
|
||
|
|
||
|
if(Macro_depth != 0) { /* # only when not in a macro */
|
||
|
return;
|
||
|
}
|
||
|
switch(CHARMAP(c = skip_cwhite())) {
|
||
|
case LX_ID:
|
||
|
getid(c);
|
||
|
HLN_NAME(identifier) = Reuse_1;
|
||
|
HLN_LENGTH(identifier) = (UCHAR)Reuse_1_length;
|
||
|
HLN_HASH(identifier) = Reuse_1_hash;
|
||
|
break;
|
||
|
case LX_NL:
|
||
|
UNGETCH();
|
||
|
return;
|
||
|
default:
|
||
|
Msg_Temp = GET_MSG (2019);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, c);
|
||
|
error(2019); /* unknown preprocessor command */
|
||
|
skip_cnew(); /* finds a newline */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
On_pound_line = TRUE;
|
||
|
start:
|
||
|
switch(deftok = is_pkeyword(HLN_IDENTP_NAME(&identifier))) {
|
||
|
int old_prep;
|
||
|
|
||
|
case P0_DEFINE :
|
||
|
define();
|
||
|
break;
|
||
|
case P0_LINE :
|
||
|
old_prep = Prep;
|
||
|
Prep = FALSE;
|
||
|
yylex();
|
||
|
if(Basic_token != L_CINTEGER) { /* #line needs line number */
|
||
|
Msg_Temp = GET_MSG (2005);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, TS_STR(Basic_token));
|
||
|
error(2005); /* unknown preprocessor command */
|
||
|
Prep = old_prep;
|
||
|
skip_cnew();
|
||
|
On_pound_line = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
/*
|
||
|
** -1 because there's a newline at the end of this line
|
||
|
** which will be counted later when we find it.
|
||
|
** the #line says the next line is the number we've given
|
||
|
*/
|
||
|
Linenumber = TR_LVALUE(yylval.yy_tree) - 1;
|
||
|
yylex();
|
||
|
Prep = old_prep;
|
||
|
switch(Basic_token) {
|
||
|
case L_STRING:
|
||
|
if( strcmp(Filename, yylval.yy_string.str_ptr) != 0) {
|
||
|
strncpy(Filename,
|
||
|
yylval.yy_string.str_ptr,
|
||
|
sizeof(Filebuff)
|
||
|
);
|
||
|
}
|
||
|
case L_NOTOKEN:
|
||
|
break;
|
||
|
default:
|
||
|
Msg_Temp = GET_MSG (2130);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, TS_STR(Basic_token));
|
||
|
error(2130); /* #line needs a string */
|
||
|
skip_cnew();
|
||
|
On_pound_line = FALSE;
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
emit_line();
|
||
|
chk_newline("#line");
|
||
|
break;
|
||
|
case P0_INCLUDE :
|
||
|
old_prep = Prep;
|
||
|
Prep = FALSE;
|
||
|
InInclude = TRUE;
|
||
|
yylex();
|
||
|
InInclude = FALSE;
|
||
|
Prep = old_prep;
|
||
|
switch(Basic_token) {
|
||
|
case L_LT:
|
||
|
if((sysinclude()) == NULL) {
|
||
|
skip_cnew();
|
||
|
On_pound_line = FALSE;
|
||
|
return;
|
||
|
break; /* error already emitted */
|
||
|
}
|
||
|
yylval.yy_string.str_ptr = Reuse_1;
|
||
|
break;
|
||
|
case L_STRING:
|
||
|
break;
|
||
|
default:
|
||
|
Msg_Temp = GET_MSG (2006);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, TS_STR(Basic_token));
|
||
|
error(2006); /* needs file name */
|
||
|
skip_cnew();
|
||
|
On_pound_line = FALSE;
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
chk_newline("#include");
|
||
|
if( strchr(Path_chars, *yylval.yy_string.str_ptr) ||
|
||
|
(strchr(Path_chars, ':') && (yylval.yy_string.str_ptr[1] == ':'))) {
|
||
|
/*
|
||
|
** we have a string which either has a 1st char which is a path
|
||
|
** delimiter or, if ':' is a path delimiter (DOS), which has
|
||
|
** "<drive letter>:" as the first two characters. Such names
|
||
|
** specify a fully qualified pathnames. Do not append the search
|
||
|
** list, just look it up.
|
||
|
*/
|
||
|
if( ! newinput(yylval.yy_string.str_ptr,MAY_OPEN)) {
|
||
|
Msg_Temp = GET_MSG (1015);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, yylval.yy_string.str_ptr);
|
||
|
fatal (1015); /* can't find include file */
|
||
|
}
|
||
|
}
|
||
|
else if( (Basic_token != L_STRING) || (! nested_include())) {
|
||
|
in_standard();
|
||
|
}
|
||
|
break;
|
||
|
case P0_IFDEF :
|
||
|
case P0_IFNDEF :
|
||
|
if(CHARMAP(c = skip_cwhite()) != LX_ID) {
|
||
|
Msg_Temp = GET_MSG (1016);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1016);
|
||
|
}
|
||
|
getid(c);
|
||
|
eval = (get_defined()) ? TRUE : FALSE;
|
||
|
chk_newline((deftok == P0_IFDEF) ? "#ifdef" : "#ifndef");
|
||
|
if(deftok == P0_IFNDEF) {
|
||
|
eval = ( ! eval );
|
||
|
}
|
||
|
if( eval
|
||
|
||
|
||
|
((condition = skipto(ELSE_OR_ENDIF)) == GOT_ELSE)
|
||
|
) {
|
||
|
/*
|
||
|
** expression is TRUE or when we skipped the false part
|
||
|
** we found a #else that will be expanded.
|
||
|
*/
|
||
|
ifstack[incr_ifstack()] = GOT_IF;
|
||
|
}
|
||
|
else if(condition == GOT_ELIF) {
|
||
|
/* hash is wrong, but it won't be used */
|
||
|
HLN_NAME(identifier) = "if"; /* sleazy HACK */
|
||
|
goto start;
|
||
|
}
|
||
|
break;
|
||
|
case P0_IF :
|
||
|
old_prep = Prep;
|
||
|
Prep = FALSE;
|
||
|
InIf = TRUE;
|
||
|
eval = do_constexpr();
|
||
|
InIf = FALSE;
|
||
|
Prep = old_prep;
|
||
|
chk_newline(PPifel_str /* "#if/#elif" */);
|
||
|
if( (eval)
|
||
|
||
|
||
|
((condition = skipto(ELSE_OR_ENDIF)) == GOT_ELSE)
|
||
|
) {
|
||
|
/*
|
||
|
** expression is TRUE or when we skipped the false part
|
||
|
** we found a #else that will be expanded.
|
||
|
*/
|
||
|
ifstack[incr_ifstack()] = GOT_IF;
|
||
|
if(Eflag && !eval)
|
||
|
emit_line();
|
||
|
}
|
||
|
/*
|
||
|
** here the #if's expression was false, so we skipped until we found
|
||
|
** an #elif. we'll restart and fake that we're processing a #if
|
||
|
*/
|
||
|
else {
|
||
|
if(Eflag)
|
||
|
emit_line();
|
||
|
if(condition == GOT_ELIF) {
|
||
|
/* hash is wrong, but it won't be needed */
|
||
|
HLN_NAME(identifier) = "if"; /* sleazy HACK */
|
||
|
goto start;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case P0_ELIF :
|
||
|
/*
|
||
|
** here, we have found a #elif. first check to make sure that
|
||
|
** this is not an occurrance of a #elif with no preceding #if.
|
||
|
** (if Prep_ifstack < 0) then there is no preceding #if.
|
||
|
*/
|
||
|
if(Prep_ifstack-- < 0) {
|
||
|
Msg_Temp = GET_MSG (1018);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1018);
|
||
|
}
|
||
|
/*
|
||
|
** now, the preceding #if/#elif was true, and we've
|
||
|
** just found the next #elif. we want to skip all #else's
|
||
|
** and #elif's from here until we find the enclosing #endif
|
||
|
*/
|
||
|
while(skipto(ELSE_OR_ENDIF) != GOT_ENDIF) {
|
||
|
;
|
||
|
}
|
||
|
if(Eflag)
|
||
|
emit_line();
|
||
|
break;
|
||
|
case P0_ELSE : /* the preceding #if/#elif was true */
|
||
|
if((Prep_ifstack < 0) || (ifstack[Prep_ifstack--] != GOT_IF)) {
|
||
|
Msg_Temp = GET_MSG (1019);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1019); /* make sure there was one */
|
||
|
}
|
||
|
chk_newline(PPelse_str /* "#else" */);
|
||
|
skipto(ENDIF_ONLY);
|
||
|
if(Eflag)
|
||
|
emit_line();
|
||
|
break;
|
||
|
case P0_ENDIF : /* only way here is a lonely #endif */
|
||
|
if(Prep_ifstack-- < 0) {
|
||
|
Msg_Temp = GET_MSG (1020);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1020);
|
||
|
}
|
||
|
if(Eflag)
|
||
|
emit_line();
|
||
|
chk_newline(PPendif_str /* "#endif" */);
|
||
|
break;
|
||
|
case P0_PRAGMA :
|
||
|
pragma();
|
||
|
break;
|
||
|
case P0_UNDEF :
|
||
|
if(CHARMAP(c = skip_cwhite()) != LX_ID) {
|
||
|
Msg_Temp = GET_MSG (4006);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
warning(4006); /* missing identifier on #undef */
|
||
|
}
|
||
|
else {
|
||
|
getid(c);
|
||
|
undefine();
|
||
|
}
|
||
|
chk_newline("#undef");
|
||
|
break;
|
||
|
case P0_ERROR:
|
||
|
{
|
||
|
PUCHAR p;
|
||
|
|
||
|
p = Reuse_1;
|
||
|
while((c = get_non_eof()) != LX_EOS) {
|
||
|
if(c == '\n') {
|
||
|
UNGETCH();
|
||
|
break;
|
||
|
}
|
||
|
*p++ = c;
|
||
|
}
|
||
|
*p = '\0';
|
||
|
}
|
||
|
Msg_Temp = GET_MSG (2188);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, Reuse_1);
|
||
|
error(2188);
|
||
|
chk_newline("#error");
|
||
|
break;
|
||
|
case P0_IDENT:
|
||
|
old_prep = Prep ;
|
||
|
Prep = FALSE;
|
||
|
yylex();
|
||
|
Prep = old_prep;
|
||
|
if(Basic_token != L_STRING) {
|
||
|
Msg_Temp = GET_MSG (4079);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, TS_STR(Basic_token));
|
||
|
warning(4079);
|
||
|
}
|
||
|
chk_newline("#error");
|
||
|
break;
|
||
|
case P0_NOTOKEN:
|
||
|
Msg_Temp = GET_MSG (1021);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, HLN_IDENTP_NAME(&identifier));
|
||
|
fatal (1021);
|
||
|
break;
|
||
|
}
|
||
|
On_pound_line = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
* SKIPTO - skip code until the end of an undefined block is reached.
|
||
|
*
|
||
|
* ARGUMENTS
|
||
|
* short key - skip to an ELSE or ENDIF or just an ENDIF
|
||
|
*
|
||
|
* RETURNS - none
|
||
|
*
|
||
|
* SIDE EFFECTS
|
||
|
* - throws away input
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* The preprocessor is skipping code between failed ifdef, etc. and
|
||
|
* the corresponding ELSE or ENDIF (when key == ELSE_OR_ENDIF).
|
||
|
* Or it is skipping code between a failed ELSE and the ENDIF (when
|
||
|
* key == ENDIF_ONLY).
|
||
|
*
|
||
|
* AUTHOR - Ralph Ryan, Sept. 16, 1982
|
||
|
*
|
||
|
* MODIFICATIONS - none
|
||
|
*
|
||
|
************************************************************************/
|
||
|
int skipto(int key)
|
||
|
{
|
||
|
REG int level;
|
||
|
REG token_t tok;
|
||
|
|
||
|
level = 0;
|
||
|
tok = P0_NOTOKEN;
|
||
|
for(;;) {
|
||
|
/* make sure that IF [ELSE] ENDIF s are balanced */
|
||
|
switch(next_control()) {
|
||
|
case P0_IFDEF:
|
||
|
case P0_IFNDEF:
|
||
|
case P0_IF:
|
||
|
level++;
|
||
|
break;
|
||
|
case P0_ELSE:
|
||
|
tok = P0_ELSE;
|
||
|
/*
|
||
|
** FALLTHROUGH
|
||
|
*/
|
||
|
case P0_ELIF:
|
||
|
/*
|
||
|
** we found a #else or a #elif. these have their only chance
|
||
|
** at being valid if they're at level 0.
|
||
|
** if we're at any other level,
|
||
|
** then this else/elif belongs to some other #if and we skip them.
|
||
|
** if we were looking for an endif, the we have an error.
|
||
|
*/
|
||
|
if(level != 0) {
|
||
|
tok = P0_NOTOKEN;
|
||
|
break;
|
||
|
}
|
||
|
if(key == ENDIF_ONLY) {
|
||
|
Msg_Temp = GET_MSG (1022);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1022); /* expected #endif */
|
||
|
}
|
||
|
else if(tok == P0_ELSE) {
|
||
|
chk_newline(PPelse_str /* "#else" */);
|
||
|
return(GOT_ELSE);
|
||
|
}
|
||
|
else {
|
||
|
return(GOT_ELIF);
|
||
|
}
|
||
|
break;
|
||
|
case P0_ENDIF:
|
||
|
if(level == 0) {
|
||
|
chk_newline(PPendif_str /* "#endif" */);
|
||
|
return(GOT_ENDIF);
|
||
|
}
|
||
|
else {
|
||
|
level--;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
** in_standard : search for the given file name in the directory list.
|
||
|
** Input : ptr to include file name.
|
||
|
** Output : fatal error if not found.
|
||
|
*************************************************************************/
|
||
|
void in_standard(void)
|
||
|
{
|
||
|
int i;
|
||
|
int stop;
|
||
|
char *p_dir;
|
||
|
char *p_file;
|
||
|
char *p_tmp;
|
||
|
|
||
|
stop = Includes.li_top;
|
||
|
|
||
|
for(i = MAXLIST-1; i >= stop; i--) {
|
||
|
p_file = yylval.yy_string.str_ptr;
|
||
|
if( ((p_dir = Includes.li_defns[i])!=0) &&(strcmp(p_dir, "./") != 0) ) {
|
||
|
/*
|
||
|
** there is a directory to prepend and it's not './'
|
||
|
*/
|
||
|
p_tmp = Exp_ptr;
|
||
|
while((*p_tmp++ = *p_dir++) != 0)
|
||
|
;
|
||
|
/*
|
||
|
** above loop increments p_tmp past null.
|
||
|
** this replaces that null with a '/' if needed. Not needed if the
|
||
|
** last character of the directory spec is a path delimiter.
|
||
|
** we then point to the char after the '/'
|
||
|
*/
|
||
|
if(strchr(Path_chars, p_dir[-2]) == 0) {
|
||
|
p_tmp[-1] = '/';
|
||
|
}
|
||
|
else {
|
||
|
--p_tmp;
|
||
|
}
|
||
|
while((*p_tmp++ = *p_file++) != 0)
|
||
|
;
|
||
|
p_file = Exp_ptr;
|
||
|
}
|
||
|
if(newinput(p_file,MAY_OPEN)) { /* this is the non-error way out */
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
Msg_Temp = GET_MSG (1015);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, yylval.yy_string.str_ptr);
|
||
|
fatal (1015); /* can't find include file */
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
** chk_newline : check for whitespace only before a newline.
|
||
|
** eat the newline.
|
||
|
*************************************************************************/
|
||
|
void chk_newline(PCHAR cmd)
|
||
|
{
|
||
|
if(skip_cwhite() != '\n') {
|
||
|
Msg_Temp = GET_MSG (4067);
|
||
|
SET_MSG (Msg_Text, Msg_Temp, cmd);
|
||
|
warning(4067); /* cmd expected newline */
|
||
|
skip_cnew();
|
||
|
}
|
||
|
else {
|
||
|
UNGETCH();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
** skip_quoted : skips chars until it finds a char which matches its arg.
|
||
|
*************************************************************************/
|
||
|
void skip_quoted(int sc)
|
||
|
{
|
||
|
REG UCHAR c;
|
||
|
|
||
|
for(;;) {
|
||
|
switch(CHARMAP(c = GETCH())) {
|
||
|
case LX_NL:
|
||
|
Msg_Temp = GET_MSG (4093);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
warning(4093);
|
||
|
UNGETCH();
|
||
|
return;
|
||
|
break;
|
||
|
case LX_DQUOTE:
|
||
|
case LX_SQUOTE:
|
||
|
if(c == (UCHAR)sc)
|
||
|
return;
|
||
|
break;
|
||
|
case LX_EOS:
|
||
|
if(handle_eos() == BACKSLASH_EOS) {
|
||
|
SKIPCH(); /* might be /" !! */
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case LX_LEADBYTE:
|
||
|
get_non_eof();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
** next_control : find a newline. find a pound sign as the first non-white.
|
||
|
** find an id start char, build an id look it up and return the token.
|
||
|
** this knows about strings/char const and such.
|
||
|
*************************************************************************/
|
||
|
token_t next_control(void)
|
||
|
{
|
||
|
REG UCHAR c;
|
||
|
|
||
|
for(;;) {
|
||
|
c = skip_cwhite();
|
||
|
first_switch:
|
||
|
switch(CHARMAP(c)) {
|
||
|
case LX_NL:
|
||
|
Linenumber++;
|
||
|
if(Prep) {
|
||
|
fputc('\n', OUTPUTFILE);
|
||
|
}
|
||
|
if((c = skip_cwhite()) == '#') {
|
||
|
if(LX_IS_IDENT(c = skip_cwhite())) {
|
||
|
/*
|
||
|
** this is the only way to return to the caller.
|
||
|
*/
|
||
|
getid(c);
|
||
|
return(is_pkeyword(Reuse_1)); /* if its predefined */
|
||
|
}
|
||
|
}
|
||
|
goto first_switch;
|
||
|
break;
|
||
|
case LX_DQUOTE:
|
||
|
case LX_SQUOTE:
|
||
|
skip_quoted(c);
|
||
|
break;
|
||
|
case LX_EOS:
|
||
|
if(handle_eos() == BACKSLASH_EOS) {
|
||
|
SKIPCH(); /* might be \" !! */
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
** do_defined : does the work for the defined(id)
|
||
|
** should parens be counted, or just be used as delimiters (ie the
|
||
|
** first open paren matches the first close paren)? If this is ever
|
||
|
** an issue, it really means that there is not a legal identifier
|
||
|
** between the parens, causing an error anyway, but consider:
|
||
|
** #if (defined(2*(x-1))) || 1
|
||
|
** #endif
|
||
|
** It is friendlier to allow compilation to continue
|
||
|
*************************************************************************/
|
||
|
int do_defined(PUCHAR p_tmp)
|
||
|
{
|
||
|
REG UINT c;
|
||
|
REG int value=0;
|
||
|
int paren_level = 0;
|
||
|
|
||
|
/*
|
||
|
** we want to allow:
|
||
|
** #define FOO defined
|
||
|
** #define BAR(a,b) a FOO | b
|
||
|
** #define SNAFOO 0
|
||
|
** #if FOO BAR
|
||
|
** print("BAR is defined");
|
||
|
** #endif
|
||
|
** #if BAR(defined, SNAFOO)
|
||
|
** print("FOO is defined");
|
||
|
** #endif
|
||
|
*/
|
||
|
if(strcmp(p_tmp,"defined") != 0) {
|
||
|
return(0);
|
||
|
}
|
||
|
if((!can_get_non_white()) && (Tiny_lexer_nesting == 0)) {
|
||
|
/* NL encountered */
|
||
|
return(value);
|
||
|
}
|
||
|
if((c = CHECKCH())== '(') { /* assumes no other CHARMAP form of OPAREN */
|
||
|
*Exp_ptr++ = (UCHAR)c;
|
||
|
SKIPCH();
|
||
|
paren_level++;
|
||
|
if((!can_get_non_white()) && (Tiny_lexer_nesting == 0)) {
|
||
|
/* NL encountered */
|
||
|
return(value);
|
||
|
}
|
||
|
}
|
||
|
if(Tiny_lexer_nesting>0) {
|
||
|
if((CHARMAP(c=CHECKCH())==LX_MACFORMAL) || (CHARMAP(c)==LX_ID)) {
|
||
|
SKIPCH();
|
||
|
tl_getid((UCHAR)c);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if(LX_IS_IDENT(c = CHECKCH())) {
|
||
|
SKIPCH();
|
||
|
if(Macro_depth >0) {
|
||
|
lex_getid((UCHAR)c);
|
||
|
}
|
||
|
else {
|
||
|
getid((UCHAR)c);
|
||
|
}
|
||
|
value = (get_defined()) ? TRUE : FALSE;
|
||
|
}
|
||
|
else {
|
||
|
if(paren_level==0) {
|
||
|
Msg_Temp = GET_MSG (2003);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
error(2003);
|
||
|
}
|
||
|
else {
|
||
|
Msg_Temp = GET_MSG (2004);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
error(2004);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if((CHARMAP(c = CHECKCH()) == LX_WHITE) || (CHARMAP(c) == LX_EOS)) {
|
||
|
if( ! can_get_non_white()) {
|
||
|
return(value);
|
||
|
}
|
||
|
}
|
||
|
if(paren_level) {
|
||
|
if((CHARMAP(c = CHECKCH()) == LX_CPAREN)) {
|
||
|
SKIPCH();
|
||
|
paren_level--;
|
||
|
*Exp_ptr++ = (UCHAR)c;
|
||
|
}
|
||
|
}
|
||
|
if((paren_level > 0) && (Tiny_lexer_nesting == 0)) {
|
||
|
Msg_Temp = GET_MSG (4004);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
warning(4004);
|
||
|
}
|
||
|
return(value);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
* NEXTIS - The lexical interface for #if expression parsing.
|
||
|
* If the next token does not match what is wanted, return FALSE.
|
||
|
* otherwise Set Currtok to L_NOTOKEN to force scanning on the next call.
|
||
|
* Return TRUE.
|
||
|
* will leave a newline as next char if it finds one.
|
||
|
*************************************************************************/
|
||
|
int nextis(register token_t tok)
|
||
|
{
|
||
|
if(Currtok != L_NOTOKEN) {
|
||
|
if(tok == Currtok) {
|
||
|
Currtok = L_NOTOKEN; /* use up the token */
|
||
|
return(TRUE);
|
||
|
}
|
||
|
else {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
switch(yylex()) { /* acquire a new token */
|
||
|
case 0:
|
||
|
break;
|
||
|
case L_CONSTANT:
|
||
|
if( ! IS_INTEGRAL(TR_BTYPE(yylval.yy_tree))) {
|
||
|
Msg_Temp = GET_MSG (1017);
|
||
|
SET_MSG (Msg_Text, Msg_Temp);
|
||
|
fatal (1017);
|
||
|
}
|
||
|
else {
|
||
|
Currval = TR_LVALUE(yylval.yy_tree);
|
||
|
}
|
||
|
if(tok == L_CINTEGER) {
|
||
|
return(TRUE);
|
||
|
}
|
||
|
Currtok = L_CINTEGER;
|
||
|
break;
|
||
|
case L_IDENT:
|
||
|
Currval = do_defined(HLN_IDENTP_NAME(&yylval.yy_ident));
|
||
|
if(tok == L_CINTEGER) {
|
||
|
return(TRUE);
|
||
|
}
|
||
|
Currtok = L_CINTEGER;
|
||
|
break;
|
||
|
default:
|
||
|
if(tok == Basic_token) {
|
||
|
return(TRUE);
|
||
|
}
|
||
|
Currtok = Basic_token;
|
||
|
break;
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
** skip_cnew : reads up to and including the next newline.
|
||
|
************************************************************************/
|
||
|
void skip_cnew(void)
|
||
|
{
|
||
|
for(;;) {
|
||
|
switch(CHARMAP(GETCH())) {
|
||
|
case LX_NL:
|
||
|
UNGETCH();
|
||
|
return;
|
||
|
case LX_SLASH:
|
||
|
skip_comment();
|
||
|
break;
|
||
|
case LX_EOS:
|
||
|
handle_eos();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
** skip_NLonly : reads up to the next newline, disallowing comments
|
||
|
************************************************************************/
|
||
|
void skip_NLonly(void)
|
||
|
{
|
||
|
for(;;) {
|
||
|
switch(CHARMAP(GETCH())) {
|
||
|
case LX_NL:
|
||
|
UNGETCH();
|
||
|
return;
|
||
|
case LX_EOS:
|
||
|
handle_eos();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/************************************************************************
|
||
|
** pragma : handle processing the pragma directive
|
||
|
** called by preprocess() after we have seen the #pragma
|
||
|
** and are ready to handle the keyword which follows.
|
||
|
************************************************************************/
|
||
|
void pragma(void)
|
||
|
{
|
||
|
if(Prep) {
|
||
|
UCHAR c;
|
||
|
|
||
|
fwrite("#pragma", 7, 1, OUTPUTFILE);
|
||
|
while((c = get_non_eof()) != '\n') {
|
||
|
fputc(c, OUTPUTFILE);
|
||
|
}
|
||
|
UNGETCH();
|
||
|
return;
|
||
|
}
|
||
|
}
|