home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
243_01
/
cpp5.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-14
|
32KB
|
1,032 lines
/*
* C P P 5 . C
* E x p r e s s i o n E v a l u a t i o n
*
* Edit History
* 31-Aug-84 MM USENET net.sources release
* 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring()
* so they work correctly with token concatenation.
* Added string formal recognition.
* 25-Oct-84 MM "Short-circuit" evaluate #if's so that we
* don't print unnecessary error messages for
* #if !defined(FOO) && FOO != 0 && 10 / FOO ...
* 31-Oct-84 ado/MM Added token concatenation
* 6-Nov-84 MM Split from #define stuff, added sizeof stuff
* 19-Nov-84 ado #if error returns TRUE for (sigh) compatibility
* 22-Apr-85 ado/MM added evalone to properly handle \value
* 29-Apr-85 ado Cleaned up #if ... sizeof
*/
#include "cppdef.h"
#include "cpp.h"
/*
* Evaluate an #if expression.
*/
static char *opname[] = { /* For debug and error messages */
"end of expression", "val", "id",
"+", "-", "*", "/", "%",
"<<", ">>", "&", "|", "^",
"==", "!=", "<", "<=", ">=", ">",
"&&", "||", "?", ":", ",",
"unary +", "unary -", "~", "!", "(", ")", "(none)",
};
/*
* opdope[] has the operator precedence:
* Bits
* 7 Unused (so the value is always positive)
* 6-2 Precedence (000x .. 017x)
* 1-0 Binary op. flags:
* 01 The binop flag should be set/cleared when this op is seen.
* 10 The new value of the binop flag.
* Note: Expected, New binop
* constant 0 1 Binop, end, or ) should follow constants
* End of line 1 0 End may not be preceeded by an operator
* binary 1 0 Binary op follows a value, value follows.
* unary 0 0 Unary op doesn't follow a value, value follows
* ( 0 0 Doesn't follow value, value or unop follows
* ) 1 1 Follows value. Op follows.
*/
static char opdope[OP_MAX] = {
0001, /* End of expression */
0002, /* Digit */
0000, /* Letter (identifier) */
0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */
0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */
0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */
0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */
/*
* Unary op's follow
*/
0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */
0170, 0013, 0023, /* LPA, RPA, END */
};
/*
* OP_QUE and OP_RPA have alternate precedences:
*/
#define OP_RPA_PREC 0013
#define OP_QUE_PREC 0034
/*
* S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
* #if FOO != 0 && 10 / FOO ...
* doesn't generate an error message. They are stored in optab.skip.
*/
#define S_ANDOR 2
#define S_QUEST 1
typedef struct optab {
char op; /* Operator */
char prec; /* Its precedence */
char skip; /* Short-circuit: TRUE to skip */
} OPTAB;
static int evalue; /* Current value from evallex() */
#ifdef nomacargs
FILE_LOCAL int
isbinary(op)
register int op;
{
return (op >= FIRST_BINOP && op <= LAST_BINOP);
}
FILE_LOCAL int
isunary(op)
register int op;
{
return (op >= FIRST_UNOP && op <= LAST_UNOP);
}
#else
#define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP)
#define isunary(op) (op >= FIRST_UNOP && op <= LAST_UNOP)
#endif
/*
* The following definitions are used to specify basic variable sizes.
*/
#ifndef S_CHAR
#define S_CHAR (sizeof (char))
#endif
#ifndef S_SINT
#define S_SINT (sizeof (short int))
#endif
#ifndef S_INT
#define S_INT (sizeof (int))
#endif
#ifndef S_LINT
#define S_LINT (sizeof (long int))
#endif
#ifndef S_FLOAT
#define S_FLOAT (sizeof (float))
#endif
#ifndef S_DOUBLE
#define S_DOUBLE (sizeof (double))
#endif
#ifndef S_PCHAR
#define S_PCHAR (sizeof (char *))
#endif
#ifndef S_PSINT
#define S_PSINT (sizeof (short int *))
#endif
#ifndef S_PINT
#define S_PINT (sizeof (int *))
#endif
#ifndef S_PLINT
#define S_PLINT (sizeof (long int *))
#endif
#ifndef S_PFLOAT
#define S_PFLOAT (sizeof (float *))
#endif
#ifndef S_PDOUBLE
#define S_PDOUBLE (sizeof (double *))
#endif
#ifndef S_PFPTR
#define S_PFPTR (sizeof (int (*)()))
#endif
typedef struct types {
short type; /* This is the bit if */
char *name; /* this is the token word */
short excluded; /* but these aren't legal here */
} TYPES;
#define ANYSIGN (T_SIGNED | T_UNSIGNED)
#define ANYFLOAT (T_FLOAT | T_DOUBLE)
#define ANYINT (T_CHAR | T_SHORT | T_INT | T_LONG)
static TYPES basic_types[] = {
T_CHAR, "char", ANYFLOAT | ANYINT,
T_INT, "int", ANYFLOAT | T_CHAR | T_INT,
T_FLOAT, "float", ANYFLOAT | ANYINT | ANYSIGN,
T_DOUBLE, "double", ANYFLOAT | ANYINT | ANYSIGN,
T_SHORT, "short", ANYFLOAT | ANYINT,
T_LONG, "long", ANYFLOAT | ANYINT,
T_SIGNED, "signed", ANYFLOAT | ANYINT | T_CHAR | T_INT,
T_UNSIGNED, "unsigned", ANYFLOAT | ANYINT | T_CHAR | T_INT,
0, NULL, 0 /* Signal end */
};
/*
* The order of this table is important -- it is also referenced by
* the command line processor to allow run-time overriding of the
* built-in size values. The order must not be changed:
* char, short, int, long, float, double (func pointer)
*/
SIZES size_table[] = {
{ T_CHAR, S_CHAR, S_PCHAR }, /* char */
{ T_SHORT, S_SINT, S_PSINT }, /* short int */
{ T_INT, S_INT, S_PINT }, /* int */
{ T_LONG, S_LINT, S_PLINT }, /* long */
{ T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */
{ T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */
{ T_FPTR, 0, S_PFPTR }, /* int (*()) */
{ 0, 0, 0 }, /* End of table */
};
int
eval()
/*
* Evaluate an expression. Straight-forward operator precedence.
* This is called from control() on encountering an #if statement.
* It calls the following routines:
* evallex Lexical analyser -- returns the type and value of
* the next input token.
* evaleval Evaluate the current operator, given the values on
* the value stack. Returns a pointer to the (new)
* value stack.
* For compatiblity with older cpp's, this return returns 1 (TRUE)
* if a syntax error is detected.
*/
{
register int op; /* Current operator */
register int *valp; /* -> value vector */
register OPTAB *opp; /* Operator stack */
int prec; /* Op precedence */
int binop; /* Set if binary op. needed */
int op1; /* Operand from stack */
int skip; /* For short-circuit testing */
int value[NEXP]; /* Value stack */
OPTAB