mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-02 11:00:37 +08:00
Initial revision
From-SVN: r9191
This commit is contained in:
parent
b310a51d35
commit
7f2935c734
81
gcc/cppalloc.c
Normal file
81
gcc/cppalloc.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* Part of CPP library. (memory allocation - xmalloc etc)
|
||||
Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994.
|
||||
Based on CCCP program by by Paul Rubin, June 1986
|
||||
Adapted to ANSI C, Richard Stallman, Jan 1987
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
static void
|
||||
memory_full ()
|
||||
{
|
||||
fatal ("Memory exhausted.");
|
||||
}
|
||||
|
||||
char *
|
||||
xmalloc (size)
|
||||
unsigned size;
|
||||
{
|
||||
register char *ptr = (char *) malloc (size);
|
||||
if (ptr != 0) return (ptr);
|
||||
memory_full ();
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
xrealloc (old, size)
|
||||
char *old;
|
||||
unsigned size;
|
||||
{
|
||||
register char *ptr = (char *) realloc (old, size);
|
||||
if (ptr != 0) return (ptr);
|
||||
memory_full ();
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
xcalloc (number, size)
|
||||
unsigned number, size;
|
||||
{
|
||||
register unsigned total = number * size;
|
||||
register char *ptr = (char *) malloc (total);
|
||||
if (ptr != 0) {
|
||||
if (total > 100)
|
||||
bzero (ptr, total);
|
||||
else {
|
||||
/* It's not too long, so loop, zeroing by longs.
|
||||
It must be safe because malloc values are always well aligned. */
|
||||
register long *zp = (long *) ptr;
|
||||
register long *zl = (long *) (ptr + total - 4);
|
||||
register int i = total - 4;
|
||||
while (zp < zl)
|
||||
*zp++ = 0;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
while (i < total)
|
||||
ptr[i++] = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
memory_full ();
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
338
gcc/cpperror.c
Normal file
338
gcc/cpperror.c
Normal file
@ -0,0 +1,338 @@
|
||||
/* Default error handlers for CPP Library.
|
||||
Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994.
|
||||
Based on CCCP program by by Paul Rubin, June 1986
|
||||
Adapted to ANSI C, Richard Stallman, Jan 1987
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#include "cpplib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* This defines "errno" properly for VMS, and gives us EACCES. */
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef VMS
|
||||
#ifndef HAVE_STRERROR
|
||||
extern int sys_nerr;
|
||||
#if defined(bsd4_4) || defined(__NetBSD__)
|
||||
extern const char *const sys_errlist[];
|
||||
#else
|
||||
extern char *sys_errlist[];
|
||||
#endif
|
||||
#else /* HAVE_STERRROR */
|
||||
char *strerror ();
|
||||
#endif
|
||||
#else /* VMS */
|
||||
char *strerror (int,...);
|
||||
#endif
|
||||
|
||||
/* Print the file names and line numbers of the #include
|
||||
commands which led to the current file. */
|
||||
|
||||
void
|
||||
cpp_print_containing_files (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
cpp_buffer *ip;
|
||||
int i;
|
||||
int first = 1;
|
||||
|
||||
/* If stack of files hasn't changed since we last printed
|
||||
this info, don't repeat it. */
|
||||
if (pfile->input_stack_listing_current)
|
||||
return;
|
||||
|
||||
ip = cpp_file_buffer (pfile);
|
||||
|
||||
/* Give up if we don't find a source file. */
|
||||
if (ip == NULL)
|
||||
return;
|
||||
|
||||
/* Find the other, outer source files. */
|
||||
while ((ip = CPP_PREV_BUFFER (ip)), ip != CPP_NULL_BUFFER (pfile))
|
||||
{
|
||||
long line, col;
|
||||
cpp_buf_line_and_col (ip, &line, &col);
|
||||
if (ip->fname != NULL)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = 0;
|
||||
fprintf (stderr, "In file included");
|
||||
}
|
||||
else
|
||||
fprintf (stderr, ",\n ");
|
||||
}
|
||||
|
||||
/* start-sanitize-mpw */
|
||||
#ifdef MPW
|
||||
fprintf (stderr, " File \"%s\"; Line %d # ", ip->nominal_fname, line);
|
||||
#else
|
||||
/* end-sanitize-mpw */
|
||||
fprintf (stderr, " from %s:%d", ip->nominal_fname, line);
|
||||
/* start-sanitize-mpw */
|
||||
#endif /* MPW */
|
||||
/* end-sanitize-mpw */
|
||||
}
|
||||
if (! first)
|
||||
fprintf (stderr, ":\n");
|
||||
|
||||
/* Record we have printed the status as of this time. */
|
||||
pfile->input_stack_listing_current = 1;
|
||||
}
|
||||
|
||||
void
|
||||
cpp_print_file_and_line (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
cpp_buffer *ip = cpp_file_buffer (pfile);
|
||||
|
||||
if (ip != NULL)
|
||||
{
|
||||
long line, col;
|
||||
cpp_buf_line_and_col (ip, &line, &col);
|
||||
if (pfile->show_column)
|
||||
fprintf (stderr, "%s:%d:%d: ", ip->nominal_fname, line, col);
|
||||
else
|
||||
fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpp_error (pfile, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
cpp_print_containing_files (pfile);
|
||||
cpp_print_file_and_line (pfile);
|
||||
fprintf (stderr, msg, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
pfile->errors++;
|
||||
}
|
||||
|
||||
/* Print error message but don't count it. */
|
||||
|
||||
void
|
||||
cpp_warning (pfile, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
if (CPP_OPTIONS (pfile)->inhibit_warnings)
|
||||
return;
|
||||
|
||||
if (CPP_OPTIONS (pfile)->warnings_are_errors)
|
||||
pfile->errors++;
|
||||
|
||||
cpp_print_containing_files (pfile);
|
||||
cpp_print_file_and_line (pfile);
|
||||
fprintf (stderr, "warning: ");
|
||||
fprintf (stderr, msg, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
cpp_error_with_line (pfile, line, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
int line;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
int i;
|
||||
cpp_buffer *ip = cpp_file_buffer (pfile);
|
||||
|
||||
cpp_print_containing_files (pfile);
|
||||
|
||||
if (ip != NULL)
|
||||
fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
|
||||
|
||||
fprintf (stderr, msg, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
pfile->errors++;
|
||||
}
|
||||
|
||||
void
|
||||
cpp_warning_with_line (pfile, line, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
int line;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
int i;
|
||||
cpp_buffer *ip;
|
||||
|
||||
if (CPP_OPTIONS (pfile)->inhibit_warnings)
|
||||
return;
|
||||
|
||||
if (CPP_OPTIONS (pfile)->warnings_are_errors)
|
||||
pfile->errors++;
|
||||
|
||||
cpp_print_containing_files (pfile);
|
||||
|
||||
ip = cpp_file_buffer (pfile);
|
||||
|
||||
if (ip != NULL)
|
||||
fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
|
||||
fprintf (stderr, "warning: ");
|
||||
fprintf (stderr, msg, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
/* Print an error message and maybe count it. */
|
||||
|
||||
void
|
||||
cpp_pedwarn (pfile, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
if (CPP_OPTIONS (pfile)->pedantic_errors)
|
||||
cpp_error (pfile, msg, arg1, arg2, arg3);
|
||||
else
|
||||
cpp_warning (pfile, msg, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
void
|
||||
cpp_pedwarn_with_line (pfile, line, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
int line;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
if (CPP_OPTIONS (pfile)->pedantic_errors)
|
||||
cpp_error_with_line (pfile, line, msg, arg1, arg2, arg3);
|
||||
else
|
||||
cpp_warning_with_line (pfile, line, msg, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
/* Report a warning (or an error if pedantic_errors)
|
||||
giving specified file name and line number, not current. */
|
||||
|
||||
void
|
||||
cpp_pedwarn_with_file_and_line (pfile, file, line, msg, arg1, arg2, arg3)
|
||||
cpp_reader *pfile;
|
||||
char *file;
|
||||
int line;
|
||||
char *msg;
|
||||
char *arg1, *arg2, *arg3;
|
||||
{
|
||||
if (!CPP_OPTIONS (pfile)->pedantic_errors
|
||||
&& CPP_OPTIONS (pfile)->inhibit_warnings)
|
||||
return;
|
||||
if (file != NULL)
|
||||
fprintf (stderr, "%s:%d: ", file, line);
|
||||
if (CPP_OPTIONS (pfile)->pedantic_errors)
|
||||
pfile->errors++;
|
||||
else
|
||||
fprintf (stderr, "warning: ");
|
||||
fprintf (stderr, msg, arg1, arg2, arg3);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
fatal (str, arg)
|
||||
char *str, *arg;
|
||||
{
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
fprintf (stderr, str, arg);
|
||||
fprintf (stderr, "\n");
|
||||
exit (FAILURE_EXIT_CODE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* my_strerror - return the descriptive text associated with an `errno' code.
|
||||
*/
|
||||
|
||||
char *
|
||||
my_strerror (errnum)
|
||||
int errnum;
|
||||
{
|
||||
char *result;
|
||||
|
||||
#ifndef VMS
|
||||
#ifndef HAVE_STRERROR
|
||||
result = (char *) ((errnum < sys_nerr) ? sys_errlist[errnum] : 0);
|
||||
#else
|
||||
result = strerror (errnum);
|
||||
#endif
|
||||
#else /* VMS */
|
||||
/* VAXCRTL's strerror() takes an optional second argument, which only
|
||||
matters when the first argument is EVMSERR. However, it's simplest
|
||||
just to pass it unconditionally. `vaxc$errno' is declared in
|
||||
<errno.h>, and maintained by the library in parallel with `errno'.
|
||||
We assume that caller's `errnum' either matches the last setting of
|
||||
`errno' by the library or else does not have the value `EVMSERR'. */
|
||||
|
||||
result = strerror (errnum, vaxc$errno);
|
||||
#endif
|
||||
|
||||
if (!result)
|
||||
result = "undocumented I/O error";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Error including a message from `errno'. */
|
||||
|
||||
void
|
||||
cpp_error_from_errno (pfile, name)
|
||||
cpp_reader *pfile;
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
cpp_buffer *ip = cpp_file_buffer (pfile);
|
||||
|
||||
cpp_print_containing_files (pfile);
|
||||
|
||||
if (ip != NULL)
|
||||
fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
|
||||
|
||||
fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
|
||||
|
||||
pfile->errors++;
|
||||
}
|
||||
|
||||
void
|
||||
cpp_perror_with_name (pfile, name)
|
||||
cpp_reader *pfile;
|
||||
char *name;
|
||||
{
|
||||
fprintf (stderr, "%s: ", progname);
|
||||
fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
|
||||
pfile->errors++;
|
||||
}
|
||||
|
||||
void
|
||||
cpp_pfatal_with_name (pfile, name)
|
||||
cpp_reader *pfile;
|
||||
char *name;
|
||||
{
|
||||
cpp_perror_with_name (pfile, name);
|
||||
#ifdef VMS
|
||||
exit (vaxc$errno);
|
||||
#else
|
||||
exit (FAILURE_EXIT_CODE);
|
||||
#endif
|
||||
}
|
988
gcc/cppexp.c
Normal file
988
gcc/cppexp.c
Normal file
@ -0,0 +1,988 @@
|
||||
/* Parse C expressions for CCCP.
|
||||
Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding!
|
||||
|
||||
Written by Per Bothner 1994. */
|
||||
|
||||
/* Parse a C expression from text in a string */
|
||||
|
||||
#include "config.h"
|
||||
#include "cpplib.h"
|
||||
|
||||
#ifdef MULTIBYTE_CHARS
|
||||
#include <stdlib.h>
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* This is used for communicating lists of keywords with cccp.c. */
|
||||
struct arglist {
|
||||
struct arglist *next;
|
||||
U_CHAR *name;
|
||||
int length;
|
||||
int argno;
|
||||
};
|
||||
|
||||
/* Define a generic NULL if one hasn't already been defined. */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef GENERIC_PTR
|
||||
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
|
||||
#define GENERIC_PTR void *
|
||||
#else
|
||||
#define GENERIC_PTR char *
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL_PTR
|
||||
#define NULL_PTR ((GENERIC_PTR)0)
|
||||
#endif
|
||||
|
||||
extern char *xmalloc ();
|
||||
|
||||
#ifndef CHAR_TYPE_SIZE
|
||||
#define CHAR_TYPE_SIZE BITS_PER_UNIT
|
||||
#endif
|
||||
|
||||
#ifndef INT_TYPE_SIZE
|
||||
#define INT_TYPE_SIZE BITS_PER_WORD
|
||||
#endif
|
||||
|
||||
#ifndef LONG_TYPE_SIZE
|
||||
#define LONG_TYPE_SIZE BITS_PER_WORD
|
||||
#endif
|
||||
|
||||
#ifndef WCHAR_TYPE_SIZE
|
||||
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef MAX_CHAR_TYPE_SIZE
|
||||
#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef MAX_INT_TYPE_SIZE
|
||||
#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef MAX_LONG_TYPE_SIZE
|
||||
#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef MAX_WCHAR_TYPE_SIZE
|
||||
#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
|
||||
#endif
|
||||
|
||||
/* Yield nonzero if adding two numbers with A's and B's signs can yield a
|
||||
number with SUM's sign, where A, B, and SUM are all C integers. */
|
||||
#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
|
||||
|
||||
static void integer_overflow ();
|
||||
static long left_shift ();
|
||||
static long right_shift ();
|
||||
|
||||
#define ERROR 299
|
||||
#define OROR 300
|
||||
#define ANDAND 301
|
||||
#define EQUAL 302
|
||||
#define NOTEQUAL 303
|
||||
#define LEQ 304
|
||||
#define GEQ 305
|
||||
#define LSH 306
|
||||
#define RSH 307
|
||||
#define NAME 308
|
||||
#define INT 309
|
||||
#define CHAR 310
|
||||
|
||||
#define LEFT_OPERAND_REQUIRED 1
|
||||
#define RIGHT_OPERAND_REQUIRED 2
|
||||
#define HAVE_VALUE 4
|
||||
/*#define UNSIGNEDP 8*/
|
||||
|
||||
struct operation {
|
||||
short op;
|
||||
char rprio; /* Priority of op (relative to it right operand). */
|
||||
char flags;
|
||||
char unsignedp; /* true if value should be treated as unsigned */
|
||||
long value; /* The value logically "right" of op. */
|
||||
};
|
||||
|
||||
/* Take care of parsing a number (anything that starts with a digit).
|
||||
LEN is the number of characters in it. */
|
||||
|
||||
/* maybe needs to actually deal with floating point numbers */
|
||||
|
||||
struct operation
|
||||
parse_number (pfile, start, olen)
|
||||
cpp_reader *pfile;
|
||||
char *start;
|
||||
int olen;
|
||||
{
|
||||
struct operation op;
|
||||
register char *p = start;
|
||||
register int c;
|
||||
register unsigned long n = 0, nd, ULONG_MAX_over_base;
|
||||
register int base = 10;
|
||||
register int len = olen;
|
||||
register int overflow = 0;
|
||||
register int digit, largest_digit = 0;
|
||||
int spec_long = 0;
|
||||
|
||||
op.unsignedp = 0;
|
||||
|
||||
for (c = 0; c < len; c++)
|
||||
if (p[c] == '.') {
|
||||
/* It's a float since it contains a point. */
|
||||
cpp_error (pfile,
|
||||
"floating point numbers not allowed in #if expressions");
|
||||
op.op = ERROR;
|
||||
return op;
|
||||
}
|
||||
|
||||
if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
|
||||
p += 2;
|
||||
base = 16;
|
||||
len -= 2;
|
||||
}
|
||||
else if (*p == '0')
|
||||
base = 8;
|
||||
|
||||
ULONG_MAX_over_base = (unsigned long) -1 / base;
|
||||
/* start-sanitize-mpw */
|
||||
/* Work around yet another MPW C bug. */
|
||||
#ifdef MPW_C
|
||||
ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
|
||||
#endif /* MPW_C */
|
||||
/* end-sanitize-mpw */
|
||||
|
||||
for (; len > 0; len--) {
|
||||
c = *p++;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
digit = c - '0';
|
||||
else if (base == 16 && c >= 'a' && c <= 'f')
|
||||
digit = c - 'a' + 10;
|
||||
else if (base == 16 && c >= 'A' && c <= 'F')
|
||||
digit = c - 'A' + 10;
|
||||
else {
|
||||
/* `l' means long, and `u' means unsigned. */
|
||||
while (1) {
|
||||
if (c == 'l' || c == 'L')
|
||||
{
|
||||
if (spec_long)
|
||||
cpp_error (pfile, "two `l's in integer constant");
|
||||
spec_long = 1;
|
||||
}
|
||||
else if (c == 'u' || c == 'U')
|
||||
{
|
||||
if (op.unsignedp)
|
||||
cpp_error (pfile, "two `u's in integer constant");
|
||||
op.unsignedp = 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (--len == 0)
|
||||
break;
|
||||
c = *p++;
|
||||
}
|
||||
/* Don't look for any more digits after the suffixes. */
|
||||
break;
|
||||
}
|
||||
if (largest_digit < digit)
|
||||
largest_digit = digit;
|
||||
nd = n * base + digit;
|
||||
overflow |= ULONG_MAX_over_base < n | nd < n;
|
||||
n = nd;
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
cpp_error (pfile, "Invalid number in #if expression");
|
||||
op.op = ERROR;
|
||||
return op;
|
||||
}
|
||||
|
||||
if (base <= largest_digit)
|
||||
cpp_warning (pfile, "integer constant contains digits beyond the radix");
|
||||
|
||||
if (overflow)
|
||||
cpp_warning (pfile, "integer constant out of range");
|
||||
|
||||
/* If too big to be signed, consider it unsigned. */
|
||||
if ((long) n < 0 && ! op.unsignedp)
|
||||
{
|
||||
if (base == 10)
|
||||
cpp_warning (pfile, "integer constant is so large that it is unsigned");
|
||||
op.unsignedp = 1;
|
||||
}
|
||||
|
||||
op.value = n;
|
||||
op.op = INT;
|
||||
return op;
|
||||
}
|
||||
|
||||
struct token {
|
||||
char *operator;
|
||||
int token;
|
||||
};
|
||||
|
||||
static struct token tokentab2[] = {
|
||||
{"&&", ANDAND},
|
||||
{"||", OROR},
|
||||
{"<<", LSH},
|
||||
{">>", RSH},
|
||||
{"==", EQUAL},
|
||||
{"!=", NOTEQUAL},
|
||||
{"<=", LEQ},
|
||||
{">=", GEQ},
|
||||
{"++", ERROR},
|
||||
{"--", ERROR},
|
||||
{NULL, ERROR}
|
||||
};
|
||||
|
||||
/* Read one token. */
|
||||
|
||||
struct operation
|
||||
cpp_lex (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
register int c;
|
||||
register int namelen;
|
||||
register struct token *toktab;
|
||||
enum cpp_token token;
|
||||
struct operation op;
|
||||
U_CHAR *tok_start, *tok_end;
|
||||
int old_written;
|
||||
|
||||
retry:
|
||||
|
||||
c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
|
||||
if (c == '#')
|
||||
return parse_number (pfile,
|
||||
cpp_read_check_assertion (pfile) ? "1" : "0", 1);
|
||||
|
||||
old_written = CPP_WRITTEN (pfile);
|
||||
cpp_skip_hspace (pfile);
|
||||
if (c == '\n')
|
||||
{
|
||||
op.op = 0;
|
||||
return op;
|
||||
}
|
||||
|
||||
token = cpp_get_token (pfile);
|
||||
tok_start = pfile->token_buffer + old_written;
|
||||
tok_end = CPP_PWRITTEN (pfile);
|
||||
pfile->limit = tok_start;
|
||||
switch (token)
|
||||
{
|
||||
case CPP_EOF: /* Should not happen ... */
|
||||
op.op = 0;
|
||||
return op;
|
||||
case CPP_VSPACE:
|
||||
case CPP_POP:
|
||||
if (CPP_BUFFER (pfile)->fname != NULL)
|
||||
{
|
||||
op.op = 0;
|
||||
return op;
|
||||
}
|
||||
goto retry;
|
||||
case CPP_HSPACE: case CPP_COMMENT:
|
||||
goto retry;
|
||||
case CPP_NUMBER:
|
||||
return parse_number (pfile, tok_start, tok_end - tok_start);
|
||||
case CPP_STRING:
|
||||
cpp_error (pfile, "string constants not allowed in #if expressions");
|
||||
op.op = ERROR;
|
||||
return op;
|
||||
case CPP_CHAR:
|
||||
/* This code for reading a character constant
|
||||
handles multicharacter constants and wide characters.
|
||||
It is mostly copied from c-lex.c. */
|
||||
{
|
||||
register int result = 0;
|
||||
register num_chars = 0;
|
||||
unsigned width = MAX_CHAR_TYPE_SIZE;
|
||||
int wide_flag = 0;
|
||||
int max_chars;
|
||||
U_CHAR *ptr = tok_start;
|
||||
#ifdef MULTIBYTE_CHARS
|
||||
char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + MB_CUR_MAX];
|
||||
#else
|
||||
char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + 1];
|
||||
#endif
|
||||
|
||||
if (*ptr == 'L')
|
||||
{
|
||||
ptr++;
|
||||
wide_flag = 1;
|
||||
width = MAX_WCHAR_TYPE_SIZE;
|
||||
#ifdef MULTIBYTE_CHARS
|
||||
max_chars = MB_CUR_MAX;
|
||||
#else
|
||||
max_chars = 1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
max_chars = MAX_LONG_TYPE_SIZE / width;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (ptr >= CPP_PWRITTEN (pfile) || (c = *ptr++) == '\'')
|
||||
break;
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
c = cpp_parse_escape (pfile, &ptr);
|
||||
if (width < HOST_BITS_PER_INT
|
||||
&& (unsigned) c >= (1 << width))
|
||||
cpp_pedwarn (pfile,
|
||||
"escape sequence out of range for character");
|
||||
}
|
||||
|
||||
num_chars++;
|
||||
|
||||
/* Merge character into result; ignore excess chars. */
|
||||
if (num_chars < max_chars + 1)
|
||||
{
|
||||
if (width < HOST_BITS_PER_INT)
|
||||
result = (result << width) | (c & ((1 << width) - 1));
|
||||
else
|
||||
result = c;
|
||||
token_buffer[num_chars - 1] = c;
|
||||
}
|
||||
}
|
||||
|
||||
token_buffer[num_chars] = 0;
|
||||
|
||||
if (c != '\'')
|
||||
cpp_error (pfile, "malformatted character constant");
|
||||
else if (num_chars == 0)
|
||||
cpp_error (pfile, "empty character constant");
|
||||
else if (num_chars > max_chars)
|
||||
{
|
||||
num_chars = max_chars;
|
||||
cpp_error (pfile, "character constant too long");
|
||||
}
|
||||
else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
|
||||
cpp_warning (pfile, "multi-character character constant");
|
||||
|
||||
/* If char type is signed, sign-extend the constant. */
|
||||
if (! wide_flag)
|
||||
{
|
||||
int num_bits = num_chars * width;
|
||||
|
||||
if (cpp_lookup (pfile, "__CHAR_UNSIGNED__",
|
||||
sizeof ("__CHAR_UNSIGNED__")-1, -1)
|
||||
|| ((result >> (num_bits - 1)) & 1) == 0)
|
||||
op.value
|
||||
= result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
|
||||
else
|
||||
op.value
|
||||
= result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MULTIBYTE_CHARS
|
||||
/* Set the initial shift state and convert the next sequence. */
|
||||
result = 0;
|
||||
/* In all locales L'\0' is zero and mbtowc will return zero,
|
||||
so don't use it. */
|
||||
if (num_chars > 1
|
||||
|| (num_chars == 1 && token_buffer[0] != '\0'))
|
||||
{
|
||||
wchar_t wc;
|
||||
(void) mbtowc (NULL_PTR, NULL_PTR, 0);
|
||||
if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
|
||||
result = wc;
|
||||
else
|
||||
cpp_warning (pfile,"Ignoring invalid multibyte character");
|
||||
}
|
||||
#endif
|
||||
op.value = result;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is always a signed type. */
|
||||
op.unsignedp = 0;
|
||||
op.op = CHAR;
|
||||
|
||||
return op;
|
||||
|
||||
case CPP_NAME:
|
||||
return parse_number (pfile, "0", 0);
|
||||
|
||||
case CPP_OTHER:
|
||||
/* See if it is a special token of length 2. */
|
||||
if (tok_start + 2 == tok_end)
|
||||
{
|
||||
for (toktab = tokentab2; toktab->operator != NULL; toktab++)
|
||||
if (tok_start[0] == toktab->operator[0]
|
||||
&& tok_start[1] == toktab->operator[1])
|
||||
break;
|
||||
if (toktab->token == ERROR)
|
||||
{
|
||||
char *buf = (char *) alloca (40);
|
||||
sprintf (buf, "`%s' not allowed in operand of `#if'", tok_start);
|
||||
cpp_error (pfile, buf);
|
||||
}
|
||||
op.op = toktab->token;
|
||||
return op;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
op.op = *tok_start;
|
||||
return op;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse a C escape sequence. STRING_PTR points to a variable
|
||||
containing a pointer to the string to parse. That pointer
|
||||
is updated past the characters we use. The value of the
|
||||
escape sequence is returned.
|
||||
|
||||
A negative value means the sequence \ newline was seen,
|
||||
which is supposed to be equivalent to nothing at all.
|
||||
|
||||
If \ is followed by a null character, we return a negative
|
||||
value and leave the string pointer pointing at the null character.
|
||||
|
||||
If \ is followed by 000, we return 0 and leave the string pointer
|
||||
after the zeros. A value of 0 does not mean end of string. */
|
||||
|
||||
int
|
||||
cpp_parse_escape (pfile, string_ptr)
|
||||
cpp_reader *pfile;
|
||||
char **string_ptr;
|
||||
{
|
||||
register int c = *(*string_ptr)++;
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
return TARGET_BELL;
|
||||
case 'b':
|
||||
return TARGET_BS;
|
||||
case 'e':
|
||||
case 'E':
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, `\\%c'", c);
|
||||
return 033;
|
||||
case 'f':
|
||||
return TARGET_FF;
|
||||
case 'n':
|
||||
return TARGET_NEWLINE;
|
||||
case 'r':
|
||||
return TARGET_CR;
|
||||
case 't':
|
||||
return TARGET_TAB;
|
||||
case 'v':
|
||||
return TARGET_VT;
|
||||
case '\n':
|
||||
return -2;
|
||||
case 0:
|
||||
(*string_ptr)--;
|
||||
return 0;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
register int i = c - '0';
|
||||
register int count = 0;
|
||||
while (++count < 3)
|
||||
{
|
||||
c = *(*string_ptr)++;
|
||||
if (c >= '0' && c <= '7')
|
||||
i = (i << 3) + c - '0';
|
||||
else
|
||||
{
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
|
||||
{
|
||||
i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
|
||||
cpp_warning (pfile,
|
||||
"octal character constant does not fit in a byte");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case 'x':
|
||||
{
|
||||
register unsigned i = 0, overflow = 0, digits_found = 0, digit;
|
||||
for (;;)
|
||||
{
|
||||
c = *(*string_ptr)++;
|
||||
if (c >= '0' && c <= '9')
|
||||
digit = c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
digit = c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
digit = c - 'A' + 10;
|
||||
else
|
||||
{
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
overflow |= i ^ (i << 4 >> 4);
|
||||
i = (i << 4) + digit;
|
||||
digits_found = 1;
|
||||
}
|
||||
if (!digits_found)
|
||||
cpp_error (pfile, "\\x used with no following hex digits");
|
||||
if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
|
||||
{
|
||||
i &= (1 << BITS_PER_UNIT) - 1;
|
||||
cpp_warning (pfile,
|
||||
"hex character constant does not fit in a byte");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
integer_overflow (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
|
||||
}
|
||||
|
||||
static long
|
||||
left_shift (pfile, a, unsignedp, b)
|
||||
cpp_reader *pfile;
|
||||
long a;
|
||||
int unsignedp;
|
||||
unsigned long b;
|
||||
{
|
||||
if (b >= HOST_BITS_PER_LONG)
|
||||
{
|
||||
if (! unsignedp && a != 0)
|
||||
integer_overflow (pfile);
|
||||
return 0;
|
||||
}
|
||||
else if (unsignedp)
|
||||
return (unsigned long) a << b;
|
||||
else
|
||||
{
|
||||
long l = a << b;
|
||||
if (l >> b != a)
|
||||
integer_overflow (pfile);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
right_shift (pfile, a, unsignedp, b)
|
||||
cpp_reader *pfile;
|
||||
long a;
|
||||
int unsignedp;
|
||||
unsigned long b;
|
||||
{
|
||||
if (b >= HOST_BITS_PER_LONG)
|
||||
return unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1);
|
||||
else if (unsignedp)
|
||||
return (unsigned long) a >> b;
|
||||
else
|
||||
return a >> b;
|
||||
}
|
||||
|
||||
/* These priorities are all even, so we can handle associatively. */
|
||||
#define PAREN_INNER_PRIO 0
|
||||
#define COMMA_PRIO 4
|
||||
#define COND_PRIO (COMMA_PRIO+2)
|
||||
#define OROR_PRIO (COND_PRIO+2)
|
||||
#define ANDAND_PRIO (OROR_PRIO+2)
|
||||
#define OR_PRIO (ANDAND_PRIO+2)
|
||||
#define XOR_PRIO (OR_PRIO+2)
|
||||
#define AND_PRIO (XOR_PRIO+2)
|
||||
#define EQUAL_PRIO (AND_PRIO+2)
|
||||
#define LESS_PRIO (EQUAL_PRIO+2)
|
||||
#define SHIFT_PRIO (LESS_PRIO+2)
|
||||
#define PLUS_PRIO (SHIFT_PRIO+2)
|
||||
#define MUL_PRIO (PLUS_PRIO+2)
|
||||
#define UNARY_PRIO (MUL_PRIO+2)
|
||||
#define PAREN_OUTER_PRIO (UNARY_PRIO+2)
|
||||
|
||||
#define COMPARE(OP) \
|
||||
top->unsignedp = 0;\
|
||||
top->value = (unsigned1 || unsigned2) ? (unsigned long) v1 OP v2 : (v1 OP v2)
|
||||
|
||||
/* Parse and evaluate a C expression, reading from PFILE.
|
||||
Returns the value of the expression. */
|
||||
|
||||
long
|
||||
cpp_parse_expr (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
/* The implementation is an operator precedence parser,
|
||||
i.e. a bottom-up parser, using a stack for not-yet-reduced tokens.
|
||||
|
||||
The stack base is 'stack', and the current stack pointer is 'top'.
|
||||
There is a stack element for each operator (only),
|
||||
and the most recently pushed operator is 'top->op'.
|
||||
An operand (value) is stored in the 'value' field of the stack
|
||||
element of the operator that precedes it.
|
||||
In that case the 'flags' field has the HAVE_VALUE flag set. */
|
||||
|
||||
#define INIT_STACK_SIZE 20
|
||||
struct operation init_stack[INIT_STACK_SIZE];
|
||||
struct operation *stack = init_stack;
|
||||
struct operation *limit = stack + INIT_STACK_SIZE;
|
||||
register struct operation *top = stack;
|
||||
int lprio, rprio;
|
||||
|
||||
top->rprio = 0;
|
||||
top->flags = 0;
|
||||
for (;;)
|
||||
{
|
||||
struct operation op;
|
||||
char flags = 0;
|
||||
|
||||
/* Read a token */
|
||||
op = cpp_lex (pfile);
|
||||
|
||||
/* See if the token is an operand, in which case go to set_value.
|
||||
If the token is an operator, figure out its left and right
|
||||
priorities, and then goto maybe_reduce. */
|
||||
|
||||
switch (op.op)
|
||||
{
|
||||
case NAME:
|
||||
top->value = 0, top->unsignedp = 0;
|
||||
goto set_value;
|
||||
case INT: case CHAR:
|
||||
top->value = op.value;
|
||||
top->unsignedp = op.unsignedp;
|
||||
goto set_value;
|
||||
case 0:
|
||||
lprio = 0; goto maybe_reduce;
|
||||
case '+': case '-':
|
||||
/* Is this correct if unary ? FIXME */
|
||||
flags = RIGHT_OPERAND_REQUIRED;
|
||||
lprio = PLUS_PRIO; rprio = lprio + 1; goto maybe_reduce;
|
||||
case '!': case '~':
|
||||
flags = RIGHT_OPERAND_REQUIRED;
|
||||
rprio = UNARY_PRIO; lprio = rprio + 1; goto maybe_reduce;
|
||||
case '*': case '/': case '%':
|
||||
lprio = MUL_PRIO; goto binop;
|
||||
case '<': case '>': case LEQ: case GEQ:
|
||||
lprio = LESS_PRIO; goto binop;
|
||||
case EQUAL: case NOTEQUAL:
|
||||
lprio = EQUAL_PRIO; goto binop;
|
||||
case LSH: case RSH:
|
||||
lprio = SHIFT_PRIO; goto binop;
|
||||
case '&': lprio = AND_PRIO; goto binop;
|
||||
case '^': lprio = XOR_PRIO; goto binop;
|
||||
case '|': lprio = OR_PRIO; goto binop;
|
||||
case ANDAND: lprio = ANDAND_PRIO; goto binop;
|
||||
case OROR: lprio = OROR_PRIO; goto binop;
|
||||
case ',':
|
||||
lprio = COMMA_PRIO; goto binop;
|
||||
case '(':
|
||||
lprio = PAREN_OUTER_PRIO; rprio = PAREN_INNER_PRIO;
|
||||
goto maybe_reduce;
|
||||
case ')':
|
||||
lprio = PAREN_INNER_PRIO; rprio = PAREN_OUTER_PRIO;
|
||||
goto maybe_reduce;
|
||||
case ':':
|
||||
lprio = COND_PRIO; rprio = COND_PRIO;
|
||||
goto maybe_reduce;
|
||||
case '?':
|
||||
lprio = COND_PRIO + 1; rprio = COND_PRIO;
|
||||
goto maybe_reduce;
|
||||
binop:
|
||||
flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED;
|
||||
rprio = lprio + 1;
|
||||
goto maybe_reduce;
|
||||
default:
|
||||
cpp_error (pfile, "invalid character in #if");
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
set_value:
|
||||
/* Push a value onto the stack. */
|
||||
if (top->flags & HAVE_VALUE)
|
||||
{
|
||||
cpp_error (pfile, "syntax error in #if");
|
||||
goto syntax_error;
|
||||
}
|
||||
top->flags |= HAVE_VALUE;
|
||||
continue;
|
||||
|
||||
maybe_reduce:
|
||||
/* Push an operator, and check if we can reduce now. */
|
||||
while (top->rprio > lprio)
|
||||
{
|
||||
long v1 = top[-1].value, v2 = top[0].value;
|
||||
int unsigned1 = top[-1].unsignedp, unsigned2 = top[0].unsignedp;
|
||||
top--;
|
||||
if ((top[1].flags & LEFT_OPERAND_REQUIRED)
|
||||
&& ! (top[0].flags & HAVE_VALUE))
|
||||
{
|
||||
cpp_error (pfile, "syntax error - missing left operand");
|
||||
goto syntax_error;
|
||||
}
|
||||
if ((top[1].flags & RIGHT_OPERAND_REQUIRED)
|
||||
&& ! (top[1].flags & HAVE_VALUE))
|
||||
{
|
||||
cpp_error (pfile, "syntax error - missing right operand");
|
||||
goto syntax_error;
|
||||
}
|
||||
/* top[0].value = (top[1].op)(v1, v2);*/
|
||||
switch (top[1].op)
|
||||
{
|
||||
case '+':
|
||||
if (!(top->flags & HAVE_VALUE))
|
||||
{ /* Unary '+' */
|
||||
top->value = v2;
|
||||
top->unsignedp = unsigned2;
|
||||
top->flags |= HAVE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
top->value = v1 + v2;
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
if (! top->unsignedp
|
||||
&& ! possible_sum_sign (v1, v2, top->value))
|
||||
integer_overflow (pfile);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (!(top->flags & HAVE_VALUE))
|
||||
{ /* Unary '-' */
|
||||
top->value = - v2;
|
||||
if ((top->value & v2) < 0 && ! unsigned2)
|
||||
integer_overflow (pfile);
|
||||
top->unsignedp = unsigned2;
|
||||
top->flags |= HAVE_VALUE;
|
||||
}
|
||||
else
|
||||
{ /* Binary '-' */
|
||||
top->value = v1 - v2;
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
if (! top->unsignedp
|
||||
&& ! possible_sum_sign (top->value, v2, v1))
|
||||
integer_overflow (pfile);
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
if (top->unsignedp)
|
||||
top->value = (unsigned long) v1 * v2;
|
||||
else
|
||||
{
|
||||
top->value = v1 * v2;
|
||||
if (v1
|
||||
&& (top->value / v1 != v2
|
||||
|| (top->value & v1 & v2) < 0))
|
||||
integer_overflow (pfile);
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
if (v2 == 0)
|
||||
{
|
||||
cpp_error (pfile, "division by zero in #if");
|
||||
v2 = 1;
|
||||
}
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
if (top->unsignedp)
|
||||
top->value = (unsigned long) v1 / v2;
|
||||
else
|
||||
{
|
||||
top->value = v1 / v2;
|
||||
if ((top->value & v1 & v2) < 0)
|
||||
integer_overflow (pfile);
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
if (v2 == 0)
|
||||
{
|
||||
cpp_error (pfile, "division by zero in #if");
|
||||
v2 = 1;
|
||||
}
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
if (top->unsignedp)
|
||||
top->value = (unsigned long) v1 % v2;
|
||||
else
|
||||
top->value = v1 % v2;
|
||||
break;
|
||||
case '!':
|
||||
if (top->flags & HAVE_VALUE)
|
||||
{
|
||||
cpp_error (pfile, "syntax error");
|
||||
goto syntax_error;
|
||||
}
|
||||
top->value = ! v2;
|
||||
top->unsignedp = 0;
|
||||
top->flags |= HAVE_VALUE;
|
||||
break;
|
||||
case '~':
|
||||
if (top->flags & HAVE_VALUE)
|
||||
{
|
||||
cpp_error (pfile, "syntax error");
|
||||
goto syntax_error;
|
||||
}
|
||||
top->value = ~ v2;
|
||||
top->unsignedp = unsigned2;
|
||||
top->flags |= HAVE_VALUE;
|
||||
break;
|
||||
case '<': COMPARE(<); break;
|
||||
case '>': COMPARE(>); break;
|
||||
case LEQ: COMPARE(<=); break;
|
||||
case GEQ: COMPARE(>=); break;
|
||||
case EQUAL:
|
||||
top->value = (v1 == v2);
|
||||
top->unsignedp = 0;
|
||||
break;
|
||||
case NOTEQUAL:
|
||||
top->value = (v1 != v2);
|
||||
top->unsignedp = 0;
|
||||
break;
|
||||
case LSH:
|
||||
top->unsignedp = unsigned1;
|
||||
if (v2 < 0 && ! unsigned2)
|
||||
top->value = right_shift (pfile, v1, unsigned1, -v2);
|
||||
else
|
||||
top->value = left_shift (pfile, v1, unsigned1, v2);
|
||||
break;
|
||||
case RSH:
|
||||
top->unsignedp = unsigned1;
|
||||
if (v2 < 0 && ! unsigned2)
|
||||
top->value = left_shift (pfile, v1, unsigned1, -v2);
|
||||
else
|
||||
top->value = right_shift (pfile, v1, unsigned1, v2);
|
||||
break;
|
||||
#define LOGICAL(OP) \
|
||||
top->value = v1 OP v2;\
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
case '&': LOGICAL(&); break;
|
||||
case '^': LOGICAL(^); break;
|
||||
case '|': LOGICAL(|); break;
|
||||
case ANDAND:
|
||||
top->value = v1 && v2; top->unsignedp = 0; break;
|
||||
case OROR:
|
||||
top->value = v1 || v2; top->unsignedp = 0; break;
|
||||
case ',':
|
||||
if (CPP_PEDANTIC (pfile))
|
||||
cpp_pedwarn (pfile, "comma operator in operand of `#if'");
|
||||
top->value = v2;
|
||||
top->unsignedp = unsigned2;
|
||||
break;
|
||||
case '(': case '?':
|
||||
cpp_error (pfile, "syntax error in #if");
|
||||
goto syntax_error;
|
||||
case ':':
|
||||
if (top[0].op != '?')
|
||||
{
|
||||
cpp_error (pfile,
|
||||
"syntax error ':' without preceding '?'");
|
||||
goto syntax_error;
|
||||
}
|
||||
else if (! (top[1].flags & HAVE_VALUE)
|
||||
|| !(top[-1].flags & HAVE_VALUE)
|
||||
|| !(top[0].flags & HAVE_VALUE))
|
||||
{
|
||||
cpp_error (pfile, "bad syntax for ?: operator");
|
||||
goto syntax_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
top--;
|
||||
top->value = top->value ? v1 : v2;
|
||||
top->unsignedp = unsigned1 || unsigned2;
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
if ((top[1].flags & HAVE_VALUE)
|
||||
|| ! (top[0].flags & HAVE_VALUE)
|
||||
|| top[0].op != '('
|
||||
|| (top[-1].flags & HAVE_VALUE))
|
||||
{
|
||||
cpp_error (pfile, "mismatched parentheses in #if");
|
||||
goto syntax_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
top--;
|
||||
top->value = v1;
|
||||
top->unsignedp = unsigned1;
|
||||
top->flags |= HAVE_VALUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr,
|
||||
top[1].op >= ' ' && top[1].op <= '~'
|
||||
? "unimplemented operator '%c'\n"
|
||||
: "unimplemented operator '\\%03o'\n",
|
||||
top[1].op);
|
||||
}
|
||||
}
|
||||
if (op.op == 0)
|
||||
{
|
||||
if (top != stack)
|
||||
cpp_error (pfile, "internal error in #if expression");
|
||||
if (stack != init_stack)
|
||||
free (stack);
|
||||
return top->value;
|
||||
}
|
||||
top++;
|
||||
|
||||
/* Check for and handle stack overflow. */
|
||||
if (top == limit)
|
||||
{
|
||||
struct operation *new_stack;
|
||||
int old_size = (char*)limit - (char*)stack;
|
||||
int new_size = 2 * old_size;
|
||||
if (stack != init_stack)
|
||||
new_stack = (struct operation*) xrealloc (stack, new_size);
|
||||
else
|
||||
{
|
||||
new_stack = (struct operation*) xmalloc (new_size);
|
||||
bcopy (stack, new_stack, old_size);
|
||||
}
|
||||
stack = new_stack;
|
||||
top = (struct operation*)((char*) new_stack + old_size);
|
||||
limit = (struct operation*)((char*) new_stack + new_size);
|
||||
}
|
||||
|
||||
top->flags = flags;
|
||||
top->rprio = rprio;
|
||||
top->op = op.op;
|
||||
}
|
||||
syntax_error:
|
||||
if (stack != init_stack)
|
||||
free (stack);
|
||||
skip_rest_of_line (pfile);
|
||||
return 0;
|
||||
}
|
192
gcc/cpphash.c
Normal file
192
gcc/cpphash.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* Part of CPP library. (Macro hash table support.)
|
||||
Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994.
|
||||
Based on CCCP program by by Paul Rubin, June 1986
|
||||
Adapted to ANSI C, Richard Stallman, Jan 1987
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#include "cpplib.h"
|
||||
#include "cpphash.h"
|
||||
|
||||
/* Define a generic NULL if one hasn't already been defined. */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* return hash function on name. must be compatible with the one
|
||||
* computed a step at a time, elsewhere
|
||||
*/
|
||||
int
|
||||
hashf (name, len, hashsize)
|
||||
register const U_CHAR *name;
|
||||
register int len;
|
||||
int hashsize;
|
||||
{
|
||||
register int r = 0;
|
||||
|
||||
while (len--)
|
||||
r = HASHSTEP (r, *name++);
|
||||
|
||||
return MAKE_POS (r) % hashsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the most recent hash node for name name (ending with first
|
||||
* non-identifier char) installed by install
|
||||
*
|
||||
* If LEN is >= 0, it is the length of the name.
|
||||
* Otherwise, compute the length by scanning the entire name.
|
||||
*
|
||||
* If HASH is >= 0, it is the precomputed hash code.
|
||||
* Otherwise, compute the hash code.
|
||||
*/
|
||||
HASHNODE *
|
||||
cpp_lookup (pfile, name, len, hash)
|
||||
struct parse_file *pfile;
|
||||
const U_CHAR *name;
|
||||
int len;
|
||||
int hash;
|
||||
{
|
||||
register const U_CHAR *bp;
|
||||
register HASHNODE *bucket;
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
for (bp = name; is_idchar[*bp]; bp++) ;
|
||||
len = bp - name;
|
||||
}
|
||||
|
||||
if (hash < 0)
|
||||
hash = hashf (name, len, HASHSIZE);
|
||||
|
||||
bucket = hashtab[hash];
|
||||
while (bucket) {
|
||||
if (bucket->length == len && strncmp (bucket->name, name, len) == 0)
|
||||
return bucket;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
return (HASHNODE*) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a hash node. Some weirdness to free junk from macros.
|
||||
* More such weirdness will have to be added if you define more hash
|
||||
* types that need it.
|
||||
*/
|
||||
|
||||
/* Note that the DEFINITION of a macro is removed from the hash table
|
||||
but its storage is not freed. This would be a storage leak
|
||||
except that it is not reasonable to keep undefining and redefining
|
||||
large numbers of macros many times.
|
||||
In any case, this is necessary, because a macro can be #undef'd
|
||||
in the middle of reading the arguments to a call to it.
|
||||
If #undef freed the DEFINITION, that would crash. */
|
||||
|
||||
void
|
||||
delete_macro (hp)
|
||||
HASHNODE *hp;
|
||||
{
|
||||
|
||||
if (hp->prev != NULL)
|
||||
hp->prev->next = hp->next;
|
||||
if (hp->next != NULL)
|
||||
hp->next->prev = hp->prev;
|
||||
|
||||
/* make sure that the bucket chain header that
|
||||
the deleted guy was on points to the right thing afterwards. */
|
||||
if (hp == *hp->bucket_hdr)
|
||||
*hp->bucket_hdr = hp->next;
|
||||
|
||||
#if 0
|
||||
if (hp->type == T_MACRO) {
|
||||
DEFINITION *d = hp->value.defn;
|
||||
struct reflist *ap, *nextap;
|
||||
|
||||
for (ap = d->pattern; ap != NULL; ap = nextap) {
|
||||
nextap = ap->next;
|
||||
free (ap);
|
||||
}
|
||||
free (d);
|
||||
}
|
||||
#endif
|
||||
free (hp);
|
||||
}
|
||||
/*
|
||||
* install a name in the main hash table, even if it is already there.
|
||||
* name stops with first non alphanumeric, except leading '#'.
|
||||
* caller must check against redefinition if that is desired.
|
||||
* delete_macro () removes things installed by install () in fifo order.
|
||||
* this is important because of the `defined' special symbol used
|
||||
* in #if, and also if pushdef/popdef directives are ever implemented.
|
||||
*
|
||||
* If LEN is >= 0, it is the length of the name.
|
||||
* Otherwise, compute the length by scanning the entire name.
|
||||
*
|
||||
* If HASH is >= 0, it is the precomputed hash code.
|
||||
* Otherwise, compute the hash code.
|
||||
*/
|
||||
HASHNODE *
|
||||
install (name, len, type, ivalue, value, hash)
|
||||
U_CHAR *name;
|
||||
int len;
|
||||
enum node_type type;
|
||||
int ivalue;
|
||||
char *value;
|
||||
int hash;
|
||||
{
|
||||
register HASHNODE *hp;
|
||||
register int i, bucket;
|
||||
register U_CHAR *p, *q;
|
||||
|
||||
if (len < 0) {
|
||||
p = name;
|
||||
while (is_idchar[*p])
|
||||
p++;
|
||||
len = p - name;
|
||||
}
|
||||
|
||||
if (hash < 0)
|
||||
hash = hashf (name, len, HASHSIZE);
|
||||
|
||||
i = sizeof (HASHNODE) + len + 1;
|
||||
hp = (HASHNODE *) xmalloc (i);
|
||||
bucket = hash;
|
||||
hp->bucket_hdr = &hashtab[bucket];
|
||||
hp->next = hashtab[bucket];
|
||||
hashtab[bucket] = hp;
|
||||
hp->prev = NULL;
|
||||
if (hp->next != NULL)
|
||||
hp->next->prev = hp;
|
||||
hp->type = type;
|
||||
hp->length = len;
|
||||
if (hp->type == T_CONST)
|
||||
hp->value.ival = ivalue;
|
||||
else
|
||||
hp->value.cpval = value;
|
||||
hp->name = ((U_CHAR *) hp) + sizeof (HASHNODE);
|
||||
p = hp->name;
|
||||
q = name;
|
||||
for (i = 0; i < len; i++)
|
||||
*p++ = *q++;
|
||||
hp->name[len] = 0;
|
||||
return hp;
|
||||
}
|
40
gcc/cpphash.h
Normal file
40
gcc/cpphash.h
Normal file
@ -0,0 +1,40 @@
|
||||
enum node_type;
|
||||
|
||||
/* different kinds of things that can appear in the value field
|
||||
of a hash node. Actually, this may be useless now. */
|
||||
union hashval {
|
||||
int ival;
|
||||
char *cpval;
|
||||
DEFINITION *defn;
|
||||
#if 0
|
||||
KEYDEF *keydef;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct hashnode {
|
||||
struct hashnode *next; /* double links for easy deletion */
|
||||
struct hashnode *prev;
|
||||
struct hashnode **bucket_hdr; /* also, a back pointer to this node's hash
|
||||
chain is kept, in case the node is the head
|
||||
of the chain and gets deleted. */
|
||||
enum node_type type; /* type of special token */
|
||||
int length; /* length of token, for quick comparison */
|
||||
U_CHAR *name; /* the actual name */
|
||||
union hashval value; /* pointer to expansion, or whatever */
|
||||
};
|
||||
|
||||
typedef struct hashnode HASHNODE;
|
||||
|
||||
/* Some definitions for the hash table. The hash function MUST be
|
||||
computed as shown in hashf () below. That is because the rescan
|
||||
loop computes the hash value `on the fly' for most tokens,
|
||||
in order to avoid the overhead of a lot of procedure calls to
|
||||
the hashf () function. Hashf () only exists for the sake of
|
||||
politeness, for use when speed isn't so important. */
|
||||
|
||||
#define HASHSIZE 1403
|
||||
static HASHNODE *hashtab[HASHSIZE];
|
||||
#define HASHSTEP(old, c) ((old << 2) + c)
|
||||
#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
|
||||
|
||||
extern HASHNODE* install PARAMS ((U_CHAR*,int,enum node_type, int,char*,int));
|
7288
gcc/cpplib.c
Normal file
7288
gcc/cpplib.c
Normal file
File diff suppressed because it is too large
Load Diff
657
gcc/cpplib.h
Normal file
657
gcc/cpplib.h
Normal file
@ -0,0 +1,657 @@
|
||||
/* Definitions for CPP library.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994-95.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STATIC_BUFFERS
|
||||
|
||||
typedef unsigned char U_CHAR;
|
||||
|
||||
#ifndef FAILURE_EXIT_CODE
|
||||
#define FAILURE_EXIT_CODE 33 /* gnu cc command understands this */
|
||||
#endif
|
||||
|
||||
#ifndef SUCCESS_EXIT_CODE
|
||||
#define SUCCESS_EXIT_CODE 0 /* 0 means success on Unix. */
|
||||
#endif
|
||||
|
||||
struct parse_file;
|
||||
typedef struct cpp_reader cpp_reader;
|
||||
typedef struct cpp_buffer cpp_buffer;
|
||||
typedef struct cpp_options cpp_options;
|
||||
typedef struct hashnode cpp_hashnode;
|
||||
|
||||
enum cpp_token {
|
||||
CPP_EOF = -1,
|
||||
CPP_OTHER = 0,
|
||||
CPP_COMMENT = 1,
|
||||
CPP_HSPACE,
|
||||
CPP_VSPACE, /* newlines and #line directives */
|
||||
CPP_NAME,
|
||||
CPP_NUMBER,
|
||||
CPP_CHAR,
|
||||
CPP_STRING,
|
||||
CPP_DIRECTIVE,
|
||||
CPP_LPAREN, /* "(" */
|
||||
CPP_RPAREN, /* ")" */
|
||||
CPP_LBRACE, /* "{" */
|
||||
CPP_RBRACE, /* "}" */
|
||||
CPP_COMMA, /* "," */
|
||||
CPP_SEMICOLON,/* ";" */
|
||||
CPP_3DOTS, /* "..." */
|
||||
#if 0
|
||||
CPP_ANDAND, /* "&&" */
|
||||
CPP_OROR, /* "||" */
|
||||
CPP_LSH, /* "<<" */
|
||||
CPP_RSH, /* ">>" */
|
||||
CPP_EQL, /* "==" */
|
||||
CPP_NEQ, /* "!=" */
|
||||
CPP_LEQ, /* "<=" */
|
||||
CPP_GEQ, /* ">=" */
|
||||
CPP_PLPL, /* "++" */
|
||||
CPP_MINMIN, /* "--" */
|
||||
#endif
|
||||
/* POP_TOKEN is returned when we've popped a cpp_buffer. */
|
||||
CPP_POP
|
||||
};
|
||||
|
||||
#ifndef PARAMS
|
||||
#ifdef __STDC
|
||||
#define PARAMS(P) P
|
||||
#else
|
||||
#define PARAMS(P) ()
|
||||
#endif
|
||||
#endif /* !PARAMS */
|
||||
|
||||
typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader*));
|
||||
typedef int (*parse_cleanup_t) PARAMS((cpp_buffer *, cpp_reader*));
|
||||
|
||||
/* A parse_marker indicates a previous position,
|
||||
which we can backtrack to. */
|
||||
|
||||
struct parse_marker {
|
||||
cpp_buffer *buf;
|
||||
struct parse_marker *next;
|
||||
int position;
|
||||
};
|
||||
|
||||
extern void parse_set_mark PARAMS ((struct parse_marker*, cpp_reader*));
|
||||
extern void parse_clear_mark PARAMS ((struct parse_marker*));
|
||||
extern void parse_goto_mark PARAMS((struct parse_marker*, cpp_reader*));
|
||||
extern void parse_move_mark PARAMS((struct parse_marker*, cpp_reader*));
|
||||
|
||||
extern int cpp_handle_options PARAMS ((cpp_reader*, int, char**));
|
||||
extern enum cpp_token cpp_get_token PARAMS ((struct parse_marker*));
|
||||
extern void cpp_skip_hspace PARAMS((cpp_reader*));
|
||||
extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *));
|
||||
|
||||
|
||||
/* Maintain and search list of included files, for #import. */
|
||||
|
||||
#define IMPORT_HASH_SIZE 31
|
||||
|
||||
struct import_file {
|
||||
char *name;
|
||||
ino_t inode;
|
||||
dev_t dev;
|
||||
struct import_file *next;
|
||||
};
|
||||
|
||||
/* If we have a huge buffer, may need to cache more recent counts */
|
||||
#define CPP_LINE_BASE(BUF) ((BUF)->buf + (BUF)->line_base)
|
||||
|
||||
struct cpp_buffer {
|
||||
unsigned char *buf;
|
||||
unsigned char *cur;
|
||||
unsigned char *rlimit; /* end of valid data */
|
||||
unsigned char *alimit; /* end of allocated buffer */
|
||||
unsigned char *prev; /* start of current token */
|
||||
|
||||
char *fname;
|
||||
/* Filename specified with #line command. */
|
||||
char *nominal_fname;
|
||||
|
||||
/* Record where in the search path this file was found.
|
||||
For #include_next. */
|
||||
struct file_name_list *dir;
|
||||
|
||||
long line_base;
|
||||
long lineno; /* Line number at CPP_LINE_BASE. */
|
||||
long colno; /* Column number at CPP_LINE_BASE. */
|
||||
#ifndef STATIC_BUFFERS
|
||||
cpp_buffer *chain;
|
||||
#endif
|
||||
parse_underflow_t underflow;
|
||||
parse_cleanup_t cleanup;
|
||||
void *data;
|
||||
struct parse_marker *marks;
|
||||
/* Value of if_stack at start of this file.
|
||||
Used to prohibit unmatched #endif (etc) in an include file. */
|
||||
struct if_stack *if_stack;
|
||||
|
||||
/* True if this is a header file included using <FILENAME>. */
|
||||
char system_header_p;
|
||||
char seen_eof;
|
||||
|
||||
/* True if buffer contains escape sequences.
|
||||
Currently there are are only two kind:
|
||||
"@-" means following identifier should not be macro-expanded.
|
||||
"@@" means a normal '@'. */
|
||||
char has_escapes;
|
||||
};
|
||||
|
||||
struct cpp_pending; /* Forward declaration - for C++. */
|
||||
|
||||
typedef struct assertion_hashnode ASSERTION_HASHNODE;
|
||||
#define ASSERTION_HASHSIZE 37
|
||||
|
||||
#ifdef STATIC_BUFFERS
|
||||
/* Maximum nesting of cpp_buffers. We use a static limit, partly for
|
||||
efficiency, and partly to limit runaway recursion. */
|
||||
#define CPP_STACK_MAX 200
|
||||
#endif
|
||||
|
||||
struct cpp_reader {
|
||||
unsigned char *limit;
|
||||
parse_underflow_t get_token;
|
||||
cpp_buffer *buffer;
|
||||
#ifdef STATIC_BUFFERS
|
||||
cpp_buffer buffer_stack[CPP_STACK_MAX];
|
||||
#endif
|
||||
|
||||
int errors; /* Error counter for exit code */
|
||||
/* While scanning a comment or a string constant,
|
||||
this records the line it started on, for error messages. */
|
||||
int start_line;
|
||||
void *data;
|
||||
|
||||
U_CHAR *token_buffer;
|
||||
int token_buffer_size;
|
||||
|
||||
/* Current depth in #include directives that use <...>. */
|
||||
int system_include_depth;
|
||||
|
||||
/* List of included files that contained #pragma once. */
|
||||
struct file_name_list *dont_repeat_files;
|
||||
|
||||
/* List of other included files.
|
||||
If ->control_macro if nonzero, the file had a #ifndef
|
||||
around the entire contents, and ->control_macro gives the macro name. */
|
||||
struct file_name_list *all_include_files;
|
||||
|
||||
/* Current maximum length of directory names in the search path
|
||||
for include files. (Altered as we get more of them.) */
|
||||
int max_include_len;
|
||||
|
||||
/* Hash table of files already included with #include or #import. */
|
||||
struct import_file *import_hash_table[IMPORT_HASH_SIZE];
|
||||
|
||||
struct if_stack *if_stack;
|
||||
|
||||
/* Nonzero means we are inside an IF during a -pcp run. In this mode
|
||||
macro expansion is done, and preconditions are output for all macro
|
||||
uses requiring them. */
|
||||
char pcp_inside_if;
|
||||
|
||||
/* Nonzero means we have printed (while error reporting) a list of
|
||||
containing files that matches the current status. */
|
||||
char input_stack_listing_current;
|
||||
|
||||
/* If non-zero, macros are not expanded. */
|
||||
char no_macro_expand;
|
||||
|
||||
/* Print column number in error messages. */
|
||||
char show_column;
|
||||
|
||||
/* We're printed a warning recommending against using #import. */
|
||||
char import_warning;
|
||||
|
||||
/* If true, character between '<' and '>' are a single (string) token. */
|
||||
char parsing_include_directive;
|
||||
|
||||
/* True if escape sequences (as described for has_escapes in
|
||||
parse_buffer) should be emitted. */
|
||||
char output_escapes;
|
||||
|
||||
/* 0: Have seen non-white-space on this line.
|
||||
1: Only seen white space so far on this line.
|
||||
2: Only seen white space so far in this file. */
|
||||
char only_seen_white;
|
||||
|
||||
/* Nonzero means this file was included with a -imacros or -include
|
||||
command line and should not be recorded as an include file. */
|
||||
|
||||
int no_record_file;
|
||||
|
||||
long lineno;
|
||||
|
||||
struct tm *timebuf;
|
||||
|
||||
ASSERTION_HASHNODE *assertion_hashtab[ASSERTION_HASHSIZE];
|
||||
|
||||
/* Buffer of -M output. */
|
||||
char *deps_buffer;
|
||||
|
||||
/* Number of bytes allocated in above. */
|
||||
int deps_allocated_size;
|
||||
|
||||
/* Number of bytes used. */
|
||||
int deps_size;
|
||||
|
||||
/* Number of bytes since the last newline. */
|
||||
int deps_column;
|
||||
};
|
||||
|
||||
#define CPP_BUF_PEEK(BUFFER) \
|
||||
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur : EOF)
|
||||
#define CPP_BUF_GET(BUFFER) \
|
||||
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF)
|
||||
#define CPP_FORWARD(BUFFER, N) ((BUFFER)->cur += (N))
|
||||
|
||||
/* Number of characters currently in PFILE's output buffer. */
|
||||
#define CPP_WRITTEN(PFILE) ((PFILE)->limit - (PFILE)->token_buffer)
|
||||
#define CPP_PWRITTEN(PFILE) ((PFILE)->limit)
|
||||
|
||||
/* Make sure PFILE->token_buffer has space for at least N more characters. */
|
||||
#define CPP_RESERVE(PFILE, N) \
|
||||
(CPP_WRITTEN (PFILE) + N > (PFILE)->token_buffer_size \
|
||||
&& (cpp_grow_buffer (PFILE, N), 0))
|
||||
|
||||
/* Append string STR (of length N) to PFILE's output buffer.
|
||||
Assume there is enough space. */
|
||||
#define CPP_PUTS_Q(PFILE, STR, N) \
|
||||
(bcopy (STR, (PFILE)->limit, (N)), (PFILE)->limit += (N))
|
||||
/* Append string STR (of length N) to PFILE's output buffer. Make space. */
|
||||
#define CPP_PUTS(PFILE, STR, N) CPP_RESERVE(PFILE, N), CPP_PUTS_Q(PFILE, STR,N)
|
||||
/* Append character CH to PFILE's output buffer. Assume sufficient space. */
|
||||
#define CPP_PUTC_Q(PFILE, CH) (*(PFILE)->limit++ = (CH))
|
||||
/* Append character CH to PFILE's output buffer. Make space if need be. */
|
||||
#define CPP_PUTC(PFILE, CH) (CPP_RESERVE (PFILE, 1), CPP_PUTC_Q (PFILE, CH))
|
||||
/* Make sure PFILE->limit is followed by '\0'. */
|
||||
#define CPP_NUL_TERMINATE_Q(PFILE) (*(PFILE)->limit = 0)
|
||||
#define CPP_NUL_TERMINATE(PFILE) (CPP_RESERVE(PFILE, 1), *(PFILE)->limit = 0)
|
||||
#define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA))
|
||||
#define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N))
|
||||
|
||||
#define CPP_OPTIONS(PFILE) ((cpp_options*)(PFILE)->data)
|
||||
#define CPP_BUFFER(PFILE) ((PFILE)->buffer)
|
||||
#ifdef STATIC_BUFFERS
|
||||
#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)+1)
|
||||
#define CPP_NULL_BUFFER(PFILE) (&(PFILE)->buffer_stack[CPP_STACK_MAX])
|
||||
#else
|
||||
#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)->chain)
|
||||
#define CPP_NULL_BUFFER(PFILE) ((cpp_buffer*)0)
|
||||
#endif
|
||||
|
||||
/* Pointed to by parse_file::data. */
|
||||
struct cpp_options {
|
||||
char *in_fname;
|
||||
|
||||
/* Name of output file, for error messages. */
|
||||
char *out_fname;
|
||||
|
||||
/* Non-0 means -v, so print the full set of include dirs. */
|
||||
char verbose;
|
||||
|
||||
/* Nonzero means use extra default include directories for C++. */
|
||||
|
||||
char cplusplus;
|
||||
|
||||
/* Nonzero means handle cplusplus style comments */
|
||||
|
||||
char cplusplus_comments;
|
||||
|
||||
/* Nonzero means handle #import, for objective C. */
|
||||
|
||||
char objc;
|
||||
|
||||
/* Nonzero means this is an assembly file, and allow
|
||||
unknown directives, which could be comments. */
|
||||
|
||||
int lang_asm;
|
||||
|
||||
/* Nonzero means turn NOTREACHED into #pragma NOTREACHED etc */
|
||||
|
||||
char for_lint;
|
||||
|
||||
/* Nonzero means handle CHILL comment syntax
|
||||
and output CHILL string delimeter for __DATE___ etc. */
|
||||
|
||||
char chill;
|
||||
|
||||
/* Nonzero means copy comments into the output file. */
|
||||
|
||||
char put_out_comments;
|
||||
|
||||
/* Nonzero means don't process the ANSI trigraph sequences. */
|
||||
|
||||
char no_trigraphs;
|
||||
|
||||
/* Nonzero means print the names of included files rather than
|
||||
the preprocessed output. 1 means just the #include "...",
|
||||
2 means #include <...> as well. */
|
||||
|
||||
char print_deps;
|
||||
|
||||
/* Nonzero if missing .h files in -M output are assumed to be generated
|
||||
files and not errors. */
|
||||
|
||||
char print_deps_missing_files;
|
||||
|
||||
/* If true, fopen (deps_file, "a") else fopen (deps_file, "w"). */
|
||||
char print_deps_append;
|
||||
|
||||
/* Nonzero means print names of header files (-H). */
|
||||
|
||||
char print_include_names;
|
||||
|
||||
/* Nonzero means try to make failure to fit ANSI C an error. */
|
||||
|
||||
char pedantic_errors;
|
||||
|
||||
/* Nonzero means don't print warning messages. -w. */
|
||||
|
||||
char inhibit_warnings;
|
||||
|
||||
/* Nonzero means warn if slash-star appears in a comment. */
|
||||
|
||||
char warn_comments;
|
||||
|
||||
/* Nonzero means warn if there are any trigraphs. */
|
||||
|
||||
char warn_trigraphs;
|
||||
|
||||
/* Nonzero means warn if #import is used. */
|
||||
|
||||
char warn_import;
|
||||
|
||||
/* Nonzero means warn if a macro argument is (or would be)
|
||||
stringified with -traditional. */
|
||||
|
||||
char warn_stringify;
|
||||
|
||||
/* Nonzero means turn warnings into errors. */
|
||||
|
||||
char warnings_are_errors;
|
||||
|
||||
/* Nonzero causes output not to be done,
|
||||
but directives such as #define that have side effects
|
||||
are still obeyed. */
|
||||
|
||||
char no_output;
|
||||
|
||||
/* Nonzero means don't output line number information. */
|
||||
|
||||
char no_line_commands;
|
||||
|
||||
/* Nonzero means output the text in failing conditionals,
|
||||
inside #failed ... #endfailed. */
|
||||
|
||||
char output_conditionals;
|
||||
|
||||
/* Nonzero means -I- has been seen,
|
||||
so don't look for #include "foo" the source-file directory. */
|
||||
char ignore_srcdir;
|
||||
|
||||
/* Zero means dollar signs are punctuation.
|
||||
-$ stores 0; -traditional may store 1. Default is 1 for VMS, 0 otherwise.
|
||||
This must be 0 for correct processing of this ANSI C program:
|
||||
#define foo(a) #a
|
||||
#define lose(b) foo (b)
|
||||
#define test$
|
||||
lose (test) */
|
||||
char dollars_in_ident;
|
||||
#ifndef DOLLARS_IN_IDENTIFIERS
|
||||
#define DOLLARS_IN_IDENTIFIERS 1
|
||||
#endif
|
||||
|
||||
/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */
|
||||
char traditional;
|
||||
|
||||
/* Nonzero means give all the error messages the ANSI standard requires. */
|
||||
char pedantic;
|
||||
|
||||
char done_initializing;
|
||||
|
||||
struct file_name_list *include; /* First dir to search */
|
||||
/* First dir to search for <file> */
|
||||
/* This is the first element to use for #include <...>.
|
||||
If it is 0, use the entire chain for such includes. */
|
||||
struct file_name_list *first_bracket_include;
|
||||
/* This is the first element in the chain that corresponds to
|
||||
a directory of system header files. */
|
||||
struct file_name_list *first_system_include;
|
||||
struct file_name_list *last_include; /* Last in chain */
|
||||
|
||||
/* Chain of include directories to put at the end of the other chain. */
|
||||
struct file_name_list *after_include;
|
||||
struct file_name_list *last_after_include; /* Last in chain */
|
||||
|
||||
/* Chain to put at the start of the system include files. */
|
||||
struct file_name_list *before_system;
|
||||
struct file_name_list *last_before_system; /* Last in chain */
|
||||
|
||||
/* Directory prefix that should replace `/usr' in the standard
|
||||
include file directories. */
|
||||
char *include_prefix;
|
||||
|
||||
char inhibit_predefs;
|
||||
char no_standard_includes;
|
||||
char no_standard_cplusplus_includes;
|
||||
|
||||
/* dump_only means inhibit output of the preprocessed text
|
||||
and instead output the definitions of all user-defined
|
||||
macros in a form suitable for use as input to cccp.
|
||||
dump_names means pass #define and the macro name through to output.
|
||||
dump_definitions means pass the whole definition (plus #define) through
|
||||
*/
|
||||
|
||||
enum {dump_none = 0, dump_only, dump_names, dump_definitions}
|
||||
dump_macros;
|
||||
|
||||
/* Nonzero means pass all #define and #undef directives which we actually
|
||||
process through to the output stream. This feature is used primarily
|
||||
to allow cc1 to record the #defines and #undefs for the sake of
|
||||
debuggers which understand about preprocessor macros, but it may
|
||||
also be useful with -E to figure out how symbols are defined, and
|
||||
where they are defined. */
|
||||
int debug_output;
|
||||
|
||||
/* Pending -D, -U and -A options, in reverse order. */
|
||||
struct cpp_pending *pending;
|
||||
|
||||
/* File name which deps are being written to.
|
||||
This is 0 if deps are being written to stdout. */
|
||||
char *deps_file;
|
||||
|
||||
/* Target-name to write with the dependency information. */
|
||||
char *deps_target;
|
||||
};
|
||||
|
||||
#define CPP_TRADITIONAL(PFILE) (CPP_OPTIONS(PFILE)-> traditional)
|
||||
#define CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic)
|
||||
#define CPP_PRINT_DEPS(PFILE) (CPP_OPTIONS (PFILE)->print_deps)
|
||||
|
||||
#define PARSE_GETC(IN) ((IN)-> cur < (IN)->limit || ((IN)->cur = (IN)->token_buffer, (IN)->underflow (IN) != EOF_TOKEN) ? *(IN)->cur++ : EOF)
|
||||
|
||||
/* Name under which this program was invoked. */
|
||||
|
||||
extern char *progname;
|
||||
|
||||
/* The structure of a node in the hash table. The hash table
|
||||
has entries for all tokens defined by #define commands (type T_MACRO),
|
||||
plus some special tokens like __LINE__ (these each have their own
|
||||
type, and the appropriate code is run when that type of node is seen.
|
||||
It does not contain control words like "#define", which are recognized
|
||||
by a separate piece of code. */
|
||||
|
||||
/* different flavors of hash nodes --- also used in keyword table */
|
||||
enum node_type {
|
||||
T_DEFINE = 1, /* the `#define' keyword */
|
||||
T_INCLUDE, /* the `#include' keyword */
|
||||
T_INCLUDE_NEXT, /* the `#include_next' keyword */
|
||||
T_IMPORT, /* the `#import' keyword */
|
||||
T_IFDEF, /* the `#ifdef' keyword */
|
||||
T_IFNDEF, /* the `#ifndef' keyword */
|
||||
T_IF, /* the `#if' keyword */
|
||||
T_ELSE, /* `#else' */
|
||||
T_PRAGMA, /* `#pragma' */
|
||||
T_ELIF, /* `#elif' */
|
||||
T_UNDEF, /* `#undef' */
|
||||
T_LINE, /* `#line' */
|
||||
T_ERROR, /* `#error' */
|
||||
T_WARNING, /* `#warning' */
|
||||
T_ENDIF, /* `#endif' */
|
||||
T_SCCS, /* `#sccs', used on system V. */
|
||||
T_IDENT, /* `#ident', used on system V. */
|
||||
T_ASSERT, /* `#assert', taken from system V. */
|
||||
T_UNASSERT, /* `#unassert', taken from system V. */
|
||||
T_SPECLINE, /* special symbol `__LINE__' */
|
||||
T_DATE, /* `__DATE__' */
|
||||
T_FILE, /* `__FILE__' */
|
||||
T_BASE_FILE, /* `__BASE_FILE__' */
|
||||
T_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
|
||||
T_VERSION, /* `__VERSION__' */
|
||||
T_SIZE_TYPE, /* `__SIZE_TYPE__' */
|
||||
T_PTRDIFF_TYPE, /* `__PTRDIFF_TYPE__' */
|
||||
T_WCHAR_TYPE, /* `__WCHAR_TYPE__' */
|
||||
T_USER_LABEL_PREFIX_TYPE, /* `__USER_LABEL_PREFIX__' */
|
||||
T_REGISTER_PREFIX_TYPE, /* `__REGISTER_PREFIX__' */
|
||||
T_TIME, /* `__TIME__' */
|
||||
T_CONST, /* Constant value, used by `__STDC__' */
|
||||
T_MACRO, /* macro defined by `#define' */
|
||||
T_DISABLED, /* macro temporarily turned off for rescan */
|
||||
T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */
|
||||
T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */
|
||||
T_UNUSED /* Used for something not defined. */
|
||||
};
|
||||
|
||||
/* Structure returned by create_definition */
|
||||
typedef struct macrodef MACRODEF;
|
||||
struct macrodef
|
||||
{
|
||||
struct definition *defn;
|
||||
U_CHAR *symnam;
|
||||
int symlen;
|
||||
};
|
||||
|
||||
/* Structure allocated for every #define. For a simple replacement
|
||||
such as
|
||||
#define foo bar ,
|
||||
nargs = -1, the `pattern' list is null, and the expansion is just
|
||||
the replacement text. Nargs = 0 means a functionlike macro with no args,
|
||||
e.g.,
|
||||
#define getchar() getc (stdin) .
|
||||
When there are args, the expansion is the replacement text with the
|
||||
args squashed out, and the reflist is a list describing how to
|
||||
build the output from the input: e.g., "3 chars, then the 1st arg,
|
||||
then 9 chars, then the 3rd arg, then 0 chars, then the 2nd arg".
|
||||
The chars here come from the expansion. Whatever is left of the
|
||||
expansion after the last arg-occurrence is copied after that arg.
|
||||
Note that the reflist can be arbitrarily long---
|
||||
its length depends on the number of times the arguments appear in
|
||||
the replacement text, not how many args there are. Example:
|
||||
#define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
|
||||
pattern list
|
||||
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
|
||||
where (x, y) means (nchars, argno). */
|
||||
|
||||
typedef struct definition DEFINITION;
|
||||
struct definition {
|
||||
int nargs;
|
||||
int length; /* length of expansion string */
|
||||
int predefined; /* True if the macro was builtin or */
|
||||
/* came from the command line */
|
||||
U_CHAR *expansion;
|
||||
int line; /* Line number of definition */
|
||||
char *file; /* File of definition */
|
||||
char rest_args; /* Nonzero if last arg. absorbs the rest */
|
||||
struct reflist {
|
||||
struct reflist *next;
|
||||
char stringify; /* nonzero if this arg was preceded by a
|
||||
# operator. */
|
||||
char raw_before; /* Nonzero if a ## operator before arg. */
|
||||
char raw_after; /* Nonzero if a ## operator after arg. */
|
||||
char rest_args; /* Nonzero if this arg. absorbs the rest */
|
||||
int nchars; /* Number of literal chars to copy before
|
||||
this arg occurrence. */
|
||||
int argno; /* Number of arg to substitute (origin-0) */
|
||||
} *pattern;
|
||||
union {
|
||||
/* Names of macro args, concatenated in reverse order
|
||||
with comma-space between them.
|
||||
The only use of this is that we warn on redefinition
|
||||
if this differs between the old and new definitions. */
|
||||
U_CHAR *argnames;
|
||||
} args;
|
||||
};
|
||||
|
||||
extern U_CHAR is_idchar[256];
|
||||
|
||||
/* Stack of conditionals currently in progress
|
||||
(including both successful and failing conditionals). */
|
||||
|
||||
struct if_stack {
|
||||
struct if_stack *next; /* for chaining to the next stack frame */
|
||||
char *fname; /* copied from input when frame is made */
|
||||
int lineno; /* similarly */
|
||||
int if_succeeded; /* true if a leg of this if-group
|
||||
has been passed through rescan */
|
||||
U_CHAR *control_macro; /* For #ifndef at start of file,
|
||||
this is the macro name tested. */
|
||||
enum node_type type; /* type of last directive seen in this group */
|
||||
};
|
||||
typedef struct if_stack IF_STACK_FRAME;
|
||||
|
||||
extern void cpp_buf_line_and_col PARAMS((cpp_buffer*, long*, long*));
|
||||
extern cpp_buffer* cpp_file_buffer PARAMS((cpp_reader*));
|
||||
|
||||
extern void cpp_error ();
|
||||
extern void cpp_warning ();
|
||||
extern void cpp_pedwarn ();
|
||||
extern void cpp_error_with_line ();
|
||||
extern void cpp_warning_with_line ();
|
||||
extern void cpp_pedwarn_with_line ();
|
||||
extern void cpp_pedwarn_with_file_and_line ();
|
||||
extern void fatal ();
|
||||
extern void cpp_error_from_errno ();
|
||||
extern void cpp_perror_with_name ();
|
||||
extern void cpp_pfatal_with_name ();
|
||||
|
||||
extern void cpp_grow_buffer PARAMS ((cpp_reader*, long));
|
||||
extern int cpp_parse_escape PARAMS ((cpp_reader*, char**));
|
||||
extern cpp_buffer* cpp_push_buffer PARAMS ((cpp_reader *, U_CHAR*, long));
|
||||
extern cpp_buffer* cpp_pop_buffer PARAMS ((cpp_reader *));
|
||||
|
||||
extern cpp_hashnode* cpp_lookup PARAMS ((cpp_reader*, const U_CHAR*,
|
||||
int, int));
|
||||
|
||||
extern long cpp_parse_expr PARAMS ((cpp_reader*));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
102
gcc/cppmain.c
Normal file
102
gcc/cppmain.c
Normal file
@ -0,0 +1,102 @@
|
||||
/* CPP main program, using CPP Library.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
Written by Per Bothner, 1994-95.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In other words, you are welcome to use, share and improve this program.
|
||||
You are forbidden to forbid anyone else to use, share and improve
|
||||
what you give them. Help stamp out software-hoarding! */
|
||||
|
||||
#include "cpplib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *getenv ();
|
||||
|
||||
cpp_reader parse_in;
|
||||
cpp_options options;
|
||||
|
||||
/* More 'friendly' abort that prints the line and file.
|
||||
config.h can #define abort fancy_abort if you like that sort of thing. */
|
||||
|
||||
void
|
||||
fancy_abort ()
|
||||
{
|
||||
fatal ("Internal gcc abort.");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
int argi = 1; /* Next argument to handle. */
|
||||
struct cpp_options *opts = &options;
|
||||
|
||||
p = argv[0] + strlen (argv[0]);
|
||||
while (p != argv[0] && p[-1] != '/') --p;
|
||||
progname = p;
|
||||
|
||||
init_parse_file (&parse_in);
|
||||
parse_in.data = opts;
|
||||
|
||||
init_parse_options (opts);
|
||||
|
||||
argi += cpp_handle_options (&parse_in, argc - argi , argv + argi);
|
||||
if (argi < argc)
|
||||
fatal ("Invalid option `%s'", argv[argi]);
|
||||
parse_in.show_column = 1;
|
||||
|
||||
i = push_parse_file (&parse_in, opts->in_fname);
|
||||
if (i != SUCCESS_EXIT_CODE)
|
||||
return i;
|
||||
|
||||
/* Now that we know the input file is valid, open the output. */
|
||||
|
||||
if (!opts->out_fname || !strcmp (opts->out_fname, ""))
|
||||
opts->out_fname = "stdout";
|
||||
else if (! freopen (opts->out_fname, "w", stdout))
|
||||
cpp_pfatal_with_name (&parse_in, opts->out_fname);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
#if 0
|
||||
int ch = PARSE_GETC (&parse_in);
|
||||
if (ch < 0)
|
||||
break;
|
||||
if (! opts->no_output)
|
||||
putchar (ch);
|
||||
#else
|
||||
enum cpp_token kind;
|
||||
if (! opts->no_output)
|
||||
{
|
||||
fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout);
|
||||
}
|
||||
parse_in.limit = parse_in.token_buffer;
|
||||
kind = cpp_get_token (&parse_in);
|
||||
if (kind == CPP_EOF)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cpp_finish (&parse_in);
|
||||
|
||||
if (parse_in.errors)
|
||||
exit (FAILURE_EXIT_CODE);
|
||||
exit (SUCCESS_EXIT_CODE);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user