Windows-Server-2003/sdktools/hivepp/scanner.c

1133 lines
25 KiB
C

/************************************************************************/
/* */
/* RCPP - Resource Compiler Pre-Processor for NT system */
/* */
/* SCANNER.C - Routines for token scanning */
/* */
/* 29-Nov-90 w-BrianM Update for NT from PM SDK RCPP */
/* */
/************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include "rcpptype.h"
#include "rcppdecl.h"
#include "rcppext.h"
#include "p0defs.h"
#include "charmap.h"
#include "grammar.h"
#include "rcunicod.h"
#define ABS(x) ((x > 0) ? x : -1 * x)
#define ALERT_CHAR '\007' /* ANSI alert character is ASCII BEL */
extern int vfCurrFileType; //- Added for 16-bit file support.
/************************************************************************/
/* Local Function Prototypes */
/************************************************************************/
token_t c_size(long);
int ctoi(int);
int escape(int);
token_t get_real(PUCHAR);
token_t l_size(long);
long matol(PUCHAR, int);
token_t uc_size(long);
token_t ul_size(long);
void skip_1comment(void);
/************************************************************************/
/* local_c_hash */
/************************************************************************/
hash_t local_c_hash(REG char *name)
{
REG hash_t i;
i = 0;
while(*name) {
i += (*name & HASH_MASK);
name++;
}
return(i);
}
/************************************************************************
* GETID - Get an identifier or keyword.
* (we know that we're given at least 1 id char)
* in addition, we'll hash the value using 'c'.
************************************************************************/
void getid(REG UINT c)
{
REG UCHAR *p;
p = Reuse_1;
*p++ = (UCHAR)c;
c &= HASH_MASK;
repeat:
while(LXC_IS_IDENT(*p = GETCH())) { /* while it's an id char . . . */
c += (*p & HASH_MASK); /* hash it */
p++;
}
if(*p != EOS_CHAR) {
if((*p == '\\') && (checknl())) {
goto repeat;
}
UNGETCH();
if(p >= LIMIT(Reuse_1)) {
Msg_Temp = GET_MSG (1067);
SET_MSG (Msg_Text, Msg_Temp);
fatal(1067);
}
if( ((p - Reuse_1) > LIMIT_ID_LENGTH) && ( ! Prep )) {
p = Reuse_1 + LIMIT_ID_LENGTH;
*p++ = '\0';
c = local_c_hash(Reuse_1);
Msg_Temp = GET_MSG (4011);
SET_MSG (Msg_Text, Msg_Temp, Reuse_1);
warning(4011); /* id truncated */
}
else {
*p++ = '\0';
}
Reuse_1_hash = (UCHAR)c;
Reuse_1_length = (UCHAR)(p - Reuse_1);
return;
}
if(io_eob()) { /* end of file in middle of id */
Msg_Temp = GET_MSG (1004);
SET_MSG (Msg_Text, Msg_Temp);
fatal(1004);
}
goto repeat;
}
/************************************************************************
** prep_string : outputs char/string constants when preprocessing only
************************************************************************/
void prep_string(REG UCHAR c)
{
REG char *p_buf;
int term_char;
p_buf = Reuse_1;
term_char = c;
*p_buf++ = c; /* save the open quote */
//-
//- The following check was added to support 16-bit files.
//- For the 8-bit file, the code has not changed at all.
//-
if (vfCurrFileType == DFT_FILE_IS_8_BIT) {
for(;;) {
switch(CHARMAP(c = GETCH())) {
case LX_DQUOTE:
case LX_SQUOTE:
if(c == (UCHAR)term_char) {
*p_buf++ = (UCHAR)term_char;/* save the terminating quote */
goto out_of_loop;
}
break;
case LX_BACKSLASH:
case LX_LEADBYTE:
*p_buf++ = c;
c = get_non_eof();
break;
case LX_CR:
continue;
case LX_NL:
UNGETCH();
goto out_of_loop;
case LX_EOS:
if(c == '\\') {
*p_buf++ = c;
c = get_non_eof();
break;
}
handle_eos();
continue;
break;
}
*p_buf++ = c;
if(p_buf == &Reuse_1[MED_BUFFER - 1]) {
*p_buf = '\0';
fwrite(Reuse_1, (size_t)(p_buf - Reuse_1), 1, OUTPUTFILE);
p_buf = Reuse_1;
}
}
} else {
WCHAR wchCurr;
for(;;) {
wchCurr = (WCHAR)wchCheckWideChar ();
c = GETCH (); //- Make sure buffers increment normally.
if (wchCurr < 127) {
switch(CHARMAP(c)) {
case LX_DQUOTE:
case LX_SQUOTE:
if(c == (UCHAR)term_char) {
*p_buf++ = (UCHAR)term_char;/* save the quote */
goto out_of_loop;
}
break;
case LX_BACKSLASH:
*p_buf++ = c;
break;
case LX_CR:
continue;
case LX_NL:
UNGETCH();
goto out_of_loop;
case LX_EOS:
handle_eos ();
continue;
}
*p_buf++ = c;
} else {
//- Write out as 6 octal characters.
//- This is the safest way to do it.
*p_buf++ = '\\';
*p_buf++ = (CHAR)('0' + ((wchCurr >> 15) & 7));
*p_buf++ = (CHAR)('0' + ((wchCurr >> 12) & 7));
*p_buf++ = (CHAR)('0' + ((wchCurr >> 9) & 7));
*p_buf++ = (CHAR)('0' + ((wchCurr >> 6) & 7));
*p_buf++ = (CHAR)('0' + ((wchCurr >> 3) & 7));
*p_buf++ = (CHAR)('0' + (wchCurr & 7));
}
if(p_buf > &Reuse_1[MED_BUFFER - 10]) {
*p_buf = '\0';
fwrite(Reuse_1, (size_t)(p_buf - Reuse_1), 1, OUTPUTFILE);
p_buf = Reuse_1;
}
}
}
out_of_loop:
*p_buf = '\0';
fwrite(Reuse_1, (size_t)(p_buf - Reuse_1), 1, OUTPUTFILE);
}
/************************************************************************
** char_const : gather up a character constant
** we're called after finding the openning single quote.
************************************************************************/
token_t char_const(void)
{
REG UCHAR c;
value_t value;
token_t tok;
tok = (token_t)(Jflag ? L_CUNSIGNED : L_CINTEGER);
first_switch:
switch(CHARMAP(c = GETCH())) {
case LX_BACKSLASH:
break;
case LX_SQUOTE:
Msg_Temp = GET_MSG (2137);
SET_MSG (Msg_Text, Msg_Temp); /* empty character constant */
error(2137);
value.v_long = 0;
UNGETCH();
break;
case LX_EOS: /* ??? assumes i/o buffering > 1 char */
if(handle_eos() != BACKSLASH_EOS) {
goto first_switch;
}
value.v_long = escape(get_non_eof());
if( tok == L_CUNSIGNED ) { /* don't sign extend */
value.v_long &= 0xff;
}
break;
case LX_NL:
/* newline in character constant */
Msg_Temp = GET_MSG (2001);
SET_MSG(Msg_Text, Msg_Temp);
error (2001);
UNGETCH();
/*
** FALLTHROUGH
*/
default:
value.v_long = c;
break;
}
if((c = get_non_eof()) != '\'') {
Msg_Temp = GET_MSG (2015);
SET_MSG (Msg_Text, Msg_Temp);
error (2015); /* too many chars in constant */
do {
if(c == '\n') {
Msg_Temp = GET_MSG (2016);
SET_MSG (Msg_Text, Msg_Temp);
error(2016); /* missing closing ' */
break;
}
} while((c = get_non_eof()) != '\'');
}
yylval.yy_tree = build_const(tok, &value);
return(tok);
}
/************************************************************************
** str_const : gather up a string constant
************************************************************************/
void str_const(VOID)
{
REG UCHAR c;
REG PUCHAR p_buf;
int not_warned_yet = TRUE;
p_buf = yylval.yy_string.str_ptr = Macro_buffer;
/*
** Is it possible that reading this string during a rescan will
** overwrite the expansion being rescanned? No, because a macro
** expansion is limited to the top half of Macro_buffer.
** For Macro_depth > 0, this is like copying the string from
** somewhere in the top half of Macro_buffer to the bottom half
** of Macro_buffer.
** Note that the restriction on the size of an expanded macro is
** stricter than the limit on an L_STRING length. An expanded
** macro is limited to around 1019 bytes, but an L_STRING is
** limited to 2043 bytes.
*/
for(;;) {
switch(CHARMAP(c = GETCH())) {
case LX_NL:
UNGETCH();
Msg_Temp = GET_MSG (2001);
SET_MSG (Msg_Text, Msg_Temp);
error(2001);
/*
** FALLTHROUGH
*/
case LX_DQUOTE:
*p_buf++ = '\0';
yylval.yy_string.str_len = (USHORT)(p_buf-yylval.yy_string.str_ptr);
return;
break;
case LX_LEADBYTE:
*p_buf++ = c;
c = get_non_eof();
break;
case LX_EOS:
if(handle_eos() != BACKSLASH_EOS) {
continue;
}
if(InInclude) {
break;
}
else {
c = (UCHAR)escape(get_non_eof()); /* process escaped char */
}
break;
}
if(p_buf - Macro_buffer > LIMIT_STRING_LENGTH) {
if( not_warned_yet ) {
Msg_Temp = GET_MSG (4009);
SET_MSG (Msg_Text, Msg_Temp);
warning(4009); /* string too big, truncating */
not_warned_yet = FALSE;
}
}
else {
*p_buf++ = c;
}
}
}
/************************************************************************
** do_newline : does work after a newline has been found.
************************************************************************/
void do_newline()
{
++Linenumber;
for(;;) {
switch(CHARMAP(GETCH())) {
case LX_CR:
break;
case LX_POUND:
preprocess();
break;
case LX_SLASH:
if( ! skip_comment()) {
goto leave_do_newline;
}
break;
case LX_NL:
Linenumber++;
/*
** FALLTHROUGH
*/
case LX_WHITE:
if( Prep ) { /* preprocessing only, output whitespace */
fputc(PREVCH(), OUTPUTFILE);
}
else {
do {
;
} while(LXC_IS_WHITE(GETCH()));
UNGETCH();
}
break;
case LX_EOS:
if(PREVCH() == EOS_CHAR || PREVCH() == CONTROL_Z) {
if(io_eob()) { /* leaves us pointing at a valid char */
return;
}
break;
}
if(checknl()) {
continue;
}
/* it's a backslash */
/*
** FALLTHROUGH
*/
default: /* first non-white is not a '#', leave */
leave_do_newline:
UNGETCH();
return;
}
}
}
/************************************************************************
* GETNUM - Get a number from the input stream.
*
* ARGUMENTS
* radix - the radix of the number to be accumulated. Can only be 8, 10,
* or 16
* pval - a pointer to a VALUE union to be filled in with the value
*
* RETURNS - type of the token (L_CINTEGER or L_CFLOAT)
*
* SIDE EFFECTS -
* does push back on the input stream.
* writes into pval by reference
* uses buffer Reuse_1
*
* DESCRIPTION -
* Accumulate the number according to the rules for each radix.
* Set up the format string according to the radix (or distinguish
* integer from float if radix is 10) and convert to binary.
*
* AUTHOR - Ralph Ryan, Sept. 8, 1982
*
* MODIFICATIONS - none
*
************************************************************************/
token_t getnum(REG UCHAR c)
{
REG char *p;
UCHAR *start;
int radix;
token_t tok;
value_t value;
tok = L_CINTEGER;
start = (Tiny_lexer_nesting ? Exp_ptr : Reuse_1);
p = start;
if( c == '0' ) {
c = get_non_eof();
if( IS_X(c) ) {
radix = 16;
if( Prep ) {
*p++ = '0';
*p++ = 'x';
}
for(c = get_non_eof(); LXC_IS_XDIGIT(c); c = get_non_eof()) {
/* no check for overflow? */
*p++ = c;
}
if((p == Reuse_1) && (Tiny_lexer_nesting == 0)) {
Msg_Temp = GET_MSG (2153);
SET_MSG (Msg_Text, Msg_Temp);
error(2153);
}
goto check_suffix;
}
else {
radix = 8;
*p++ = '0'; /* for preprocessing or 0.xxx case */
}
}
else {
radix = 10;
}
while( LXC_IS_DIGIT(c) ) {
*p++ = c;
c = get_non_eof();
}
if( IS_DOT(c) || IS_E(c) ) {
UNGETCH();
return(get_real(p));
}
check_suffix:
if( IS_EL(c) ) {
if( Prep ) {
*p++ = c;
}
c = get_non_eof();
if( IS_U(c) ) {
if(Prep) {
*p++ = c;
}
tok = L_LONGUNSIGNED;
}
else {
tok = L_LONGINT;
UNGETCH();
}
}
else if( IS_U(c) ) {
if( Prep ) {
*p++ = c;
}
c = get_non_eof();
if( IS_EL(c) ) {
if( Prep ) {
*p++ = c;
}
tok = L_LONGUNSIGNED;
}
else {
tok = L_CUNSIGNED;
UNGETCH();
}
}
else {
UNGETCH();
}
*p = '\0';
if( start == Exp_ptr ) {
Exp_ptr = p;
return(L_NOTOKEN);
}
else if( Prep ) {
fwrite( Reuse_1, (size_t)(p - Reuse_1), 1, OUTPUTFILE);
return(L_NOTOKEN);
}
value.v_long = matol(Reuse_1,radix);
switch(tok) {
case L_CINTEGER:
tok = (radix == 10)
? c_size(value.v_long)
: uc_size(value.v_long)
;
break;
case L_LONGINT:
tok = l_size(value.v_long);
break;
case L_CUNSIGNED:
tok = ul_size(value.v_long);
break;
}
yylval.yy_tree = build_const(tok, &value);
return(tok);
}
/************************************************************************
** get_real : gathers the real part/exponent of a real number.
** Input : ptr to the null terminator of the whole part
** pointer to receive value.
** Output : L_CFLOAT
**
** ASSUMES whole part is either at Exp_ptr or Reuse_1.
************************************************************************/
token_t get_real(REG PUCHAR p)
{
REG int c;
token_t tok;
c = get_non_eof();
if(Cross_compile && (Tiny_lexer_nesting == 0)) {
Msg_Temp = GET_MSG (4012);
SET_MSG (Msg_Text, Msg_Temp);
warning(4012); /* float constant in cross compilation */
Cross_compile = FALSE; /* only one msg per file */
}
/*
** if the next char is a digit, then we've been called after
** finding a '.'. if this is true, then
** we want to find the fractional part of the number.
** if it's a '.', then we've been called after finding
** a whole part, and we want the fraction.
*/
if( LXC_IS_DIGIT(c) || IS_DOT(c) ) {
do {
*p++ = (UCHAR)c;
c = (int)get_non_eof();
} while( LXC_IS_DIGIT(c) );
}
if( IS_E(c) ) { /* now have found the exponent */
*p++ = (UCHAR)c; /* save the 'e' */
c = (UCHAR)get_non_eof(); /* skip it */
if( IS_SIGN(c) ) { /* optional sign */
*p++ = (UCHAR)c; /* save the sign */
c = (int)get_non_eof();
}
if( ! LXC_IS_DIGIT(c)) {
if( ! Rflag ) {
if(Tiny_lexer_nesting == 0) {
Msg_Temp = GET_MSG (2021);
SET_MSG (Msg_Text, Msg_Temp, c);
error(2021); /* missing or malformed exponent */
}
*p++ = '0';
}
}
else {
do { /* gather the exponent */
*p++ = (UCHAR)c;
c = (int)get_non_eof();
} while( LXC_IS_DIGIT(c) );
}
}
if( IS_F(c) ) {
tok = L_CFLOAT;
if( Prep ) {
*p++ = (UCHAR)c;
}
}
else if( IS_EL(c) ) {
tok = L_CLDOUBLE;
if( Prep ) {
*p++ = (UCHAR)c;
}
}
else {
UNGETCH();
tok = L_CDOUBLE;
}
*p = '\0';
if( Tiny_lexer_nesting > 0 ) {
Exp_ptr = p;
return(L_NOTOKEN);
}
else if( Prep ) {
fwrite( Reuse_1, (size_t)(p - Reuse_1), 1, OUTPUTFILE);
return(L_NOTOKEN);
}
/*
** reals aren't used during preprocessing
*/
return(tok);
}
/************************************************************************
** matol : ascii to long, given a radix.
************************************************************************/
long matol(REG PUCHAR p_start,REG int radix)
{
long result, old_result;
unsigned int i;
old_result = result = 0;
while(*p_start) {
result *= radix;
i = ctoi(*p_start);
if( ((int)i >= radix) && (! Prep) ) {
Msg_Temp = GET_MSG (2020);
SET_MSG (Msg_Text, Msg_Temp, *p_start, radix);
error(2020); /* illegal digit % for base % */
}
result += i;
p_start++;
if(radix == 10) {
if(result < old_result) {
p_start--; /* fix the string ptr since we have overflowed */
break;
}
}
else if(*p_start) {
/*
** the loop is not finished.
** we will multiply by the radix again
** check the upper bits. if they're on, then
** that mult will overflow the value
*/
if(radix == 8) {
if(result & 0xe0000000) {
break;
}
}
else if(result & 0xf0000000) {
break;
}
}
old_result = result;
}
if(*p_start) {
Msg_Temp = GET_MSG (2177);
SET_MSG (Msg_Text, Msg_Temp);
error(2177); /* constant too big */
result = 0;
}
return(result);
}
/************************************************************************
** uc_size : returns 'int' or 'long' (virtual unsigned).
** if their are no bits in the upper part of the value,
** then it's an int. otherwise, it's a long.
** this is valid too if target sizeof(int) != sizeof(long).
** then L_CINTEGER and L_LONGINT are synonymous.
************************************************************************/
token_t uc_size(long value)
{
return((token_t)((value > INT_MAX) ? L_CUNSIGNED : L_CINTEGER));
}
/************************************************************************
** c_size : returns 'int' or 'long' for signed numbers.
** if the sign bit of the lower word is on or any bits
** in the upper word are on, then we must use 'long'.
************************************************************************/
token_t c_size(long value)
{
return((token_t)((ABS(value) > INT_MAX) ? L_LONGINT : L_CINTEGER));
}
/************************************************************************
** l_size : returns 'longint' or 'longunsigned' for long numbers.
** if the sign bit of the high word is on this is 'longunsigned';
************************************************************************/
token_t l_size(long value)
{
return((token_t)((value > LONG_MAX) ? L_LONGUNSIGNED : L_LONGINT));
}
/************************************************************************
** ul_size : returns 'unsigned' or 'longunsigned' for unsigned numbers.
** if the number can't be represented as unsigned, it is promoted to
** unsignedlong.
************************************************************************/
token_t ul_size(long value)
{
return((token_t)((ABS(value) > UINT_MAX-1) ? L_LONGUNSIGNED : L_CUNSIGNED));
}
/************************************************************************
** ctoi : character to int.
************************************************************************/
int ctoi(int c)
{
if(LXC_IS_DIGIT(c)) {
return(c - '0');
}
else {
return(toupper(c) - toupper('A') + 10);
}
}
/************************************************************************
* ESCAPE - get an escaped character
*
* ARGUMENTS - none
*
* RETURNS - value of escaped character
*
* SIDE EFFECTS - may push back input
*
* DESCRIPTION - An escape ( '\' ) was discovered in the input. Translate
* the next symbol or symbols into an escape sequence.
*
* AUTHOR - Ralph Ryan, Sept. 7, 1982
*
* MODIFICATIONS - none
*
************************************************************************/
int escape(REG int c)
{
REG int value;
int cnt;
escape_again:
if( LXC_IS_ODIGIT(c) ) {/* \ooo is an octal number, must fit into a byte */
cnt = 1;
for(value = ctoi(c), c = get_non_eof();
(cnt < 3) && LXC_IS_ODIGIT(c);
cnt++, c = get_non_eof()
) {
value *= 8;
value += ctoi(c);
}
if( ! Prep ) {
if(value > 255) {
Msg_Temp = GET_MSG (2022);
SET_MSG (Msg_Text, Msg_Temp, value);
error (2022);
}
}
UNGETCH();
return((char)value);
}
switch( c ) {
case 'a':
return(ALERT_CHAR);
break;
case 'b':
return('\b');
break;
case 'f':
return('\f');
break;
case 'n':
return('\n');
break;
case 'r':
return('\r');
break;
case 't':
return('\t');
break;
case 'v':
return('\v');
break;
case 'x':
cnt = 0;
value = 0;
c = get_non_eof();
while((cnt < 3) && LXC_IS_XDIGIT(c)) {
value *= 16;
value += ctoi(c);
c = get_non_eof();
cnt++;
}
if(cnt == 0) {
Msg_Temp = GET_MSG (2153);
SET_MSG (Msg_Text, Msg_Temp);
error (2153);
}
UNGETCH();
return((char)value); /* cast to get sign extend */
default:
if(c != '\\') {
return(c);
}
else {
if(checknl()) {
c = get_non_eof();
goto escape_again;
}
else {
return(c);
}
}
}
}
/************************************************************************
* CHECKOP - Check whether the next input character matches the argument.
*
* ARGUMENTS
* short op - the character to be checked against
*
* RETURNS
* TRUE or FALSE
*
* SIDE EFFECTS
* Will push character back onto the input if there is no match.
*
* DESCRIPTION
* If the next input character matches op, return TRUE. Otherwise
* push it back onto the input.
*
* AUTHOR - Ralph Ryan, Sept. 9, 1982
*
* MODIFICATIONS - none
*
************************************************************************/
int checkop(int op)
{
if(op == (int)get_non_eof()) {
return(TRUE);
}
UNGETCH();
return(FALSE);
}
/************************************************************************
** DumpSlashComment : while skipping a comment, output it.
************************************************************************/
void DumpSlashComment(VOID)
{
if( ! Cflag ) {
skip_NLonly();
return;
}
fwrite("//", 2, 1, OUTPUTFILE);
for(;;) {
REG UCHAR c;
switch(CHARMAP(c = GETCH())) {
case LX_CR:
continue;
case LX_EOS:
handle_eos();
continue;
case LX_NL:
UNGETCH();
return;
}
fputc(c, OUTPUTFILE);
}
}
/************************************************************************
** dump_comment : while skipping a comment, output it.
************************************************************************/
void dump_comment()
{
if( ! Cflag ) {
skip_1comment();
return;
}
fwrite("/*", 2, 1, OUTPUTFILE);
for(;;) {
REG UCHAR c;
switch(CHARMAP(c = GETCH())) {
case LX_STAR:
if(checkop('/')) {
fwrite("*/", 2, 1, OUTPUTFILE);
return;
}
break;
case LX_EOS:
handle_eos();
continue;
case LX_NL:
Linenumber++;
break; /* output below */
case LX_CR:
continue;
}
fputc(c, OUTPUTFILE);
}
}
/************************************************************************/
/* skip_comment() */
/************************************************************************/
int skip_comment(void)
{
if(checkop('*')) {
skip_1comment();
return(TRUE);
}
else if(checkop('/')) {
skip_NLonly();
return(TRUE);
}
else {
return(FALSE);
}
}
/************************************************************************
** skip_1comment : we're called when we're already in a comment.
** we're looking for the comment close. we also count newlines
** and output them if we're preprocessing.
************************************************************************/
void skip_1comment(void)
{
UINT c;
for(;;) {
c = GETCH();
if(c == '*') {
recheck:
c = GETCH();
if(c == '/') { /* end of comment */
return;
}
else if(c == '*') {
/*
** if we get another '*' go back and check for a slash
*/
goto recheck;
}
else if(c == EOS_CHAR) {
handle_eos();
goto recheck;
}
}
/*
** note we fall through here. we know this baby is not a '*'
** we used to unget the char and continue. since we check for
** another '*' inside the above test, we can fall through here
** without ungetting/getting and checking again.
*/
if(c <= '\n') {
/*
** hopefully, the above test is less expensive than doing two tests
*/
if(c == '\n') {
Linenumber++;
if(Prep) {
fputc('\n', OUTPUTFILE);
}
}
else if(c == EOS_CHAR) {
handle_eos();
}
}
}
}
/************************************************************************
** skip_cwhite : while the current character is whitespace or a comment.
** a newline is NOT whitespace.
************************************************************************/
UCHAR skip_cwhite(void)
{
REG UCHAR c;
skip_cwhite_again:
while((c = GETCH()) <= '/') { /* many chars are above this */
if(c == '/') {
if( ! skip_comment()) {
return('/');
}
}
else if(c > ' ') { /* char is between '!' and '.' */
return(c);
}
else {
switch(CHARMAP(c)) {
case LX_EOS:
handle_eos();
break;
case LX_WHITE:
continue;
break;
case LX_CR:
continue;
break;
default:
return(c);
break;
}
}
}
if((c == '\\') && (checknl())) {
goto skip_cwhite_again;
}
return(c);
}
/************************************************************************
** checknl : check for newline, skipping carriage return if there is one.
** also increments Linenumber, so this should be used by routines which
** will not push the newline back in such a way that rawtok() will be invoked,
** find the newline and do another increment.
************************************************************************/
int checknl(void)
{
REG UCHAR c;
for(;;) {
c = GETCH();
if(c > '\r') {
UNGETCH();
return(FALSE);
}
switch(c) {
case '\n':
Linenumber++;
if( Prep ) {
fputc('\n', OUTPUTFILE);
}
return(TRUE);
break;
case '\r':
continue;
break;
case EOS_CHAR:
handle_eos();
PREVCH() = '\\'; /* M00HACK - needs pushback */
continue;
break;
default:
UNGETCH();
return(FALSE);
break;
}
}
}
/************************************************************************
** get_non_eof : get a real char.
************************************************************************/
UCHAR get_non_eof(void)
{
UCHAR c;
get_non_eof_again:
while((c = GETCH()) <= '\r') {
if(c == '\r') {
continue;
}
else if(c != EOS_CHAR) {
break;
}
if(Tiny_lexer_nesting > 0) {
break;
}
handle_eos();
}
if((c == '\\') && (checknl())) {
goto get_non_eof_again;
}
return(c);
}