revised check_ival() (among some other small changes)

This commit is contained in:
erikb 1986-04-03 11:33:32 +00:00
parent 52d743f223
commit 725d3fa6ea
4 changed files with 152 additions and 148 deletions

View file

@ -9,10 +9,12 @@ EM_INCLUDES =$(EM)/h# # directory containing EM interface definition
# Libraries # Libraries
SYSLIB = /user1/erikb/em/lib/libsystem.a SYSLIB = /user1/erikb/em/lib/libsystem.a
EMLIB = /user1/erikb/em/lib/libemk.a EMKLIB = /user1/erikb/em/lib/libemk.a
EMELIB = /user1/erikb/em/lib/libeme.a
STRLIB = /user1/erikb/em/lib/libstr.a STRLIB = /user1/erikb/em/lib/libstr.a
EMMESLIB = /user1/erikb/em/lib/libem_mes.a EMMESLIB = /user1/erikb/em/lib/libem_mes.a
LIBS = $(EMMESLIB) $(EMLIB) $(STRLIB) $(SYSLIB) LIBS = $(EMMESLIB) $(EMKLIB) $(STRLIB) $(SYSLIB)
ELIBS = $(EMMESLIB) $(EMELIB) $(STRLIB) $(SYSLIB)
LIB_INCLUDES = /user1/erikb/em/h LIB_INCLUDES = /user1/erikb/em/h
# Where to install the compiler and its driver # Where to install the compiler and its driver
@ -128,6 +130,10 @@ main: $(OBJ) Makefile
$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o main $(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(LIBS) -o main
size main size main
emain: $(OBJ) Makefile
$(CC) $(COPTIONS) $(LFLAGS) $(OBJ) $(ELIBS) -o emain
size emain
cfiles: hfiles LLfiles $(GSRC) cfiles: hfiles LLfiles $(GSRC)
@touch cfiles @touch cfiles

View file

@ -46,21 +46,23 @@ ch7mon(oper, expp)
} }
break; break;
case '&': case '&':
if ((*expp)->ex_type->tp_fund == ARRAY) if ((*expp)->ex_type->tp_fund == ARRAY) {
warning("& before array: ignored");
array2pointer(expp); array2pointer(expp);
}
else else
if ((*expp)->ex_type->tp_fund == FUNCTION) if ((*expp)->ex_type->tp_fund == FUNCTION) {
warning("& before function: ignored");
function2pointer(expp); function2pointer(expp);
}
else else
#ifndef NOBITFIELD #ifndef NOBITFIELD
if ((*expp)->ex_type->tp_fund == FIELD) { if ((*expp)->ex_type->tp_fund == FIELD)
expr_error(*expp, "& applied to field variable"); expr_error(*expp, "& applied to field variable");
}
else else
#endif NOBITFIELD #endif NOBITFIELD
if (!(*expp)->ex_lvalue) { if (!(*expp)->ex_lvalue)
expr_error(*expp, "& applied to non-lvalue"); expr_error(*expp, "& applied to non-lvalue");
}
else { else {
/* assume that enums are already filtered out */ /* assume that enums are already filtered out */
if ( (*expp)->ex_class == Value if ( (*expp)->ex_class == Value
@ -89,11 +91,15 @@ ch7mon(oper, expp)
int fund = (*expp)->ex_type->tp_fund; int fund = (*expp)->ex_type->tp_fund;
if (fund == FLOAT || fund == DOUBLE) { if (fund == FLOAT || fund == DOUBLE) {
expr_error(*expp, "~ not allowed on %s operands", expr_error(
symbol2str(fund)); *expp,
"~ not allowed on %s operands",
symbol2str(fund)
);
erroneous2int(expp); erroneous2int(expp);
break; break;
} }
/* FALL THROUGH */
} }
case '-': case '-':
any2arith(expp, oper); any2arith(expp, oper);
@ -106,7 +112,7 @@ ch7mon(oper, expp)
switch_sign_fp(*expp); switch_sign_fp(*expp);
else else
*expp = new_oper((*expp)->ex_type, *expp = new_oper((*expp)->ex_type,
NILEXPR, oper, *expp); NILEXPR, oper, *expp);
break; break;
case '!': case '!':
if ((*expp)->ex_type->tp_fund == FUNCTION) if ((*expp)->ex_type->tp_fund == FUNCTION)
@ -116,7 +122,7 @@ ch7mon(oper, expp)
opnd2test(expp, '!'); opnd2test(expp, '!');
if (is_cp_cst(*expp)) { if (is_cp_cst(*expp)) {
(*expp)->VL_VALUE = !((*expp)->VL_VALUE); (*expp)->VL_VALUE = !((*expp)->VL_VALUE);
(*expp)->ex_type = int_type; (*expp)->ex_type = int_type; /* a cast ???(EB) */
} }
else else
*expp = new_oper(int_type, NILEXPR, oper, *expp); *expp = new_oper(int_type, NILEXPR, oper, *expp);

View file

@ -32,12 +32,12 @@ struct expr *do_array(), *do_struct(), *IVAL();
of type tp with the initialisation expression expr by calling IVAL(). of type tp with the initialisation expression expr by calling IVAL().
Guided by type tp, the expression is evaluated. Guided by type tp, the expression is evaluated.
*/ */
do_ival(tpp, expr) do_ival(tpp, ex)
struct type **tpp; struct type **tpp;
struct expr *expr; struct expr *ex;
{ {
if (IVAL(tpp, expr) != 0) if (IVAL(tpp, ex) != 0)
too_many_initialisers(expr); too_many_initialisers(ex);
} }
/* IVAL() recursively guides the initialisation expression through the /* IVAL() recursively guides the initialisation expression through the
@ -52,9 +52,9 @@ do_ival(tpp, expr)
IVAL() returns a pointer to the remaining expression tree. IVAL() returns a pointer to the remaining expression tree.
*/ */
struct expr * struct expr *
IVAL(tpp, expr) IVAL(tpp, ex)
struct type **tpp; /* type of global variable */ struct type **tpp; /* type of global variable */
struct expr *expr; /* initialiser expression */ struct expr *ex; /* initialiser expression */
{ {
register struct type *tp = *tpp; register struct type *tp = *tpp;
@ -63,22 +63,22 @@ IVAL(tpp, expr)
/* array initialisation */ /* array initialisation */
if (valid_type(tp->tp_up, "array element") == 0) if (valid_type(tp->tp_up, "array element") == 0)
return 0; return 0;
if (ISCOMMA(expr)) /* list of initialisation expressions */ if (ISCOMMA(ex)) /* list of initialisation expressions */
return do_array(expr, tpp); return do_array(ex, tpp);
/* catch initialisations like char s[] = "I am a string" */ /* catch initialisations like char s[] = "I am a string" */
if (tp->tp_up->tp_fund == CHAR && expr->ex_class == String) if (tp->tp_up->tp_fund == CHAR && ex->ex_class == String)
init_string(tpp, expr); init_string(tpp, ex);
else /* " int i[24] = 12;" */ else /* " int i[24] = 12;" */
check_and_pad(expr, tpp); check_and_pad(ex, tpp);
break; break;
case STRUCT: case STRUCT:
/* struct initialisation */ /* struct initialisation */
if (valid_type(tp, "struct") == 0) if (valid_type(tp, "struct") == 0)
return 0; return 0;
if (ISCOMMA(expr)) /* list of initialisation expressions */ if (ISCOMMA(ex)) /* list of initialisation expressions */
return do_struct(expr, tp); return do_struct(ex, tp);
/* "struct foo f = 12;" */ /* "struct foo f = 12;" */
check_and_pad(expr, tpp); check_and_pad(ex, tpp);
break; break;
case UNION: case UNION:
error("union initialisation not allowed"); error("union initialisation not allowed");
@ -86,17 +86,17 @@ IVAL(tpp, expr)
case ERRONEOUS: case ERRONEOUS:
break; break;
default: /* fundamental type */ default: /* fundamental type */
if (ISCOMMA(expr)) { /* " int i = {12};" */ if (ISCOMMA(ex)) { /* " int i = {12};" */
if (IVAL(tpp, expr->OP_LEFT) != 0) if (IVAL(tpp, ex->OP_LEFT) != 0)
too_many_initialisers(expr); too_many_initialisers(ex);
/* return remainings of the list for the /* return remainings of the list for the
other members of the aggregate, if this other members of the aggregate, if this
item belongs to an aggregate. item belongs to an aggregate.
*/ */
return expr->OP_RIGHT; return ex->OP_RIGHT;
} }
/* "int i = 12;" */ /* "int i = 12;" */
check_ival(expr, tp); check_ival(ex, tp);
break; break;
} }
return 0; return 0;
@ -115,14 +115,14 @@ IVAL(tpp, expr)
members are padded with zeroes members are padded with zeroes
*/ */
struct expr * struct expr *
do_array(expr, tpp) do_array(ex, tpp)
struct expr *expr; struct expr *ex;
struct type **tpp; struct type **tpp;
{ {
register struct type *tp = *tpp; register struct type *tp = *tpp;
register arith elem_count; register arith elem_count;
ASSERT(tp->tp_fund == ARRAY && ISCOMMA(expr)); ASSERT(tp->tp_fund == ARRAY && ISCOMMA(ex));
/* the following test catches initialisations like /* the following test catches initialisations like
char c[] = {"just a string"}; char c[] = {"just a string"};
or or
@ -132,7 +132,7 @@ do_array(expr, tpp)
is completely foolish, we did it!! (no applause, thank you) is completely foolish, we did it!! (no applause, thank you)
*/ */
if (tp->tp_up->tp_fund == CHAR) { if (tp->tp_up->tp_fund == CHAR) {
register struct expr *f = expr->OP_LEFT; register struct expr *f = ex->OP_LEFT;
register struct expr *g = 0; register struct expr *g = 0;
while (ISCOMMA(f)) { /* eat the brackets!!! */ while (ISCOMMA(f)) { /* eat the brackets!!! */
@ -141,28 +141,28 @@ do_array(expr, tpp)
} }
if (f->ex_class == String) { /* hallelujah, it's a string! */ if (f->ex_class == String) { /* hallelujah, it's a string! */
init_string(tpp, f); init_string(tpp, f);
return g ? g->OP_RIGHT : expr->OP_RIGHT; return g ? g->OP_RIGHT : ex->OP_RIGHT;
} }
/* else: just go on with the next part of this function */ /* else: just go on with the next part of this function */
if (g != 0) if (g != 0)
expr = g; ex = g;
} }
if (tp->tp_size == (arith)-1) { if (tp->tp_size == (arith)-1) {
/* declared with unknown size: [] */ /* declared with unknown size: [] */
for (elem_count = 0; expr; elem_count++) { for (elem_count = 0; ex; elem_count++) {
/* eat whole initialisation expression */ /* eat whole initialisation expression */
if (ISCOMMA(expr->OP_LEFT)) { if (ISCOMMA(ex->OP_LEFT)) {
/* the member expression is embraced */ /* the member expression is embraced */
if (IVAL(&(tp->tp_up), expr->OP_LEFT) != 0) if (IVAL(&(tp->tp_up), ex->OP_LEFT) != 0)
too_many_initialisers(expr); too_many_initialisers(ex);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
else { else {
if (aggregate_type(tp->tp_up)) if (aggregate_type(tp->tp_up))
expr = IVAL(&(tp->tp_up), expr); ex = IVAL(&(tp->tp_up), ex);
else { else {
check_ival(expr->OP_LEFT, tp->tp_up); check_ival(ex->OP_LEFT, tp->tp_up);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
} }
} }
@ -172,30 +172,30 @@ do_array(expr, tpp)
else { /* the number of members is already known */ else { /* the number of members is already known */
arith dim = tp->tp_size / tp->tp_up->tp_size; arith dim = tp->tp_size / tp->tp_up->tp_size;
for (elem_count = 0; elem_count < dim && expr; elem_count++) { for (elem_count = 0; elem_count < dim && ex; elem_count++) {
if (ISCOMMA(expr->OP_LEFT)) { if (ISCOMMA(ex->OP_LEFT)) {
/* embraced member initialisation */ /* embraced member initialisation */
if (IVAL(&(tp->tp_up), expr->OP_LEFT) != 0) if (IVAL(&(tp->tp_up), ex->OP_LEFT) != 0)
too_many_initialisers(expr); too_many_initialisers(ex);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
else { else {
if (aggregate_type(tp->tp_up)) if (aggregate_type(tp->tp_up))
/* the member is an aggregate */ /* the member is an aggregate */
expr = IVAL(&(tp->tp_up), expr); ex = IVAL(&(tp->tp_up), ex);
else { else {
check_ival(expr->OP_LEFT, tp->tp_up); check_ival(ex->OP_LEFT, tp->tp_up);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
} }
} }
if (expr && elem_count == dim) if (ex && elem_count == dim)
/* all the members are initialised but there /* all the members are initialised but there
remains a part of the expression tree which remains a part of the expression tree which
is returned is returned
*/ */
return expr; return ex;
if ((expr == 0) && elem_count < dim) { if ((ex == 0) && elem_count < dim) {
/* the expression tree is completely absorbed /* the expression tree is completely absorbed
but there are still members which must be but there are still members which must be
initialised with zeroes initialised with zeroes
@ -214,31 +214,31 @@ do_array(expr, tpp)
during which alignment is taken care of. during which alignment is taken care of.
*/ */
struct expr * struct expr *
do_struct(expr, tp) do_struct(ex, tp)
struct expr *expr; struct expr *ex;
struct type *tp; struct type *tp;
{ {
struct sdef *sd = tp->tp_sdef; struct sdef *sd = tp->tp_sdef;
arith bytes_upto_here = (arith)0; arith bytes_upto_here = (arith)0;
arith last_offset = (arith)-1; arith last_offset = (arith)-1;
ASSERT(tp->tp_fund == STRUCT && ISCOMMA(expr)); ASSERT(tp->tp_fund == STRUCT && ISCOMMA(ex));
/* as long as there are selectors and there is an initialiser.. */ /* as long as there are selectors and there is an initialiser.. */
while (sd && expr) { while (sd && ex) {
if (ISCOMMA(expr->OP_LEFT)) { /* embraced expression */ if (ISCOMMA(ex->OP_LEFT)) { /* embraced expression */
if (IVAL(&(sd->sd_type), expr->OP_LEFT) != 0) if (IVAL(&(sd->sd_type), ex->OP_LEFT) != 0)
too_many_initialisers(expr); too_many_initialisers(ex);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
else { else {
if (aggregate_type(sd->sd_type)) if (aggregate_type(sd->sd_type))
/* selector is an aggregate itself */ /* selector is an aggregate itself */
expr = IVAL(&(sd->sd_type), expr); ex = IVAL(&(sd->sd_type), ex);
else { else {
#ifdef NOBITFIELD #ifdef NOBITFIELD
/* fundamental type, not embraced */ /* fundamental type, not embraced */
check_ival(expr->OP_LEFT, sd->sd_type); check_ival(ex->OP_LEFT, sd->sd_type);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
#else #else
if (is_anon_idf(sd->sd_idf)) if (is_anon_idf(sd->sd_idf))
/* a hole in the struct due to /* a hole in the struct due to
@ -248,9 +248,9 @@ do_struct(expr, tp)
put_bf(sd->sd_type, (arith)0); put_bf(sd->sd_type, (arith)0);
else { else {
/* fundamental type, not embraced */ /* fundamental type, not embraced */
check_ival(expr->OP_LEFT, check_ival(ex->OP_LEFT,
sd->sd_type); sd->sd_type);
expr = expr->OP_RIGHT; ex = ex->OP_RIGHT;
} }
#endif NOBITFIELD #endif NOBITFIELD
} }
@ -266,8 +266,8 @@ do_struct(expr, tp)
} }
sd = sd->sd_sdef; sd = sd->sd_sdef;
} }
/* perfect fit if (expr && (sd == 0)) holds */ /* perfect fit if (ex && (sd == 0)) holds */
if ((expr == 0) && (sd != 0)) { if ((ex == 0) && (sd != 0)) {
/* there are selectors left which must be padded with /* there are selectors left which must be padded with
zeroes zeroes
*/ */
@ -284,7 +284,7 @@ do_struct(expr, tp)
/* keep on aligning... */ /* keep on aligning... */
while (bytes_upto_here++ < tp->tp_size) while (bytes_upto_here++ < tp->tp_size)
con_nullbyte(); con_nullbyte();
return expr; return ex;
} }
/* check_and_pad() is given a simple initialisation expression /* check_and_pad() is given a simple initialisation expression
@ -292,17 +292,17 @@ do_struct(expr, tp)
In the latter case, only the first member is initialised and In the latter case, only the first member is initialised and
the rest is zeroed. the rest is zeroed.
*/ */
check_and_pad(expr, tpp) check_and_pad(ex, tpp)
struct expr *expr; struct expr *ex;
struct type **tpp; struct type **tpp;
{ {
/* expr is of a fundamental type */ /* ex is of a fundamental type */
struct type *tp = *tpp; struct type *tp = *tpp;
if (tp->tp_fund == ARRAY) { if (tp->tp_fund == ARRAY) {
if (valid_type(tp->tp_up, "array element") == 0) if (valid_type(tp->tp_up, "array element") == 0)
return; return;
check_and_pad(expr, &(tp->tp_up)); /* first member */ check_and_pad(ex, &(tp->tp_up)); /* first member */
if (tp->tp_size == (arith)-1) if (tp->tp_size == (arith)-1)
/* no size specified upto here: just /* no size specified upto here: just
set it to the size of one member. set it to the size of one member.
@ -321,7 +321,7 @@ check_and_pad(expr, tpp)
if (valid_type(tp, "struct") == 0) if (valid_type(tp, "struct") == 0)
return; return;
check_and_pad(expr, &(sd->sd_type)); check_and_pad(ex, &(sd->sd_type));
/* Next selector is aligned by adding extra zeroes */ /* Next selector is aligned by adding extra zeroes */
if (sd->sd_sdef) if (sd->sd_sdef)
zero_bytes(sd); zero_bytes(sd);
@ -332,7 +332,7 @@ check_and_pad(expr, tpp)
} }
} }
else /* simple type */ else /* simple type */
check_ival(expr, tp); check_ival(ex, tp);
} }
/* pad() fills an element of type tp with zeroes. /* pad() fills an element of type tp with zeroes.
@ -404,9 +404,9 @@ pad(tp)
No further comment is needed to explain the internal structure No further comment is needed to explain the internal structure
of this straightforward function. of this straightforward function.
*/ */
check_ival(expr, type) check_ival(ex, tp)
struct expr *expr; struct expr *ex;
struct type *type; struct type *tp;
{ {
/* The philosophy here is that ch7cast puts an explicit /* The philosophy here is that ch7cast puts an explicit
conversion node in front of the expression if the types conversion node in front of the expression if the types
@ -414,88 +414,81 @@ check_ival(expr, type)
expression is no longer a constant. expression is no longer a constant.
*/ */
switch (type->tp_fund) { switch (tp->tp_fund) {
case CHAR: case CHAR:
case SHORT: case SHORT:
case INT: case INT:
case LONG: case LONG:
case ENUM: case ENUM:
ch7cast(&expr, '=', type); case POINTER:
if (is_cp_cst(expr)) ch7cast(&ex, '=', tp);
con_int(expr); #ifdef DEBUG
print_expr("init-expr after cast", ex);
#endif DEBUG
if (!is_ld_cst(ex))
illegal_init_cst(ex);
else else
illegal_init_cst(expr); if (ex->VL_CLASS == Const)
break; con_int(ex);
#ifndef NOBITFIELD
case FIELD:
ch7cast(&expr, '=', type->tp_up);
if (is_cp_cst(expr))
put_bf(type, expr->VL_VALUE);
else else
illegal_init_cst(expr); if (ex->VL_CLASS == Name) {
register struct idf *id = ex->VL_IDF;
register struct def *df = id->id_def;
if (df->df_level >= L_LOCAL)
illegal_init_cst(ex);
else /* e.g., int f(); int p = f; */
if (df->df_type->tp_fund == FUNCTION)
C_con_pnam(id->id_text);
else /* e.g., int a; int *p = &a; */
C_con_dnam(id->id_text, ex->VL_VALUE);
}
else {
ASSERT(ex->VL_CLASS == Label);
C_con_dlb(ex->VL_LBL, ex->VL_VALUE);
}
break; break;
#endif NOBITFIELD
case FLOAT: case FLOAT:
case DOUBLE: case DOUBLE:
ch7cast(&expr, '=', type); ch7cast(&ex, '=', tp);
if (expr->ex_class == Float) #ifdef DEBUG
C_con_fcon(expr->FL_VALUE, expr->ex_type->tp_size); print_expr("init-expr after cast", ex);
#endif DEBUG
if (ex->ex_class == Float)
C_con_fcon(ex->FL_VALUE, ex->ex_type->tp_size);
else else
if (expr->ex_class == Oper && expr->OP_OPER == INT2FLOAT) { if (ex->ex_class == Oper && ex->OP_OPER == INT2FLOAT) {
expr = expr->OP_RIGHT; /* float f = 1; */
if (is_cp_cst(expr)) ex = ex->OP_RIGHT;
if (is_cp_cst(ex))
C_con_fcon( C_con_fcon(
long2str((long)expr->VL_VALUE, 10), long2str((long)ex->VL_VALUE, 10),
type->tp_size tp->tp_size
); );
else else
illegal_init_cst(expr); illegal_init_cst(ex);
} }
else else
illegal_init_cst(expr); illegal_init_cst(ex);
break; break;
case POINTER:
ch7cast(&expr, '=', type);
switch (expr->ex_class) {
case Oper:
illegal_init_cst(expr);
break;
case Value:
{
ASSERT(expr->ex_type->tp_fund == POINTER);
if (expr->ex_type->tp_up->tp_fund == FUNCTION) {
if (expr->VL_CLASS == Name)
C_con_pnam(expr->VL_IDF->id_text);
else /* int (*func)() = 0 */
con_int(expr);
}
else
if (expr->VL_CLASS == Name) {
register struct idf *id = expr->VL_IDF;
if (id ->id_def->df_level >= L_LOCAL) #ifndef NOBITFIELD
expr_error(expr, case FIELD:
"illegal initialisation"); ch7cast(&ex, '=', tp->tp_up);
else #ifdef DEBUG
C_con_dnam(id->id_text, expr->VL_VALUE); print_expr("init-expr after cast", ex);
} #endif DEBUG
else if (is_cp_cst(ex))
if (expr->VL_CLASS == Label) put_bf(tp, ex->VL_VALUE);
C_con_dlb(expr->VL_LBL, expr->VL_VALUE); else
else illegal_init_cst(ex);
con_int(expr);
break;
}
case String:
default:
crash("(check_ival) illegal value class");
}
break; break;
#endif NOBITFIELD
case ERRONEOUS: case ERRONEOUS:
break; break;
default: default:
crash("(check_ival) bad fundamental type %s", crash("check_ival");
symbol2str(type->tp_fund));
} }
} }
@ -503,17 +496,17 @@ check_ival(expr, type)
a string constant. a string constant.
Alignment is taken care of. Alignment is taken care of.
*/ */
init_string(tpp, expr) init_string(tpp, ex)
struct type **tpp; /* type tp = array of characters */ struct type **tpp; /* type tp = array of characters */
struct expr *expr; struct expr *ex;
{ {
register struct type *tp = *tpp; register struct type *tp = *tpp;
register arith length; register arith length;
char *s = expr->SG_VALUE; char *s = ex->SG_VALUE;
arith ntopad; arith ntopad;
ASSERT(expr->ex_class == String); ASSERT(ex->ex_class == String);
length = expr->SG_LEN; length = ex->SG_LEN;
if (tp->tp_size == (arith)-1) { if (tp->tp_size == (arith)-1) {
/* set the dimension */ /* set the dimension */
tp = *tpp = construct_type(ARRAY, tp->tp_up, length); tp = *tpp = construct_type(ARRAY, tp->tp_up, length);
@ -524,7 +517,7 @@ init_string(tpp, expr)
ntopad = align(dim, word_align) - length; ntopad = align(dim, word_align) - length;
if (length > dim) if (length > dim)
expr_error(expr, expr_error(ex,
"too many characters in initialiser string"); "too many characters in initialiser string");
} }
/* throw out the characters of the already prepared string */ /* throw out the characters of the already prepared string */

View file

@ -1,5 +1,4 @@
User options: User options:
C while running preprocessor, copy comment C while running preprocessor, copy comment
D see identifier following as a macro D see identifier following as a macro
E run preprocessor only E run preprocessor only