tradcpp.c: New file.
* tradcpp.c: New file. * tradcif.y: New file. * tradcif.c: New generated file. * Makefile.in: Add rules to build tradcpp.o, tradcif.o, $(srcdir)/tradcif.c. Add tradcpp to STAGESTUFF and dependencies of C. Install tradcpp from install-common, in $(libsubdir). From-SVN: r34893
This commit is contained in:
parent
60893f4317
commit
24c3c71a8c
5 changed files with 6985 additions and 2 deletions
|
@ -1,3 +1,14 @@
|
|||
2000-07-06 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* tradcpp.c: New file.
|
||||
* tradcif.y: New file.
|
||||
* tradcif.c: New generated file.
|
||||
|
||||
* Makefile.in: Add rules to build tradcpp.o, tradcif.o,
|
||||
$(srcdir)/tradcif.c. Add tradcpp to STAGESTUFF and
|
||||
dependencies of C. Install tradcpp from install-common, in
|
||||
$(libsubdir).
|
||||
|
||||
2000-07-06 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* cppinit.c: Include cppdefault.h. Refer to
|
||||
|
|
|
@ -716,7 +716,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
|
|||
xgcc$(exeext) xcpp$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES) \
|
||||
$(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) cc1obj$(exeext) \
|
||||
enquire$(exeext) protoize$(exeext) unprotoize$(exeext) \
|
||||
specs collect2$(exeext) $(USE_COLLECT2) underscore.c \
|
||||
specs collect2$(exeext) $(USE_COLLECT2) underscore.c tradcpp$(exeext) \
|
||||
gcov$(exeext) *.[0-9][0-9].* *.[si] libcpp.a libgcc libgcc.mk \
|
||||
$(LANG_STAGESTUFF)
|
||||
|
||||
|
@ -869,7 +869,7 @@ native: config.status auto-host.h cpp$(exeext) intl.all $(LANGUAGES) \
|
|||
$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
|
||||
|
||||
# Define the names for selecting languages in LANGUAGES.
|
||||
C c: cc1$(exeext)
|
||||
C c: cc1$(exeext) tradcpp$(exeext)
|
||||
PROTO: proto
|
||||
|
||||
# Tell GNU make these are phony targets.
|
||||
|
@ -1814,6 +1814,18 @@ cppdefault.o: cppdefault.c $(CONFIG_H) system.h cppdefault.h Makefile
|
|||
|
||||
mkdeps.o: mkdeps.c $(CONFIG_H) system.h mkdeps.h
|
||||
|
||||
# The traditional mode preprocessor, a separate program for ease of
|
||||
# maintenance. Some code is shared with the ISO-C cpp.
|
||||
tradcpp$(exeext): tradcpp.o tradcif.o cppdefault.o $(LIBDEPS)
|
||||
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o tradcpp$(exeext) \
|
||||
tradcpp.o tradcif.o cppdefault.o version.o intl.o $(LIBS)
|
||||
|
||||
tradcpp.o: tradcpp.c $(CONFIG_H) system.h version.h cppdefault.h
|
||||
tradcif.o: tradcif.c $(CONFIG_H) system.h
|
||||
|
||||
$(srcdir)/tradcif.c: $(srcdir)/tradcif.y
|
||||
cd $(srcdir); $(BISON) $(BISONFLAGS) -o tradcif.c tradcif.y
|
||||
|
||||
# Note for the stamp targets, we run the program `true' instead of
|
||||
# having an empty command (nothing following the semicolon).
|
||||
|
||||
|
@ -2339,6 +2351,8 @@ install-common: native installdirs $(EXTRA_PARTS) lang.install-common
|
|||
fi
|
||||
-rm -f $(libsubdir)/cpp$(exeext)
|
||||
$(INSTALL_PROGRAM) cpp$(exeext) $(libsubdir)/cpp$(exeext)
|
||||
-rm -f $(libsubdir)/tradcpp$(exeext)
|
||||
$(INSTALL_PROGRAM) tradcpp$(exeext) $(libsubdir)/tradcpp$(exeext)
|
||||
# Install gcov if it was compiled.
|
||||
-if [ -f gcov$(exeext) ]; \
|
||||
then \
|
||||
|
|
1543
gcc/tradcif.c
Normal file
1543
gcc/tradcif.c
Normal file
File diff suppressed because it is too large
Load diff
584
gcc/tradcif.y
Normal file
584
gcc/tradcif.y
Normal file
|
@ -0,0 +1,584 @@
|
|||
/* Parse C expressions for CCCP.
|
||||
Copyright (C) 1987 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 1, 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!
|
||||
|
||||
Adapted from expread.y of GDB by Paul Rubin, July 1986.
|
||||
|
||||
/* Parse a C expression from text in a string */
|
||||
|
||||
%{
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
int yylex PARAMS ((void));
|
||||
void yyerror PARAMS ((const char *msgid));
|
||||
extern void error PARAMS ((const char *msgid, ...));
|
||||
extern void warning PARAMS ((const char *msgid, ...));
|
||||
extern struct hashnode *lookup PARAMS ((const unsigned char *, int, int));
|
||||
|
||||
int parse_number PARAMS ((int));
|
||||
int parse_escape PARAMS ((char **));
|
||||
int parse_c_expression PARAMS ((char *));
|
||||
|
||||
int expression_value;
|
||||
static jmp_buf parse_return_error;
|
||||
|
||||
/* some external tables of character types */
|
||||
extern unsigned char is_idstart[], is_idchar[];
|
||||
|
||||
#ifndef CHAR_TYPE_SIZE
|
||||
#define CHAR_TYPE_SIZE BITS_PER_UNIT
|
||||
#endif
|
||||
%}
|
||||
|
||||
%union {
|
||||
struct constant {long value; int unsignedp;} integer;
|
||||
int voidval;
|
||||
char *sval;
|
||||
}
|
||||
|
||||
%type <integer> exp exp1 start
|
||||
%token <integer> INT CHAR
|
||||
%token <sval> NAME
|
||||
%token <integer> ERROR
|
||||
|
||||
%right '?' ':'
|
||||
%left ','
|
||||
%left OR
|
||||
%left AND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left EQUAL NOTEQUAL
|
||||
%left '<' '>' LEQ GEQ
|
||||
%left LSH RSH
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right UNARY
|
||||
|
||||
/* %expect 40 */
|
||||
|
||||
%%
|
||||
|
||||
start : exp1
|
||||
{ expression_value = $1.value; }
|
||||
;
|
||||
|
||||
/* Expressions, including the comma operator. */
|
||||
exp1 : exp
|
||||
| exp1 ',' exp
|
||||
{ $$ = $3; }
|
||||
;
|
||||
|
||||
/* Expressions, not including the comma operator. */
|
||||
exp : '-' exp %prec UNARY
|
||||
{ $$.value = - $2.value;
|
||||
$$.unsignedp = $2.unsignedp; }
|
||||
| '!' exp %prec UNARY
|
||||
{ $$.value = ! $2.value;
|
||||
$$.unsignedp = 0; }
|
||||
| '+' exp %prec UNARY
|
||||
{ $$ = $2; }
|
||||
| '~' exp %prec UNARY
|
||||
{ $$.value = ~ $2.value;
|
||||
$$.unsignedp = $2.unsignedp; }
|
||||
| '(' exp1 ')'
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
/* Binary operators in order of decreasing precedence. */
|
||||
exp : exp '*' exp
|
||||
{ $$.unsignedp = $1.unsignedp || $3.unsignedp;
|
||||
if ($$.unsignedp)
|
||||
$$.value = (unsigned) $1.value * $3.value;
|
||||
else
|
||||
$$.value = $1.value * $3.value; }
|
||||
| exp '/' exp
|
||||
{ if ($3.value == 0)
|
||||
{
|
||||
error ("division by zero in #if");
|
||||
$3.value = 1;
|
||||
}
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp;
|
||||
if ($$.unsignedp)
|
||||
$$.value = (unsigned) $1.value / $3.value;
|
||||
else
|
||||
$$.value = $1.value / $3.value; }
|
||||
| exp '%' exp
|
||||
{ if ($3.value == 0)
|
||||
{
|
||||
error ("division by zero in #if");
|
||||
$3.value = 1;
|
||||
}
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp;
|
||||
if ($$.unsignedp)
|
||||
$$.value = (unsigned) $1.value % $3.value;
|
||||
else
|
||||
$$.value = $1.value % $3.value; }
|
||||
| exp '+' exp
|
||||
{ $$.value = $1.value + $3.value;
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp; }
|
||||
| exp '-' exp
|
||||
{ $$.value = $1.value - $3.value;
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp; }
|
||||
| exp LSH exp
|
||||
{ $$.unsignedp = $1.unsignedp;
|
||||
if ($$.unsignedp)
|
||||
$$.value = (unsigned) $1.value << $3.value;
|
||||
else
|
||||
$$.value = $1.value << $3.value; }
|
||||
| exp RSH exp
|
||||
{ $$.unsignedp = $1.unsignedp;
|
||||
if ($$.unsignedp)
|
||||
$$.value = (unsigned) $1.value >> $3.value;
|
||||
else
|
||||
$$.value = $1.value >> $3.value; }
|
||||
| exp EQUAL exp
|
||||
{ $$.value = ($1.value == $3.value);
|
||||
$$.unsignedp = 0; }
|
||||
| exp NOTEQUAL exp
|
||||
{ $$.value = ($1.value != $3.value);
|
||||
$$.unsignedp = 0; }
|
||||
| exp LEQ exp
|
||||
{ $$.unsignedp = 0;
|
||||
if ($1.unsignedp || $3.unsignedp)
|
||||
$$.value =
|
||||
(unsigned) $1.value <= (unsigned) $3.value;
|
||||
else
|
||||
$$.value = $1.value <= $3.value; }
|
||||
| exp GEQ exp
|
||||
{ $$.unsignedp = 0;
|
||||
if ($1.unsignedp || $3.unsignedp)
|
||||
$$.value =
|
||||
(unsigned) $1.value >= (unsigned) $3.value;
|
||||
else
|
||||
$$.value = $1.value >= $3.value; }
|
||||
| exp '<' exp
|
||||
{ $$.unsignedp = 0;
|
||||
if ($1.unsignedp || $3.unsignedp)
|
||||
$$.value =
|
||||
(unsigned) $1.value < (unsigned) $3.value;
|
||||
else
|
||||
$$.value = $1.value < $3.value; }
|
||||
| exp '>' exp
|
||||
{ $$.unsignedp = 0;
|
||||
if ($1.unsignedp || $3.unsignedp)
|
||||
$$.value =
|
||||
(unsigned) $1.value > (unsigned) $3.value;
|
||||
else
|
||||
$$.value = $1.value > $3.value; }
|
||||
| exp '&' exp
|
||||
{ $$.value = $1.value & $3.value;
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp; }
|
||||
| exp '^' exp
|
||||
{ $$.value = $1.value ^ $3.value;
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp; }
|
||||
| exp '|' exp
|
||||
{ $$.value = $1.value | $3.value;
|
||||
$$.unsignedp = $1.unsignedp || $3.unsignedp; }
|
||||
| exp AND exp
|
||||
{ $$.value = ($1.value && $3.value);
|
||||
$$.unsignedp = 0; }
|
||||
| exp OR exp
|
||||
{ $$.value = ($1.value || $3.value);
|
||||
$$.unsignedp = 0; }
|
||||
| exp '?' exp ':' exp
|
||||
{ $$.value = $1.value ? $3.value : $5.value;
|
||||
$$.unsignedp = $3.unsignedp || $5.unsignedp; }
|
||||
| INT
|
||||
{ $$ = yylval.integer; }
|
||||
| CHAR
|
||||
{ $$ = yylval.integer; }
|
||||
| NAME
|
||||
{ $$.value = 0;
|
||||
$$.unsignedp = 0; }
|
||||
;
|
||||
%%
|
||||
|
||||
/* During parsing of a C expression, the pointer to the next character
|
||||
is in this variable. */
|
||||
|
||||
static char *lexptr;
|
||||
|
||||
/* Take care of parsing a number (anything that starts with a digit).
|
||||
Set yylval and return the token type; update lexptr.
|
||||
LEN is the number of characters in it. */
|
||||
|
||||
/* maybe needs to actually deal with floating point numbers */
|
||||
|
||||
int
|
||||
parse_number (olen)
|
||||
int olen;
|
||||
{
|
||||
register char *p = lexptr;
|
||||
register long n = 0;
|
||||
register int c;
|
||||
register int base = 10;
|
||||
register int len = olen;
|
||||
|
||||
for (c = 0; c < len; c++)
|
||||
if (p[c] == '.') {
|
||||
/* It's a float since it contains a point. */
|
||||
yyerror ("floating point numbers not allowed in #if expressions");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
yylval.integer.unsignedp = 0;
|
||||
|
||||
if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
|
||||
p += 2;
|
||||
base = 16;
|
||||
len -= 2;
|
||||
}
|
||||
else if (*p == '0')
|
||||
base = 8;
|
||||
|
||||
while (len > 0) {
|
||||
c = *p++;
|
||||
len--;
|
||||
if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
n *= base;
|
||||
n += c - '0';
|
||||
} else if (base == 16 && c >= 'a' && c <= 'f') {
|
||||
n *= base;
|
||||
n += c - 'a' + 10;
|
||||
} else {
|
||||
/* `l' means long, and `u' means unsigned. */
|
||||
while (1) {
|
||||
if (c == 'l' || c == 'L')
|
||||
;
|
||||
else if (c == 'u' || c == 'U')
|
||||
yylval.integer.unsignedp = 1;
|
||||
else
|
||||
break;
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
c = *p++;
|
||||
len--;
|
||||
}
|
||||
/* Don't look for any more digits after the suffixes. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len != 0) {
|
||||
yyerror ("Invalid number in #if expression");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* If too big to be signed, consider it unsigned. */
|
||||
if (n < 0)
|
||||
yylval.integer.unsignedp = 1;
|
||||
|
||||
lexptr = p;
|
||||
yylval.integer.value = n;
|
||||
return INT;
|
||||
}
|
||||
|
||||
struct token {
|
||||
const char *operator;
|
||||
int token;
|
||||
};
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
static struct token tokentab2[] = {
|
||||
{"&&", AND},
|
||||
{"||", OR},
|
||||
{"<<", LSH},
|
||||
{">>", RSH},
|
||||
{"==", EQUAL},
|
||||
{"!=", NOTEQUAL},
|
||||
{"<=", LEQ},
|
||||
{">=", GEQ},
|
||||
{NULL, ERROR}
|
||||
};
|
||||
|
||||
/* Read one token, getting characters through lexptr. */
|
||||
|
||||
int
|
||||
yylex ()
|
||||
{
|
||||
register int c;
|
||||
register int namelen;
|
||||
register char *tokstart;
|
||||
register struct token *toktab;
|
||||
|
||||
retry:
|
||||
|
||||
tokstart = lexptr;
|
||||
c = *tokstart;
|
||||
/* See if it is a special token of length 2. */
|
||||
for (toktab = tokentab2; toktab->operator != NULL; toktab++)
|
||||
if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
|
||||
lexptr += 2;
|
||||
return toktab->token;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
return 0;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
lexptr++;
|
||||
goto retry;
|
||||
|
||||
case '\'':
|
||||
lexptr++;
|
||||
c = *lexptr++;
|
||||
if (c == '\\')
|
||||
c = parse_escape (&lexptr);
|
||||
|
||||
/* Sign-extend the constant if chars are signed on target machine. */
|
||||
{
|
||||
if (lookup ((const unsigned char *)"__CHAR_UNSIGNED__",
|
||||
sizeof ("__CHAR_UNSIGNED__")-1, -1)
|
||||
|| ((c >> (CHAR_TYPE_SIZE - 1)) & 1) == 0)
|
||||
yylval.integer.value = c & ((1 << CHAR_TYPE_SIZE) - 1);
|
||||
else
|
||||
yylval.integer.value = c | ~((1 << CHAR_TYPE_SIZE) - 1);
|
||||
}
|
||||
|
||||
yylval.integer.unsignedp = 0;
|
||||
c = *lexptr++;
|
||||
if (c != '\'') {
|
||||
yyerror ("Invalid character constant in #if");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return CHAR;
|
||||
|
||||
/* some of these chars are invalid in constant expressions;
|
||||
maybe do something about them later */
|
||||
case '/':
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '%':
|
||||
case '|':
|
||||
case '&':
|
||||
case '^':
|
||||
case '~':
|
||||
case '!':
|
||||
case '@':
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
case '[':
|
||||
case ']':
|
||||
case '.':
|
||||
case '?':
|
||||
case ':':
|
||||
case '=':
|
||||
case '{':
|
||||
case '}':
|
||||
case ',':
|
||||
lexptr++;
|
||||
return c;
|
||||
|
||||
case '"':
|
||||
yyerror ("double quoted strings not allowed in #if expressions");
|
||||
return ERROR;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
/* It's a number */
|
||||
for (namelen = 0;
|
||||
c = tokstart[namelen], is_idchar[c] || c == '.';
|
||||
namelen++)
|
||||
;
|
||||
return parse_number (namelen);
|
||||
}
|
||||
|
||||
if (!is_idstart[c]) {
|
||||
yyerror ("Invalid token in expression");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* It is a name. See how long it is. */
|
||||
|
||||
for (namelen = 0;
|
||||
is_idchar[(int)(unsigned char)tokstart[namelen]];
|
||||
namelen++)
|
||||
;
|
||||
|
||||
lexptr += namelen;
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
parse_escape (string_ptr)
|
||||
char **string_ptr;
|
||||
{
|
||||
register int c = *(*string_ptr)++;
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
return TARGET_BELL;
|
||||
case 'b':
|
||||
return TARGET_BS;
|
||||
case 'e':
|
||||
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 '^':
|
||||
c = *(*string_ptr)++;
|
||||
if (c == '\\')
|
||||
c = parse_escape (string_ptr);
|
||||
if (c == '?')
|
||||
return 0177;
|
||||
return (c & 0200) | (c & 037);
|
||||
|
||||
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 << CHAR_TYPE_SIZE) - 1)) != 0)
|
||||
{
|
||||
i &= (1 << CHAR_TYPE_SIZE) - 1;
|
||||
warning ("octal character constant does not fit in a byte");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
case 'x':
|
||||
{
|
||||
register int i = 0;
|
||||
for (;;)
|
||||
{
|
||||
c = *(*string_ptr)++;
|
||||
if (c >= '0' && c <= '9')
|
||||
i = (i << 4) + c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
i = (i << 4) + c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
i = (i << 4) + c - 'A' + 10;
|
||||
else
|
||||
{
|
||||
(*string_ptr)--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
|
||||
{
|
||||
i &= (1 << BITS_PER_UNIT) - 1;
|
||||
warning ("hex character constant does not fit in a byte");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
yyerror (s)
|
||||
const char *s;
|
||||
{
|
||||
error (s);
|
||||
longjmp (parse_return_error, 1);
|
||||
}
|
||||
|
||||
/* This page contains the entry point to this file. */
|
||||
|
||||
/* Parse STRING as an expression, and complain if this fails
|
||||
to use up all of the contents of STRING. */
|
||||
/* We do not support C comments. They should be removed before
|
||||
this function is called. */
|
||||
|
||||
int
|
||||
parse_c_expression (string)
|
||||
char *string;
|
||||
{
|
||||
lexptr = string;
|
||||
|
||||
if (lexptr == 0 || *lexptr == 0) {
|
||||
error ("empty #if expression");
|
||||
return 0; /* don't include the #if group */
|
||||
}
|
||||
|
||||
/* if there is some sort of scanning error, just return 0 and assume
|
||||
the parsing routine has printed an error message somewhere.
|
||||
there is surely a better thing to do than this. */
|
||||
if (setjmp (parse_return_error))
|
||||
return 0;
|
||||
|
||||
if (yyparse ())
|
||||
return 0; /* actually this is never reached
|
||||
the way things stand. */
|
||||
if (*lexptr)
|
||||
error ("Junk after end of expression.");
|
||||
|
||||
return expression_value; /* set by yyparse () */
|
||||
}
|
4831
gcc/tradcpp.c
Normal file
4831
gcc/tradcpp.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue