Merge pull request #1220 from acqn/StaticConst
[cc65] Fixed constant boolean expressions
This commit is contained in:
@@ -129,14 +129,13 @@ static SymEntry* AsmGetSym (unsigned Arg, unsigned Type)
|
|||||||
static void ParseByteArg (StrBuf* T, unsigned Arg)
|
static void ParseByteArg (StrBuf* T, unsigned Arg)
|
||||||
/* Parse the %b format specifier */
|
/* Parse the %b format specifier */
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
char Buf [16];
|
char Buf [16];
|
||||||
|
|
||||||
/* We expect an argument separated by a comma */
|
/* We expect an argument separated by a comma */
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
/* Evaluate the expression */
|
/* Evaluate the expression */
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
|
|
||||||
/* Check the range but allow negative values if the type is signed */
|
/* Check the range but allow negative values if the type is signed */
|
||||||
if (IsSignUnsigned (Expr.Type)) {
|
if (IsSignUnsigned (Expr.Type)) {
|
||||||
@@ -163,14 +162,13 @@ static void ParseByteArg (StrBuf* T, unsigned Arg)
|
|||||||
static void ParseWordArg (StrBuf* T, unsigned Arg)
|
static void ParseWordArg (StrBuf* T, unsigned Arg)
|
||||||
/* Parse the %w format specifier */
|
/* Parse the %w format specifier */
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
char Buf [16];
|
char Buf [16];
|
||||||
|
|
||||||
/* We expect an argument separated by a comma */
|
/* We expect an argument separated by a comma */
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
/* Evaluate the expression */
|
/* Evaluate the expression */
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
|
|
||||||
/* Check the range but allow negative values if the type is signed */
|
/* Check the range but allow negative values if the type is signed */
|
||||||
if (IsSignUnsigned (Expr.Type)) {
|
if (IsSignUnsigned (Expr.Type)) {
|
||||||
@@ -197,14 +195,13 @@ static void ParseWordArg (StrBuf* T, unsigned Arg)
|
|||||||
static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused)))
|
static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused)))
|
||||||
/* Parse the %l format specifier */
|
/* Parse the %l format specifier */
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
char Buf [16];
|
char Buf [16];
|
||||||
|
|
||||||
/* We expect an argument separated by a comma */
|
/* We expect an argument separated by a comma */
|
||||||
ConsumeComma ();
|
ConsumeComma ();
|
||||||
|
|
||||||
/* Evaluate the expression */
|
/* Evaluate the expression */
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
|
|
||||||
/* Convert into a hex number */
|
/* Convert into a hex number */
|
||||||
xsprintf (Buf, sizeof (Buf), "$%08lX", Expr.IVal & 0xFFFFFFFF);
|
xsprintf (Buf, sizeof (Buf), "$%08lX", Expr.IVal & 0xFFFFFFFF);
|
||||||
@@ -328,7 +325,7 @@ static void ParseStrArg (StrBuf* T, unsigned Arg attribute ((unused)))
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
xsprintf (Buf, sizeof (Buf), "%ld", Expr.IVal);
|
xsprintf (Buf, sizeof (Buf), "%ld", Expr.IVal);
|
||||||
SB_AppendStr (T, Buf);
|
SB_AppendStr (T, Buf);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ void Assignment (ExprDesc* Expr)
|
|||||||
ExprDesc Expr2;
|
ExprDesc Expr2;
|
||||||
Type* ltype = Expr->Type;
|
Type* ltype = Expr->Type;
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
|
||||||
/* We must have an lvalue for an assignment */
|
/* We must have an lvalue for an assignment */
|
||||||
if (ED_IsRVal (Expr)) {
|
if (ED_IsRVal (Expr)) {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ Type type_int[] = { TYPE(T_INT), TYPE(T_END) };
|
|||||||
Type type_uint[] = { TYPE(T_UINT), TYPE(T_END) };
|
Type type_uint[] = { TYPE(T_UINT), TYPE(T_END) };
|
||||||
Type type_long[] = { TYPE(T_LONG), TYPE(T_END) };
|
Type type_long[] = { TYPE(T_LONG), TYPE(T_END) };
|
||||||
Type type_ulong[] = { TYPE(T_ULONG), TYPE(T_END) };
|
Type type_ulong[] = { TYPE(T_ULONG), TYPE(T_END) };
|
||||||
|
Type type_bool[] = { TYPE(T_INT), TYPE(T_END) };
|
||||||
Type type_void[] = { TYPE(T_VOID), TYPE(T_END) };
|
Type type_void[] = { TYPE(T_VOID), TYPE(T_END) };
|
||||||
Type type_size_t[] = { TYPE(T_SIZE_T), TYPE(T_END) };
|
Type type_size_t[] = { TYPE(T_SIZE_T), TYPE(T_END) };
|
||||||
Type type_float[] = { TYPE(T_FLOAT), TYPE(T_END) };
|
Type type_float[] = { TYPE(T_FLOAT), TYPE(T_END) };
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ extern Type type_int[];
|
|||||||
extern Type type_uint[];
|
extern Type type_uint[];
|
||||||
extern Type type_long[];
|
extern Type type_long[];
|
||||||
extern Type type_ulong[];
|
extern Type type_ulong[];
|
||||||
|
extern Type type_bool[];
|
||||||
extern Type type_void[];
|
extern Type type_void[];
|
||||||
extern Type type_size_t[];
|
extern Type type_size_t[];
|
||||||
extern Type type_float[];
|
extern Type type_float[];
|
||||||
|
|||||||
@@ -621,9 +621,8 @@ static SymEntry* ParseEnumDecl (const char* Name, unsigned* DSFlags)
|
|||||||
/* Check for an assigned value */
|
/* Check for an assigned value */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
ExprDesc Expr;
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
EnumVal = Expr.IVal;
|
EnumVal = Expr.IVal;
|
||||||
MemberType = Expr.Type;
|
MemberType = Expr.Type;
|
||||||
IsSigned = IsSignSigned (MemberType);
|
IsSigned = IsSignSigned (MemberType);
|
||||||
@@ -750,8 +749,6 @@ static int ParseFieldWidth (Declaration* Decl)
|
|||||||
** otherwise the width of the field.
|
** otherwise the width of the field.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
|
|
||||||
if (CurTok.Tok != TOK_COLON) {
|
if (CurTok.Tok != TOK_COLON) {
|
||||||
/* No bit-field declaration */
|
/* No bit-field declaration */
|
||||||
return -1;
|
return -1;
|
||||||
@@ -775,7 +772,7 @@ static int ParseFieldWidth (Declaration* Decl)
|
|||||||
|
|
||||||
/* Read the width */
|
/* Read the width */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
|
|
||||||
if (Expr.IVal < 0) {
|
if (Expr.IVal < 0) {
|
||||||
Error ("Negative width in bit-field");
|
Error ("Negative width in bit-field");
|
||||||
@@ -1894,8 +1891,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
|
|||||||
|
|
||||||
/* Read the size if it is given */
|
/* Read the size if it is given */
|
||||||
if (CurTok.Tok != TOK_RBRACK) {
|
if (CurTok.Tok != TOK_RBRACK) {
|
||||||
ExprDesc Expr;
|
ExprDesc Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
|
||||||
if (Expr.IVal <= 0) {
|
if (Expr.IVal <= 0) {
|
||||||
if (D->Ident[0] != '\0') {
|
if (D->Ident[0] != '\0') {
|
||||||
Error ("Size of array '%s' is invalid", D->Ident);
|
Error ("Size of array '%s' is invalid", D->Ident);
|
||||||
@@ -2240,7 +2236,7 @@ static void OutputBitFieldData (StructInitData* SI)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParseScalarInitInternal (Type* T, ExprDesc* ED)
|
static ExprDesc ParseScalarInitInternal (Type* T)
|
||||||
/* Parse initializaton for scalar data types. This function will not output the
|
/* Parse initializaton for scalar data types. This function will not output the
|
||||||
** data but return it in ED.
|
** data but return it in ED.
|
||||||
*/
|
*/
|
||||||
@@ -2256,11 +2252,13 @@ static void ParseScalarInitInternal (Type* T, ExprDesc* ED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the expression and convert it to the target type */
|
/* Get the expression and convert it to the target type */
|
||||||
ConstExpr (hie1, ED);
|
ExprDesc ED = NoCodeConstExpr (hie1);
|
||||||
TypeConversion (ED, T);
|
TypeConversion (&ED, T);
|
||||||
|
|
||||||
/* Close eventually opening braces */
|
/* Close eventually opening braces */
|
||||||
ClosingCurlyBraces (BraceCount);
|
ClosingCurlyBraces (BraceCount);
|
||||||
|
|
||||||
|
return ED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2268,10 +2266,8 @@ static void ParseScalarInitInternal (Type* T, ExprDesc* ED)
|
|||||||
static unsigned ParseScalarInit (Type* T)
|
static unsigned ParseScalarInit (Type* T)
|
||||||
/* Parse initializaton for scalar data types. Return the number of data bytes. */
|
/* Parse initializaton for scalar data types. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
ExprDesc ED;
|
|
||||||
|
|
||||||
/* Parse initialization */
|
/* Parse initialization */
|
||||||
ParseScalarInitInternal (T, &ED);
|
ExprDesc ED = ParseScalarInitInternal (T);
|
||||||
|
|
||||||
/* Output the data */
|
/* Output the data */
|
||||||
DefineData (&ED);
|
DefineData (&ED);
|
||||||
@@ -2289,8 +2285,7 @@ static unsigned ParsePointerInit (Type* T)
|
|||||||
unsigned BraceCount = OpeningCurlyBraces (0);
|
unsigned BraceCount = OpeningCurlyBraces (0);
|
||||||
|
|
||||||
/* Expression */
|
/* Expression */
|
||||||
ExprDesc ED;
|
ExprDesc ED = NoCodeConstExpr (hie1);
|
||||||
ConstExpr (hie1, &ED);
|
|
||||||
TypeConversion (&ED, T);
|
TypeConversion (&ED, T);
|
||||||
|
|
||||||
/* Output the data */
|
/* Output the data */
|
||||||
@@ -2516,6 +2511,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||||||
** handling.
|
** handling.
|
||||||
*/
|
*/
|
||||||
ExprDesc ED;
|
ExprDesc ED;
|
||||||
|
ED_Init (&ED);
|
||||||
unsigned Val;
|
unsigned Val;
|
||||||
unsigned Shift;
|
unsigned Shift;
|
||||||
|
|
||||||
@@ -2527,7 +2523,7 @@ static unsigned ParseStructInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
|||||||
SI.Offs * CHAR_BITS + SI.ValBits);
|
SI.Offs * CHAR_BITS + SI.ValBits);
|
||||||
|
|
||||||
/* Read the data, check for a constant integer, do a range check */
|
/* Read the data, check for a constant integer, do a range check */
|
||||||
ParseScalarInitInternal (Entry->Type, &ED);
|
ED = ParseScalarInitInternal (Entry->Type);
|
||||||
if (!ED_IsConstAbsInt (&ED)) {
|
if (!ED_IsConstAbsInt (&ED)) {
|
||||||
Error ("Constant initializer expected");
|
Error ("Constant initializer expected");
|
||||||
ED_MakeConstAbsInt (&ED, 1);
|
ED_MakeConstAbsInt (&ED, 1);
|
||||||
@@ -2637,7 +2633,6 @@ static unsigned ParseVoidInit (Type* T)
|
|||||||
** Return the number of bytes initialized.
|
** Return the number of bytes initialized.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
unsigned Size;
|
unsigned Size;
|
||||||
|
|
||||||
/* Opening brace */
|
/* Opening brace */
|
||||||
@@ -2646,7 +2641,7 @@ static unsigned ParseVoidInit (Type* T)
|
|||||||
/* Allow an arbitrary list of values */
|
/* Allow an arbitrary list of values */
|
||||||
Size = 0;
|
Size = 0;
|
||||||
do {
|
do {
|
||||||
ConstExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstExpr (hie1);
|
||||||
switch (GetUnderlyingTypeCode (&Expr.Type[0])) {
|
switch (GetUnderlyingTypeCode (&Expr.Type[0])) {
|
||||||
|
|
||||||
case T_SCHAR:
|
case T_SCHAR:
|
||||||
|
|||||||
483
src/cc65/expr.c
483
src/cc65/expr.c
@@ -311,13 +311,15 @@ void PushAddr (const ExprDesc* Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void WarnConstCompareResult (void)
|
static void WarnConstCompareResult (const ExprDesc* Expr)
|
||||||
/* If the result of a comparison is constant, this is suspicious when not in
|
/* If the result of a comparison is constant, this is suspicious when not in
|
||||||
** preprocessor mode.
|
** preprocessor mode.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
if (!Preprocessing && IS_Get (&WarnConstComparison) != 0) {
|
if (!Preprocessing &&
|
||||||
Warning ("Result of comparison is constant");
|
!ED_NeedsConst (Expr) &&
|
||||||
|
IS_Get (&WarnConstComparison) != 0) {
|
||||||
|
Warning ("Result of comparison is always %s", Expr->IVal != 0 ? "true" : "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +392,7 @@ static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
|
|||||||
|
|
||||||
unsigned Flags;
|
unsigned Flags;
|
||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Count arguments */
|
/* Count arguments */
|
||||||
++PushedCount;
|
++PushedCount;
|
||||||
@@ -733,13 +736,10 @@ static void Primary (ExprDesc* E)
|
|||||||
{
|
{
|
||||||
SymEntry* Sym;
|
SymEntry* Sym;
|
||||||
|
|
||||||
/* Initialize fields in the expression stucture */
|
|
||||||
ED_Init (E);
|
|
||||||
|
|
||||||
/* Character and integer constants. */
|
/* Character and integer constants. */
|
||||||
if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
|
if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
|
||||||
E->IVal = CurTok.IVal;
|
E->IVal = CurTok.IVal;
|
||||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
||||||
E->Type = CurTok.Type;
|
E->Type = CurTok.Type;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
return;
|
return;
|
||||||
@@ -748,7 +748,7 @@ static void Primary (ExprDesc* E)
|
|||||||
/* Floating point constant */
|
/* Floating point constant */
|
||||||
if (CurTok.Tok == TOK_FCONST) {
|
if (CurTok.Tok == TOK_FCONST) {
|
||||||
E->FVal = CurTok.FVal;
|
E->FVal = CurTok.FVal;
|
||||||
E->Flags = E_LOC_NONE | E_RTYPE_RVAL;
|
E->Flags |= E_LOC_NONE | E_RTYPE_RVAL;
|
||||||
E->Type = CurTok.Type;
|
E->Type = CurTok.Type;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
return;
|
return;
|
||||||
@@ -783,6 +783,8 @@ static void Primary (ExprDesc* E)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned Flags = E->Flags & E_MASK_KEEP_MAKE;
|
||||||
|
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
case TOK_BOOL_AND:
|
case TOK_BOOL_AND:
|
||||||
@@ -818,7 +820,7 @@ static void Primary (ExprDesc* E)
|
|||||||
/* Cannot use type symbols */
|
/* Cannot use type symbols */
|
||||||
Error ("Variable identifier expected");
|
Error ("Variable identifier expected");
|
||||||
/* Assume an int type to make E valid */
|
/* Assume an int type to make E valid */
|
||||||
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
E->Flags |= E_LOC_STACK | E_RTYPE_LVAL;
|
||||||
E->Type = type_int;
|
E->Type = type_int;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -930,7 +932,7 @@ static void Primary (ExprDesc* E)
|
|||||||
case TOK_ASM:
|
case TOK_ASM:
|
||||||
/* ASM statement */
|
/* ASM statement */
|
||||||
AsmStatement ();
|
AsmStatement ();
|
||||||
E->Flags = E_RTYPE_RVAL;
|
E->Flags = E_RTYPE_RVAL | E_EVAL_MAYBE_UNUSED;
|
||||||
E->Type = type_void;
|
E->Type = type_void;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1000,6 +1002,8 @@ static void Primary (ExprDesc* E)
|
|||||||
ED_MakeConstAbsInt (E, 1);
|
ED_MakeConstAbsInt (E, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
E->Flags |= Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1015,6 +1019,8 @@ static void ArrayRef (ExprDesc* Expr)
|
|||||||
Type* ElementType;
|
Type* ElementType;
|
||||||
Type* tptr1;
|
Type* tptr1;
|
||||||
|
|
||||||
|
ED_Init (&Subscript);
|
||||||
|
Subscript.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* Skip the bracket */
|
/* Skip the bracket */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
@@ -2047,7 +2053,6 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
|||||||
int* UsedGen)
|
int* UsedGen)
|
||||||
/* Helper function */
|
/* Helper function */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
|
||||||
CodeMark Mark1;
|
CodeMark Mark1;
|
||||||
CodeMark Mark2;
|
CodeMark Mark2;
|
||||||
const GenDesc* Gen;
|
const GenDesc* Gen;
|
||||||
@@ -2062,6 +2067,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
|||||||
*UsedGen = 0;
|
*UsedGen = 0;
|
||||||
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* Tell the caller that we handled it's ops */
|
/* Tell the caller that we handled it's ops */
|
||||||
*UsedGen = 1;
|
*UsedGen = 1;
|
||||||
|
|
||||||
@@ -2266,7 +2275,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
void (*hienext) (ExprDesc*))
|
void (*hienext) (ExprDesc*))
|
||||||
/* Helper function for the compare operators */
|
/* Helper function for the compare operators */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
|
||||||
CodeMark Mark0;
|
CodeMark Mark0;
|
||||||
CodeMark Mark1;
|
CodeMark Mark1;
|
||||||
CodeMark Mark2;
|
CodeMark Mark2;
|
||||||
@@ -2281,6 +2289,10 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
|
|
||||||
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* Remember the generator function */
|
/* Remember the generator function */
|
||||||
void (*GenFunc) (unsigned, unsigned long) = Gen->Func;
|
void (*GenFunc) (unsigned, unsigned long) = Gen->Func;
|
||||||
|
|
||||||
@@ -2380,11 +2392,6 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
/* Check for const operands */
|
/* Check for const operands */
|
||||||
if (ED_IsConstAbs (Expr) && rconst) {
|
if (ED_IsConstAbs (Expr) && rconst) {
|
||||||
|
|
||||||
/* If the result is constant, this is suspicious when not in
|
|
||||||
** preprocessor mode.
|
|
||||||
*/
|
|
||||||
WarnConstCompareResult ();
|
|
||||||
|
|
||||||
/* Both operands are constant, remove the generated code */
|
/* Both operands are constant, remove the generated code */
|
||||||
RemoveCode (&Mark1);
|
RemoveCode (&Mark1);
|
||||||
|
|
||||||
@@ -2421,6 +2428,11 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the result is constant, this is suspicious when not in
|
||||||
|
** preprocessor mode.
|
||||||
|
*/
|
||||||
|
WarnConstCompareResult (Expr);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Determine the signedness of the operands */
|
/* Determine the signedness of the operands */
|
||||||
@@ -2479,7 +2491,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_EQ:
|
case TOK_EQ:
|
||||||
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, 0);
|
ED_MakeConstAbsInt (Expr, 0);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2487,7 +2499,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_NE:
|
case TOK_NE:
|
||||||
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, 1);
|
ED_MakeConstAbsInt (Expr, 1);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2495,7 +2507,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_LT:
|
case TOK_LT:
|
||||||
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
|
ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2503,7 +2515,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_LE:
|
case TOK_LE:
|
||||||
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
|
ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2511,7 +2523,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_GE:
|
case TOK_GE:
|
||||||
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
|
ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2519,7 +2531,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
case TOK_GT:
|
case TOK_GT:
|
||||||
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
|
||||||
ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
|
ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
|
||||||
WarnConstCompareResult ();
|
WarnConstCompareResult (Expr);
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2613,13 +2625,13 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
|
|
||||||
/* The result is an rvalue in the primary */
|
/* The result is an rvalue in the primary */
|
||||||
ED_FinalizeRValLoad (Expr);
|
ED_FinalizeRValLoad (Expr);
|
||||||
|
|
||||||
|
/* Condition codes are set */
|
||||||
|
ED_TestDone (Expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Result type is always int */
|
/* Result type is always boolean */
|
||||||
Expr->Type = type_int;
|
Done: Expr->Type = type_bool;
|
||||||
|
|
||||||
Done: /* Condition codes are set */
|
|
||||||
ED_TestDone (Expr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2653,6 +2665,9 @@ static void parseadd (ExprDesc* Expr)
|
|||||||
Type* lhst; /* Type of left hand side */
|
Type* lhst; /* Type of left hand side */
|
||||||
Type* rhst; /* Type of right hand side */
|
Type* rhst; /* Type of right hand side */
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* Skip the PLUS token */
|
/* Skip the PLUS token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -2887,6 +2902,8 @@ static void parsesub (ExprDesc* Expr)
|
|||||||
CodeMark Mark2; /* Another position in the queue */
|
CodeMark Mark2; /* Another position in the queue */
|
||||||
int rscale; /* Scale factor for the result */
|
int rscale; /* Scale factor for the result */
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* lhs cannot be function or pointer to function */
|
/* lhs cannot be function or pointer to function */
|
||||||
if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
|
if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
|
||||||
@@ -3148,16 +3165,14 @@ static void hieAndPP (ExprDesc* Expr)
|
|||||||
** called recursively from the preprocessor.
|
** called recursively from the preprocessor.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
*Expr = NoCodeConstAbsIntExpr (hie2);
|
||||||
|
|
||||||
ConstAbsIntExpr (hie2, Expr);
|
|
||||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
/* Skip the && */
|
/* Skip the && */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get rhs */
|
/* Get rhs */
|
||||||
ConstAbsIntExpr (hie2, &Expr2);
|
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hie2);
|
||||||
|
|
||||||
/* Combine the two */
|
/* Combine the two */
|
||||||
Expr->IVal = (Expr->IVal && Expr2.IVal);
|
Expr->IVal = (Expr->IVal && Expr2.IVal);
|
||||||
@@ -3171,16 +3186,14 @@ static void hieOrPP (ExprDesc *Expr)
|
|||||||
** called recursively from the preprocessor.
|
** called recursively from the preprocessor.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
*Expr = NoCodeConstAbsIntExpr (hieAndPP);
|
||||||
|
|
||||||
ConstAbsIntExpr (hieAndPP, Expr);
|
|
||||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
/* Skip the && */
|
/* Skip the && */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get rhs */
|
/* Get rhs */
|
||||||
ConstAbsIntExpr (hieAndPP, &Expr2);
|
ExprDesc Expr2 = NoCodeConstAbsIntExpr (hieAndPP);
|
||||||
|
|
||||||
/* Combine the two */
|
/* Combine the two */
|
||||||
Expr->IVal = (Expr->IVal || Expr2.IVal);
|
Expr->IVal = (Expr->IVal || Expr2.IVal);
|
||||||
@@ -3189,133 +3202,261 @@ static void hieOrPP (ExprDesc *Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp)
|
static int hieAnd (ExprDesc* Expr, unsigned* TrueLab, int* TrueLabAllocated)
|
||||||
/* Process "exp && exp" */
|
/* Process "exp && exp". This should only be called within hieOr.
|
||||||
|
** Return true if logic AND does occur.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
int FalseLab;
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
ExprDesc Expr2;
|
int HasFalseJump = 0, HasTrueJump = 0;
|
||||||
|
CodeMark Start;
|
||||||
ExprWithCheck (hie2, Expr);
|
|
||||||
if (CurTok.Tok == TOK_BOOL_AND) {
|
|
||||||
|
|
||||||
/* Tell our caller that we're evaluating a boolean */
|
|
||||||
*BoolOp = 1;
|
|
||||||
|
|
||||||
/* Get a label that we will use for false expressions */
|
/* Get a label that we will use for false expressions */
|
||||||
FalseLab = GetLocalLabel ();
|
int FalseLab = GetLocalLabel ();
|
||||||
|
|
||||||
/* If the expr hasn't set condition codes, set the force-test flag */
|
/* Get lhs */
|
||||||
if (!ED_IsTested (Expr)) {
|
GetCodePos (&Start);
|
||||||
ED_MarkForTest (Expr);
|
ExprWithCheck (hie2, Expr);
|
||||||
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
|
RemoveCode (&Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
|
||||||
|
/* Check type */
|
||||||
|
if (!ED_IsBool (Expr)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
if (!ED_IsConstAbs (Expr)) {
|
||||||
|
/* Set the test flag */
|
||||||
|
ED_RequireTest (Expr);
|
||||||
|
|
||||||
/* Load the value */
|
/* Load the value */
|
||||||
LoadExpr (CF_FORCECHAR, Expr);
|
LoadExpr (CF_FORCECHAR, Expr);
|
||||||
|
|
||||||
|
/* Remember that the jump is used */
|
||||||
|
HasFalseJump = 1;
|
||||||
|
|
||||||
/* Generate the jump */
|
/* Generate the jump */
|
||||||
g_falsejump (CF_NONE, FalseLab);
|
g_falsejump (CF_NONE, FalseLab);
|
||||||
|
} else if (Expr->IVal == 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse more boolean and's */
|
/* Parse more boolean and's */
|
||||||
while (CurTok.Tok == TOK_BOOL_AND) {
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags = Flags;
|
||||||
|
|
||||||
/* Skip the && */
|
/* Skip the && */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get rhs */
|
/* Get rhs */
|
||||||
|
GetCodePos (&Start);
|
||||||
hie2 (&Expr2);
|
hie2 (&Expr2);
|
||||||
if (!ED_IsTested (&Expr2)) {
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
ED_MarkForTest (&Expr2);
|
RemoveCode (&Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check type */
|
||||||
|
if (!ED_IsBool (&Expr2)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (&Expr2, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
ED_RequireTest (&Expr2);
|
||||||
LoadExpr (CF_FORCECHAR, &Expr2);
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
||||||
|
|
||||||
/* Do short circuit evaluation */
|
/* Do short circuit evaluation */
|
||||||
if (CurTok.Tok == TOK_BOOL_AND) {
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
||||||
|
HasFalseJump = 1;
|
||||||
g_falsejump (CF_NONE, FalseLab);
|
g_falsejump (CF_NONE, FalseLab);
|
||||||
} else {
|
} else {
|
||||||
/* Last expression - will evaluate to true */
|
/* We need the true label for the last expression */
|
||||||
g_truejump (CF_NONE, TrueLab);
|
HasTrueJump = 1;
|
||||||
|
}
|
||||||
|
} else if (Expr2.IVal == 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
/* The value of the expression will be false */
|
||||||
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Define the false jump label here */
|
/* Last expression */
|
||||||
g_defcodelabel (FalseLab);
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
if (HasFalseJump || HasTrueJump) {
|
||||||
|
if (*TrueLabAllocated == 0) {
|
||||||
|
/* Get a label that we will use for true expressions */
|
||||||
|
*TrueLab = GetLocalLabel ();
|
||||||
|
*TrueLabAllocated = 1;
|
||||||
|
}
|
||||||
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
/* Will branch to true and fall to false */
|
||||||
|
g_truejump (CF_NONE, *TrueLab);
|
||||||
|
} else {
|
||||||
|
/* Will jump away */
|
||||||
|
g_jump (*TrueLab);
|
||||||
|
}
|
||||||
/* The result is an rvalue in primary */
|
/* The result is an rvalue in primary */
|
||||||
ED_FinalizeRValLoad (Expr);
|
ED_FinalizeRValLoad (Expr);
|
||||||
ED_TestDone (Expr); /* Condition codes are set */
|
/* No need to test as the result will be jumped to */
|
||||||
|
ED_TestDone (Expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasFalseJump) {
|
||||||
|
/* Define the false jump label here */
|
||||||
|
g_defcodelabel (FalseLab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to bool */
|
||||||
|
if (ED_IsConstAbs (Expr) && Expr->IVal != 0) {
|
||||||
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
} else {
|
||||||
|
Expr->Type = type_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell our caller that we're evaluating a boolean */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void hieOr (ExprDesc *Expr)
|
static void hieOr (ExprDesc *Expr)
|
||||||
/* Process "exp || exp". */
|
/* Process "exp || exp". */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
int BoolOp = 0; /* Did we have a boolean op? */
|
|
||||||
int AndOp; /* Did we have a && operation? */
|
int AndOp; /* Did we have a && operation? */
|
||||||
unsigned TrueLab; /* Jump to this label if true */
|
unsigned TrueLab; /* Jump to this label if true */
|
||||||
unsigned DoneLab;
|
unsigned DoneLab;
|
||||||
|
int HasTrueJump = 0;
|
||||||
/* Get a label */
|
CodeMark Start;
|
||||||
TrueLab = GetLocalLabel ();
|
|
||||||
|
|
||||||
/* Call the next level parser */
|
/* Call the next level parser */
|
||||||
hieAnd (Expr, TrueLab, &BoolOp);
|
GetCodePos (&Start);
|
||||||
|
AndOp = hieAnd (Expr, &TrueLab, &HasTrueJump);
|
||||||
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
|
RemoveCode (&Start);
|
||||||
|
}
|
||||||
|
|
||||||
/* Any boolean or's? */
|
/* Any boolean or's? */
|
||||||
if (CurTok.Tok == TOK_BOOL_OR) {
|
if (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
/* If the expr hasn't set condition codes, set the force-test flag */
|
/* Check type */
|
||||||
if (!ED_IsTested (Expr)) {
|
if (!ED_IsBool (Expr)) {
|
||||||
ED_MarkForTest (Expr);
|
Error ("Scalar expression expected");
|
||||||
}
|
ED_MakeConstBool (Expr, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
|
||||||
|
if (!ED_IsConstAbs (Expr)) {
|
||||||
|
/* Test the lhs if we haven't had && operators. If we had them, the
|
||||||
|
** jump is already in place and there's no need to do the test.
|
||||||
|
*/
|
||||||
|
if (!AndOp) {
|
||||||
|
/* Set the test flag */
|
||||||
|
ED_RequireTest (Expr);
|
||||||
|
|
||||||
/* Get first expr */
|
/* Get first expr */
|
||||||
LoadExpr (CF_FORCECHAR, Expr);
|
LoadExpr (CF_FORCECHAR, Expr);
|
||||||
|
|
||||||
/* For each expression jump to TrueLab if true. Beware: If we
|
if (HasTrueJump == 0) {
|
||||||
** had && operators, the jump is already in place!
|
/* Get a label that we will use for true expressions */
|
||||||
*/
|
TrueLab = GetLocalLabel();
|
||||||
if (!BoolOp) {
|
HasTrueJump = 1;
|
||||||
g_truejump (CF_NONE, TrueLab);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember that we had a boolean op */
|
/* Jump to TrueLab if true */
|
||||||
BoolOp = 1;
|
g_truejump (CF_NONE, TrueLab);
|
||||||
|
}
|
||||||
|
} else if (Expr->IVal != 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* while there's more expr */
|
/* while there's more expr */
|
||||||
while (CurTok.Tok == TOK_BOOL_OR) {
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags = Flags;
|
||||||
|
|
||||||
/* skip the || */
|
/* skip the || */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get a subexpr */
|
/* Get rhs subexpression */
|
||||||
AndOp = 0;
|
GetCodePos (&Start);
|
||||||
hieAnd (&Expr2, TrueLab, &AndOp);
|
AndOp = hieAnd (&Expr2, &TrueLab, &HasTrueJump);
|
||||||
if (!ED_IsTested (&Expr2)) {
|
if ((Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL) {
|
||||||
ED_MarkForTest (&Expr2);
|
RemoveCode (&Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check type */
|
||||||
|
if (!ED_IsBool (&Expr2)) {
|
||||||
|
Error ("Scalar expression expected");
|
||||||
|
ED_MakeConstBool (&Expr2, 0);
|
||||||
|
} else if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
|
||||||
|
if (!ED_IsConstAbs (&Expr2)) {
|
||||||
|
/* If there is more to come, add shortcut boolean eval */
|
||||||
|
if (!AndOp) {
|
||||||
|
ED_RequireTest (&Expr2);
|
||||||
LoadExpr (CF_FORCECHAR, &Expr2);
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
||||||
|
|
||||||
/* If there is more to come, add shortcut boolean eval. */
|
if (HasTrueJump == 0) {
|
||||||
|
TrueLab = GetLocalLabel();
|
||||||
|
HasTrueJump = 1;
|
||||||
|
}
|
||||||
g_truejump (CF_NONE, TrueLab);
|
g_truejump (CF_NONE, TrueLab);
|
||||||
|
}
|
||||||
|
} else if (Expr2.IVal != 0) {
|
||||||
|
/* Skip remaining */
|
||||||
|
Flags |= E_EVAL_UNEVAL;
|
||||||
|
/* The result is always true */
|
||||||
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The result is an rvalue in primary */
|
/* Convert to bool */
|
||||||
ED_FinalizeRValLoad (Expr);
|
if (ED_IsConstAbs (Expr) && Expr->IVal != 0) {
|
||||||
ED_TestDone (Expr); /* Condition codes are set */
|
ED_MakeConstBool (Expr, 1);
|
||||||
|
} else {
|
||||||
|
Expr->Type = type_bool;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we really had boolean ops, generate the end sequence */
|
/* If we really had boolean ops, generate the end sequence if necessary */
|
||||||
if (BoolOp) {
|
if (HasTrueJump) {
|
||||||
|
/* False case needs to jump over true case */
|
||||||
DoneLab = GetLocalLabel ();
|
DoneLab = GetLocalLabel ();
|
||||||
|
if ((Flags & E_EVAL_UNEVAL) != E_EVAL_UNEVAL) {
|
||||||
|
/* Load false only if the result is not true */
|
||||||
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
|
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
|
||||||
g_falsejump (CF_NONE, DoneLab);
|
g_falsejump (CF_NONE, DoneLab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the true value */
|
||||||
g_defcodelabel (TrueLab);
|
g_defcodelabel (TrueLab);
|
||||||
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
|
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
|
||||||
g_defcodelabel (DoneLab);
|
g_defcodelabel (DoneLab);
|
||||||
|
|
||||||
|
/* The result is an rvalue in primary */
|
||||||
|
ED_FinalizeRValLoad (Expr);
|
||||||
|
/* Condition codes are set */
|
||||||
|
ED_TestDone (Expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3326,6 +3467,7 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
{
|
{
|
||||||
int FalseLab;
|
int FalseLab;
|
||||||
int TrueLab;
|
int TrueLab;
|
||||||
|
CodeMark SkippedBranch;
|
||||||
CodeMark TrueCodeEnd;
|
CodeMark TrueCodeEnd;
|
||||||
ExprDesc Expr2; /* Expression 2 */
|
ExprDesc Expr2; /* Expression 2 */
|
||||||
ExprDesc Expr3; /* Expression 3 */
|
ExprDesc Expr3; /* Expression 3 */
|
||||||
@@ -3333,7 +3475,6 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
int Expr3IsNULL; /* Expression 3 is a NULL pointer */
|
int Expr3IsNULL; /* Expression 3 is a NULL pointer */
|
||||||
Type* ResultType; /* Type of result */
|
Type* ResultType; /* Type of result */
|
||||||
|
|
||||||
|
|
||||||
/* Call the lower level eval routine */
|
/* Call the lower level eval routine */
|
||||||
if (Preprocessing) {
|
if (Preprocessing) {
|
||||||
ExprWithCheck (hieOrPP, Expr);
|
ExprWithCheck (hieOrPP, Expr);
|
||||||
@@ -3343,14 +3484,27 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
|
|
||||||
/* Check if it's a ternary expression */
|
/* Check if it's a ternary expression */
|
||||||
if (CurTok.Tok == TOK_QUEST) {
|
if (CurTok.Tok == TOK_QUEST) {
|
||||||
|
|
||||||
|
int ConstantCond = ED_IsConstAbsInt (Expr);
|
||||||
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_RESULT;
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags = Flags;
|
||||||
|
ED_Init (&Expr3);
|
||||||
|
Expr3.Flags = Flags;
|
||||||
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (!ED_IsTested (Expr)) {
|
|
||||||
|
if (!ConstantCond) {
|
||||||
/* Condition codes not set, request a test */
|
/* Condition codes not set, request a test */
|
||||||
ED_MarkForTest (Expr);
|
ED_RequireTest (Expr);
|
||||||
}
|
|
||||||
LoadExpr (CF_NONE, Expr);
|
LoadExpr (CF_NONE, Expr);
|
||||||
FalseLab = GetLocalLabel ();
|
FalseLab = GetLocalLabel ();
|
||||||
g_falsejump (CF_NONE, FalseLab);
|
g_falsejump (CF_NONE, FalseLab);
|
||||||
|
} else if (Expr->IVal == 0) {
|
||||||
|
/* Remember the current code position */
|
||||||
|
GetCodePos (&SkippedBranch);
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse second expression. Remember for later if it is a NULL pointer
|
/* Parse second expression. Remember for later if it is a NULL pointer
|
||||||
** expression, then load it into the primary.
|
** expression, then load it into the primary.
|
||||||
@@ -3358,22 +3512,37 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
ExprWithCheck (hie1, &Expr2);
|
ExprWithCheck (hie1, &Expr2);
|
||||||
Expr2IsNULL = ED_IsNullPtr (&Expr2);
|
Expr2IsNULL = ED_IsNullPtr (&Expr2);
|
||||||
if (!IsTypeVoid (Expr2.Type)) {
|
if (!IsTypeVoid (Expr2.Type)) {
|
||||||
|
if (!ConstantCond || !ED_IsConst (&Expr2)) {
|
||||||
/* Load it into the primary */
|
/* Load it into the primary */
|
||||||
LoadExpr (CF_NONE, &Expr2);
|
LoadExpr (CF_NONE, &Expr2);
|
||||||
ED_FinalizeRValLoad (&Expr2);
|
ED_FinalizeRValLoad (&Expr2);
|
||||||
|
}
|
||||||
Expr2.Type = PtrConversion (Expr2.Type);
|
Expr2.Type = PtrConversion (Expr2.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ConstantCond) {
|
||||||
/* Remember the current code position */
|
/* Remember the current code position */
|
||||||
GetCodePos (&TrueCodeEnd);
|
GetCodePos (&TrueCodeEnd);
|
||||||
|
|
||||||
/* Jump around the evaluation of the third expression */
|
/* Jump around the evaluation of the third expression */
|
||||||
TrueLab = GetLocalLabel ();
|
TrueLab = GetLocalLabel ();
|
||||||
|
|
||||||
ConsumeColon ();
|
ConsumeColon ();
|
||||||
|
|
||||||
g_jump (TrueLab);
|
g_jump (TrueLab);
|
||||||
|
|
||||||
/* Jump here if the first expression was false */
|
/* Jump here if the first expression was false */
|
||||||
g_defcodelabel (FalseLab);
|
g_defcodelabel (FalseLab);
|
||||||
|
} else {
|
||||||
|
if (Expr->IVal == 0) {
|
||||||
|
/* Remove the load code of Expr2 */
|
||||||
|
RemoveCode (&SkippedBranch);
|
||||||
|
} else {
|
||||||
|
/* Remember the current code position */
|
||||||
|
GetCodePos (&SkippedBranch);
|
||||||
|
}
|
||||||
|
ConsumeColon();
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse third expression. Remember for later if it is a NULL pointer
|
/* Parse third expression. Remember for later if it is a NULL pointer
|
||||||
** expression, then load it into the primary.
|
** expression, then load it into the primary.
|
||||||
@@ -3381,12 +3550,19 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
ExprWithCheck (hie1, &Expr3);
|
ExprWithCheck (hie1, &Expr3);
|
||||||
Expr3IsNULL = ED_IsNullPtr (&Expr3);
|
Expr3IsNULL = ED_IsNullPtr (&Expr3);
|
||||||
if (!IsTypeVoid (Expr3.Type)) {
|
if (!IsTypeVoid (Expr3.Type)) {
|
||||||
|
if (!ConstantCond || !ED_IsConst (&Expr3)) {
|
||||||
/* Load it into the primary */
|
/* Load it into the primary */
|
||||||
LoadExpr (CF_NONE, &Expr3);
|
LoadExpr (CF_NONE, &Expr3);
|
||||||
ED_FinalizeRValLoad (&Expr3);
|
ED_FinalizeRValLoad (&Expr3);
|
||||||
|
}
|
||||||
Expr3.Type = PtrConversion (Expr3.Type);
|
Expr3.Type = PtrConversion (Expr3.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConstantCond && Expr->IVal != 0) {
|
||||||
|
/* Remove the load code of Expr3 */
|
||||||
|
RemoveCode (&SkippedBranch);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if any conversions are needed, if so, do them.
|
/* Check if any conversions are needed, if so, do them.
|
||||||
** Conversion rules for ?: expression are:
|
** Conversion rules for ?: expression are:
|
||||||
** - if both expressions are int expressions, default promotion
|
** - if both expressions are int expressions, default promotion
|
||||||
@@ -3419,10 +3595,12 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
TypeConversion (&Expr2, ResultType);
|
TypeConversion (&Expr2, ResultType);
|
||||||
GetCodePos (&CvtCodeEnd);
|
GetCodePos (&CvtCodeEnd);
|
||||||
|
|
||||||
|
if (!ConstantCond) {
|
||||||
/* If we had conversion code, move it to the right place */
|
/* If we had conversion code, move it to the right place */
|
||||||
if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) {
|
if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) {
|
||||||
MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd);
|
MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
|
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
|
||||||
/* Must point to same type */
|
/* Must point to same type */
|
||||||
@@ -3440,17 +3618,34 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
|
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
|
||||||
/* Result type is void */
|
/* Result type is void */
|
||||||
ResultType = Expr3.Type;
|
ResultType = Expr3.Type;
|
||||||
|
} else {
|
||||||
|
if (IsClassStruct (Expr2.Type) && IsClassStruct (Expr3.Type) &&
|
||||||
|
TypeCmp (Expr2.Type, Expr3.Type) == TC_IDENTICAL) {
|
||||||
|
/* Result type is struct/union */
|
||||||
|
ResultType = Expr2.Type;
|
||||||
} else {
|
} else {
|
||||||
TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1,
|
TypeCompatibilityDiagnostic (Expr2.Type, Expr3.Type, 1,
|
||||||
"Incompatible types in ternary '%s' with '%s'");
|
"Incompatible types in ternary '%s' with '%s'");
|
||||||
ResultType = Expr2.Type; /* Doesn't matter here */
|
ResultType = Expr2.Type; /* Doesn't matter here */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ConstantCond) {
|
||||||
/* Define the final label */
|
/* Define the final label */
|
||||||
g_defcodelabel (TrueLab);
|
g_defcodelabel (TrueLab);
|
||||||
|
/* Set up the result expression type */
|
||||||
|
ED_FinalizeRValLoad (Expr);
|
||||||
|
/* Restore the original evaluation flags */
|
||||||
|
Expr->Flags = (Expr->Flags & ~E_MASK_KEEP_RESULT) | Flags;
|
||||||
|
} else {
|
||||||
|
if (Expr->IVal != 0) {
|
||||||
|
*Expr = Expr2;
|
||||||
|
} else {
|
||||||
|
*Expr = Expr3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the target expression */
|
/* Setup the target expression */
|
||||||
ED_FinalizeRValLoad (Expr);
|
|
||||||
Expr->Type = ResultType;
|
Expr->Type = ResultType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3460,7 +3655,6 @@ static void hieQuest (ExprDesc* Expr)
|
|||||||
static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
|
static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
|
||||||
/* Process "op=" operators. */
|
/* Process "op=" operators. */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
CodeMark Mark;
|
CodeMark Mark;
|
||||||
int MustScale;
|
int MustScale;
|
||||||
@@ -3501,6 +3695,10 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
|
|||||||
GetCodePos (&Mark);
|
GetCodePos (&Mark);
|
||||||
g_push (flags, 0);
|
g_push (flags, 0);
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* Evaluate the rhs */
|
/* Evaluate the rhs */
|
||||||
MarkedExprWithCheck (hie1, &Expr2);
|
MarkedExprWithCheck (hie1, &Expr2);
|
||||||
|
|
||||||
@@ -3581,6 +3779,8 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
|
|||||||
unsigned rflags;
|
unsigned rflags;
|
||||||
int MustScale;
|
int MustScale;
|
||||||
|
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* We're currently only able to handle some addressing modes */
|
/* We're currently only able to handle some addressing modes */
|
||||||
if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) {
|
if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) {
|
||||||
@@ -3774,8 +3974,33 @@ void hie1 (ExprDesc* Expr)
|
|||||||
void hie0 (ExprDesc *Expr)
|
void hie0 (ExprDesc *Expr)
|
||||||
/* Parse comma operator. */
|
/* Parse comma operator. */
|
||||||
{
|
{
|
||||||
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_MAKE;
|
||||||
|
unsigned PrevErrorCount = ErrorCount;
|
||||||
|
CodeMark Start, End;
|
||||||
|
|
||||||
|
/* Remember the current code position */
|
||||||
|
GetCodePos (&Start);
|
||||||
|
|
||||||
hie1 (Expr);
|
hie1 (Expr);
|
||||||
while (CurTok.Tok == TOK_COMMA) {
|
while (CurTok.Tok == TOK_COMMA) {
|
||||||
|
/* If the expression didn't generate code or isn't cast to type void,
|
||||||
|
** emit a warning.
|
||||||
|
*/
|
||||||
|
GetCodePos (&End);
|
||||||
|
if (!ED_MayHaveNoEffect (Expr) &&
|
||||||
|
CodeRangeIsEmpty (&Start, &End) &&
|
||||||
|
IS_Get (&WarnNoEffect) &&
|
||||||
|
PrevErrorCount == ErrorCount) {
|
||||||
|
Warning ("Expression result unused");
|
||||||
|
}
|
||||||
|
|
||||||
|
PrevErrorCount = ErrorCount;
|
||||||
|
/* Remember the current code position */
|
||||||
|
GetCodePos (&Start);
|
||||||
|
|
||||||
|
/* Reset the expression */
|
||||||
|
ED_Init (Expr);
|
||||||
|
Expr->Flags = Flags;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
hie1 (Expr);
|
hie1 (Expr);
|
||||||
}
|
}
|
||||||
@@ -3809,24 +4034,17 @@ int evalexpr (unsigned Flags, void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|||||||
void Expression0 (ExprDesc* Expr)
|
void Expression0 (ExprDesc* Expr)
|
||||||
/* Evaluate an expression via hie0 and put the result into the primary register */
|
/* Evaluate an expression via hie0 and put the result into the primary register */
|
||||||
{
|
{
|
||||||
|
unsigned Flags = Expr->Flags & E_MASK_KEEP_RESULT;
|
||||||
|
|
||||||
|
/* Only check further after the expression is evaluated */
|
||||||
ExprWithCheck (hie0, Expr);
|
ExprWithCheck (hie0, Expr);
|
||||||
LoadExpr (CF_NONE, Expr);
|
|
||||||
|
if ((Expr->Flags & Flags & E_MASK_EVAL) != (Flags & E_MASK_EVAL)) {
|
||||||
|
Internal ("Expression flags tampered: %08X", Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ED_YetToLoad (Expr)) {
|
||||||
|
LoadExpr (CF_NONE, Expr);
|
||||||
void ConstExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|
||||||
/* Will evaluate an expression via the given function. If the result is not
|
|
||||||
** a constant of some sort, a diagnostic will be printed, and the value is
|
|
||||||
** replaced by a constant one to make sure there are no internal errors that
|
|
||||||
** result from this input error.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
ExprWithCheck (Func, Expr);
|
|
||||||
if (!ED_IsConst (Expr)) {
|
|
||||||
Error ("Constant expression expected");
|
|
||||||
/* To avoid any compiler errors, make the expression a valid const */
|
|
||||||
ED_MakeConstAbsInt (Expr, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3841,25 +4059,56 @@ void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|||||||
{
|
{
|
||||||
ExprWithCheck (Func, Expr);
|
ExprWithCheck (Func, Expr);
|
||||||
if (!ED_IsBool (Expr)) {
|
if (!ED_IsBool (Expr)) {
|
||||||
Error ("Boolean expression expected");
|
Error ("Scalar expression expected");
|
||||||
/* To avoid any compiler errors, make the expression a valid int */
|
/* To avoid any compiler errors, make the expression a valid int */
|
||||||
ED_MakeConstAbsInt (Expr, 1);
|
ED_MakeConstBool (Expr, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ConstAbsIntExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
ExprDesc NoCodeConstExpr (void (*Func) (ExprDesc*))
|
||||||
/* Will evaluate an expression via the given function. If the result is not
|
/* Get an expression evaluated via the given function. If the result is not a
|
||||||
** a constant numeric integer value, a diagnostic will be printed, and the
|
** constant expression without runtime code generated, a diagnostic will be
|
||||||
** value is replaced by a constant one to make sure there are no internal
|
** printed, and the value is replaced by a constant one to make sure there are
|
||||||
** errors that result from this input error.
|
** no internal errors that result from this input error.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
ExprWithCheck (Func, Expr);
|
ExprDesc Expr;
|
||||||
if (!ED_IsConstAbsInt (Expr)) {
|
ED_Init (&Expr);
|
||||||
|
|
||||||
|
Expr.Flags |= E_EVAL_C_CONST;
|
||||||
|
MarkedExprWithCheck (Func, &Expr);
|
||||||
|
if (!ED_IsConst (&Expr) || !ED_CodeRangeIsEmpty (&Expr)) {
|
||||||
|
Error ("Constant expression expected");
|
||||||
|
/* To avoid any compiler errors, make the expression a valid const */
|
||||||
|
ED_MakeConstAbsInt (&Expr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return by value */
|
||||||
|
return Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ExprDesc NoCodeConstAbsIntExpr (void (*Func) (ExprDesc*))
|
||||||
|
/* Get an expression evaluated via the given function. If the result is not a
|
||||||
|
** constant numeric integer value without runtime code generated, a diagnostic
|
||||||
|
** will be printed, and the value is replaced by a constant one to make sure
|
||||||
|
** there are no internal errors that result from this input error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ExprDesc Expr;
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
|
Expr.Flags |= E_EVAL_C_CONST;
|
||||||
|
MarkedExprWithCheck (Func, &Expr);
|
||||||
|
if (!ED_IsConstAbsInt (&Expr) || !ED_CodeRangeIsEmpty (&Expr)) {
|
||||||
Error ("Constant integer expression expected");
|
Error ("Constant integer expression expected");
|
||||||
/* To avoid any compiler errors, make the expression a valid const */
|
/* To avoid any compiler errors, make the expression a valid const */
|
||||||
ED_MakeConstAbsInt (Expr, 1);
|
ED_MakeConstAbsInt (&Expr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return by value */
|
||||||
|
return Expr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,13 +54,6 @@ int evalexpr (unsigned flags, void (*Func) (ExprDesc*), ExprDesc* Expr);
|
|||||||
void Expression0 (ExprDesc* Expr);
|
void Expression0 (ExprDesc* Expr);
|
||||||
/* Evaluate an expression via hie0 and put the result into the primary register */
|
/* Evaluate an expression via hie0 and put the result into the primary register */
|
||||||
|
|
||||||
void ConstExpr (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
|
||||||
/* Will evaluate an expression via the given function. If the result is not
|
|
||||||
** a constant of some sort, a diagnostic will be printed, and the value is
|
|
||||||
** replaced by a constant one to make sure there are no internal errors that
|
|
||||||
** result from this input error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
||||||
/* Will evaluate an expression via the given function. If the result is not
|
/* Will evaluate an expression via the given function. If the result is not
|
||||||
** something that may be evaluated in a boolean context, a diagnostic will be
|
** something that may be evaluated in a boolean context, a diagnostic will be
|
||||||
@@ -68,11 +61,18 @@ void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
|||||||
** are no internal errors that result from this input error.
|
** are no internal errors that result from this input error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ConstAbsIntExpr (void (*Func) (ExprDesc*), ExprDesc* Expr);
|
ExprDesc NoCodeConstExpr (void (*Func) (ExprDesc*));
|
||||||
/* Will evaluate an expression via the given function. If the result is not
|
/* Get an expression evaluated via the given function. If the result is not a
|
||||||
** a constant numeric integer value, a diagnostic will be printed, and the
|
** constant expression without runtime code generated, a diagnostic will be
|
||||||
** value is replaced by a constant one to make sure there are no internal
|
** printed, and the value is replaced by a constant one to make sure there are
|
||||||
** errors that result from this input error.
|
** no internal errors that result from this input error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ExprDesc NoCodeConstAbsIntExpr (void (*Func) (ExprDesc*));
|
||||||
|
/* Get an expression evaluated via the given function. If the result is not a
|
||||||
|
** constant numeric integer value without runtime code generated, a diagnostic
|
||||||
|
** will be printed, and the value is replaced by a constant one to make sure
|
||||||
|
** there are no internal errors that result from this input error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void hie10 (ExprDesc* lval);
|
void hie10 (ExprDesc* lval);
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ ExprDesc* ED_Init (ExprDesc* Expr)
|
|||||||
{
|
{
|
||||||
Expr->Sym = 0;
|
Expr->Sym = 0;
|
||||||
Expr->Type = 0;
|
Expr->Type = 0;
|
||||||
Expr->Flags = 0;
|
Expr->Flags = E_NEED_EAX;
|
||||||
Expr->Name = 0;
|
Expr->Name = 0;
|
||||||
Expr->IVal = 0;
|
Expr->IVal = 0;
|
||||||
Expr->FVal = FP_D_Make (0.0);
|
Expr->FVal = FP_D_Make (0.0);
|
||||||
@@ -113,6 +113,24 @@ int ED_IsIndExpr (const ExprDesc* Expr)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int ED_YetToLoad (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression needs to be loaded somehow. */
|
||||||
|
{
|
||||||
|
return ED_NeedsPrimary (Expr) ||
|
||||||
|
ED_YetToTest (Expr) ||
|
||||||
|
(ED_IsLVal (Expr) && IsQualVolatile (Expr->Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ED_MarkForUneval (ExprDesc* Expr)
|
||||||
|
/* Mark the expression as not to be evaluated */
|
||||||
|
{
|
||||||
|
Expr->Flags = (Expr->Flags & ~E_MASK_EVAL) | E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
|
void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
|
||||||
/* Set the code range for this expression */
|
/* Set the code range for this expression */
|
||||||
{
|
{
|
||||||
@@ -206,7 +224,7 @@ ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type)
|
|||||||
{
|
{
|
||||||
Expr->Sym = 0;
|
Expr->Sym = 0;
|
||||||
Expr->Type = Type;
|
Expr->Type = Type;
|
||||||
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
|
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
|
||||||
Expr->Name = 0;
|
Expr->Name = 0;
|
||||||
Expr->IVal = Value;
|
Expr->IVal = Value;
|
||||||
Expr->FVal = FP_D_Make (0.0);
|
Expr->FVal = FP_D_Make (0.0);
|
||||||
@@ -220,6 +238,20 @@ ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value)
|
|||||||
{
|
{
|
||||||
Expr->Sym = 0;
|
Expr->Sym = 0;
|
||||||
Expr->Type = type_int;
|
Expr->Type = type_int;
|
||||||
|
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_MASK_KEEP_MAKE);
|
||||||
|
Expr->Name = 0;
|
||||||
|
Expr->IVal = Value;
|
||||||
|
Expr->FVal = FP_D_Make (0.0);
|
||||||
|
return Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value)
|
||||||
|
/* Replace Expr with a constant boolean expression with the given value */
|
||||||
|
{
|
||||||
|
Expr->Sym = 0;
|
||||||
|
Expr->Type = type_bool;
|
||||||
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
|
Expr->Flags = E_LOC_NONE | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
|
||||||
Expr->Name = 0;
|
Expr->Name = 0;
|
||||||
Expr->IVal = Value;
|
Expr->IVal = Value;
|
||||||
@@ -234,7 +266,7 @@ ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr)
|
|||||||
{
|
{
|
||||||
Expr->Sym = 0;
|
Expr->Sym = 0;
|
||||||
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_ADDRESS_OF);
|
Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_ADDRESS_OF);
|
||||||
Expr->Flags &= ~(E_NEED_TEST | E_CC_SET);
|
Expr->Flags &= ~E_CC_SET;
|
||||||
Expr->Flags |= (E_LOC_PRIMARY | E_RTYPE_RVAL);
|
Expr->Flags |= (E_LOC_PRIMARY | E_RTYPE_RVAL);
|
||||||
Expr->Name = 0;
|
Expr->Name = 0;
|
||||||
Expr->IVal = 0; /* No offset */
|
Expr->IVal = 0; /* No offset */
|
||||||
@@ -398,7 +430,8 @@ int ED_IsBool (const ExprDesc* Expr)
|
|||||||
/* Either ints, floats, or pointers can be used in a boolean context */
|
/* Either ints, floats, or pointers can be used in a boolean context */
|
||||||
return IsClassInt (Expr->Type) ||
|
return IsClassInt (Expr->Type) ||
|
||||||
IsClassFloat (Expr->Type) ||
|
IsClassFloat (Expr->Type) ||
|
||||||
IsClassPtr (Expr->Type);
|
IsClassPtr (Expr->Type) ||
|
||||||
|
IsClassFunc (Expr->Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ enum {
|
|||||||
** E_LOC_<else> -- dereference -> E_LOC_EXPR (pointed-to-value, must load)
|
** E_LOC_<else> -- dereference -> E_LOC_EXPR (pointed-to-value, must load)
|
||||||
** + E_ADDRESS_OF -- dereference -> (lvalue reference)
|
** + E_ADDRESS_OF -- dereference -> (lvalue reference)
|
||||||
*/
|
*/
|
||||||
E_MASK_LOC = 0x00FF,
|
E_MASK_LOC = 0x01FF,
|
||||||
E_LOC_NONE = 0x0000, /* Pure rvalue with no storage */
|
E_LOC_NONE = 0x0000, /* Pure rvalue with no storage */
|
||||||
E_LOC_ABS = 0x0001, /* Absolute numeric addressed variable */
|
E_LOC_ABS = 0x0001, /* Absolute numeric addressed variable */
|
||||||
E_LOC_GLOBAL = 0x0002, /* Global variable */
|
E_LOC_GLOBAL = 0x0002, /* Global variable */
|
||||||
@@ -104,29 +104,92 @@ enum {
|
|||||||
E_LOC_PRIMARY = 0x0020, /* Temporary in primary register */
|
E_LOC_PRIMARY = 0x0020, /* Temporary in primary register */
|
||||||
E_LOC_EXPR = 0x0040, /* A location that the primary register points to */
|
E_LOC_EXPR = 0x0040, /* A location that the primary register points to */
|
||||||
E_LOC_LITERAL = 0x0080, /* Literal in the literal pool */
|
E_LOC_LITERAL = 0x0080, /* Literal in the literal pool */
|
||||||
|
E_LOC_CODE = 0x0100, /* C code label location (&&Label) */
|
||||||
|
|
||||||
/* Constant location of some sort (only if rval) */
|
/* Immutable location addresses (immutable bases and offsets) */
|
||||||
E_LOC_CONST = E_LOC_NONE | E_LOC_ABS | E_LOC_GLOBAL | E_LOC_STATIC |
|
E_LOC_CONST = E_LOC_NONE | E_LOC_ABS | E_LOC_GLOBAL | E_LOC_STATIC |
|
||||||
E_LOC_REGISTER | E_LOC_LITERAL,
|
E_LOC_REGISTER | E_LOC_LITERAL | E_LOC_CODE,
|
||||||
|
|
||||||
|
/* Not-so-immutable location addresses (stack offsets may change dynamically) */
|
||||||
|
E_LOC_QUASICONST = E_LOC_CONST | E_LOC_STACK,
|
||||||
|
|
||||||
|
/* Expression type modifiers */
|
||||||
|
E_BITFIELD = 0x0200, /* Expression is a bit-field */
|
||||||
|
E_ADDRESS_OF = 0x0400, /* Expression is the address of the lvalue */
|
||||||
|
|
||||||
/* lvalue/rvalue in C language's sense */
|
/* lvalue/rvalue in C language's sense */
|
||||||
E_MASK_RTYPE = 0x0100,
|
E_MASK_RTYPE = 0x0800,
|
||||||
E_RTYPE_RVAL = 0x0000,
|
E_RTYPE_RVAL = 0x0000,
|
||||||
E_RTYPE_LVAL = 0x0100,
|
E_RTYPE_LVAL = 0x0800,
|
||||||
|
|
||||||
/* Bit-field? */
|
/* Expression status */
|
||||||
E_BITFIELD = 0x0200,
|
E_LOADED = 0x1000, /* Expression is loaded in primary */
|
||||||
|
E_CC_SET = 0x2000, /* Condition codes are set */
|
||||||
|
E_HAVE_MARKS = 0x4000, /* Code marks are valid */
|
||||||
|
|
||||||
/* Test */
|
/* Optimization hints */
|
||||||
E_NEED_TEST = 0x0400, /* Expression needs a test to set cc */
|
E_MASK_NEED = 0x030000,
|
||||||
E_CC_SET = 0x0800, /* Condition codes are set */
|
E_NEED_EAX = 0x000000, /* Expression result needs to be loaded in Primary */
|
||||||
|
E_NEED_NONE = 0x010000, /* Expression result is unused */
|
||||||
|
E_NEED_TEST = 0x020000, /* Expression needs a test to set cc */
|
||||||
|
|
||||||
E_HAVE_MARKS = 0x1000, /* Code marks are valid */
|
/* Expression evaluation requirements.
|
||||||
|
** Usage: (Flags & E_EVAL_<Flag>) == E_EVAL_<Flag>
|
||||||
|
**
|
||||||
|
** Remark:
|
||||||
|
** - Expression result, that is the "final value" of the expression, is no
|
||||||
|
** more than one of the effects of the whole expression. Effects other
|
||||||
|
** than it are usually consided "side-effects" in this regard.
|
||||||
|
** - The compiler front end cannot know things determined by the linker,
|
||||||
|
** such as the actual address of an object with static storage. What it
|
||||||
|
** can know is categorized as "compiler-known" here.
|
||||||
|
** - The concept "immutable" here means that once something is determined
|
||||||
|
** (not necessarily by the compiler), it will never change. This is not
|
||||||
|
** the same meaning as the "constant" word in the C standard.
|
||||||
|
** - The concept "compile-time" ( not to be confued with "compiler-known"),
|
||||||
|
** or "static" (compared to "run-time" as in "_Static_assert" in C, not
|
||||||
|
** to be confused with the "static" storage) here means that something
|
||||||
|
** has no run-time behaviors, enforced by the fact that it generates no
|
||||||
|
** target code (hence "no-code"). It is closely related to the concepts
|
||||||
|
** above but not the same.
|
||||||
|
** - An "unevaluated" expression is special and different from the above:
|
||||||
|
** while it generates no code, cannot change its "value" (it actually has
|
||||||
|
** no value), and must be completely handled by the compiler front-end,
|
||||||
|
** it is unique in that it is not "evaluated" while the others are, and
|
||||||
|
** the codegen routine of such an expression is usually separated from
|
||||||
|
** the normally evaluated ones. Therefore it is treated differently from
|
||||||
|
** the above and uses a separate flag that implies none of the above.
|
||||||
|
** - The "maybe-unused" flag is to suppress the checking and warning on
|
||||||
|
** expressions with no effects. It doesn't have any special meanings
|
||||||
|
** beyond that, and is independent from the E_NEED_<flag>s. All
|
||||||
|
** "unevaluated" expressions are flagged as "maybe-unused" just to
|
||||||
|
** avoid unnecessary warnings.
|
||||||
|
**
|
||||||
|
** Relationship of some concepts:
|
||||||
|
** - "no-code" implies "no-side-effects"
|
||||||
|
** - "immutable" = "compiler-known" OR "no-code"
|
||||||
|
** - "constant expression" in C = "compiler-known" AND "no-code", with minor differences
|
||||||
|
*/
|
||||||
|
E_MASK_EVAL = 0xFC0000,
|
||||||
|
E_EVAL_NONE = 0x000000, /* No requirements */
|
||||||
|
E_EVAL_IMMUTABLE_RESULT = 0x040000, /* Expression result must be immutable */
|
||||||
|
E_EVAL_COMPILER_KNOWN = 0x0C0000, /* Expression result must be known to the compiler */
|
||||||
|
E_EVAL_NO_SIDE_EFFECTS = 0x100000, /* Evaluation must have no side effects */
|
||||||
|
E_EVAL_NO_CODE = 0x340000, /* Evaluation must generate no code */
|
||||||
|
E_EVAL_MAYBE_UNUSED = 0x400000, /* Expression result may be unused */
|
||||||
|
E_EVAL_UNEVAL = 0xC00000, /* Expression is unevaluated */
|
||||||
|
|
||||||
E_LOADED = 0x4000, /* Expression is loaded in primary */
|
/* Expression result must be known to the compiler and generate no code to load */
|
||||||
|
E_EVAL_C_CONST = E_EVAL_COMPILER_KNOWN | E_EVAL_NO_CODE,
|
||||||
|
|
||||||
E_ADDRESS_OF = 0x8000, /* Expression is the address of the lvalue */
|
/* Flags to keep in subexpressions of most operations other than ternary */
|
||||||
|
E_MASK_KEEP_SUBEXPR = E_MASK_EVAL,
|
||||||
|
|
||||||
|
/* Flags to keep for the two result subexpressions of the ternary operation */
|
||||||
|
E_MASK_KEEP_RESULT = E_MASK_NEED | E_MASK_EVAL,
|
||||||
|
|
||||||
|
/* Flags to keep when using the ED_Make functions */
|
||||||
|
E_MASK_KEEP_MAKE = E_HAVE_MARKS | E_MASK_KEEP_RESULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forward */
|
/* Forward */
|
||||||
@@ -292,13 +355,33 @@ void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth);
|
|||||||
/* Make this expression a bit field expression */
|
/* Make this expression a bit field expression */
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE void ED_MarkForTest (ExprDesc* Expr)
|
INLINE void ED_RequireTest (ExprDesc* Expr)
|
||||||
/* Mark the expression for a test. */
|
/* Mark the expression for a test. */
|
||||||
{
|
{
|
||||||
Expr->Flags |= E_NEED_TEST;
|
Expr->Flags |= E_NEED_TEST;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define ED_MarkForTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0)
|
# define ED_RequireTest(Expr) do { (Expr)->Flags |= E_NEED_TEST; } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_GetNeeds (const ExprDesc* Expr)
|
||||||
|
/* Get flags about what the expression needs. */
|
||||||
|
{
|
||||||
|
return (Expr->Flags & E_MASK_NEED);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_GetNeeds(Expr) ((Expr)->Flags & E_MASK_NEED)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_NeedsPrimary (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression needs to be in Primary. */
|
||||||
|
{
|
||||||
|
return (Expr->Flags & E_MASK_NEED) == E_NEED_EAX;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_NeedsPrimary(Expr) (((Expr)->Flags & E_MASK_NEED) == E_NEED_EAX)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
@@ -311,15 +394,25 @@ INLINE int ED_NeedsTest (const ExprDesc* Expr)
|
|||||||
# define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0)
|
# define ED_NeedsTest(Expr) (((Expr)->Flags & E_NEED_TEST) != 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_YetToTest (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression needs to be tested but not yet. */
|
||||||
|
{
|
||||||
|
return ((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_YetToTest(Expr) (((Expr)->Flags & (E_NEED_TEST | E_CC_SET)) == E_NEED_TEST)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE void ED_TestDone (ExprDesc* Expr)
|
INLINE void ED_TestDone (ExprDesc* Expr)
|
||||||
/* Mark the expression as tested and condition codes set. */
|
/* Mark the expression as tested and condition codes set. */
|
||||||
{
|
{
|
||||||
Expr->Flags = (Expr->Flags & ~E_NEED_TEST) | E_CC_SET;
|
Expr->Flags |= E_CC_SET;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define ED_TestDone(Expr) \
|
# define ED_TestDone(Expr) \
|
||||||
do { (Expr)->Flags = ((Expr)->Flags & ~E_NEED_TEST) | E_CC_SET; } while (0)
|
do { (Expr)->Flags |= E_CC_SET; } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
@@ -354,6 +447,42 @@ INLINE int ED_IsLoaded (const ExprDesc* Expr)
|
|||||||
# define ED_IsLoaded(Expr) (((Expr)->Flags & E_LOADED) != 0)
|
# define ED_IsLoaded(Expr) (((Expr)->Flags & E_LOADED) != 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int ED_YetToLoad (const ExprDesc* Expr);
|
||||||
|
/* Check if the expression is yet to be loaded somehow. */
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_NeedsConst (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression need be immutable */
|
||||||
|
{
|
||||||
|
return (Expr->Flags & E_EVAL_IMMUTABLE_RESULT) == E_EVAL_IMMUTABLE_RESULT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_NeedsConst(Expr) (((Expr)->Flags & E_EVAL_IMMUTABLE_RESULT) == E_EVAL_IMMUTABLE_RESULT)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ED_MarkForUneval (ExprDesc* Expr);
|
||||||
|
/* Mark the expression as not to be evaluated */
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_MayBeUneval (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression may be uevaluated */
|
||||||
|
{
|
||||||
|
return (Expr->Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_MayBeUneval(Expr) (((Expr)->Flags & E_EVAL_UNEVAL) == E_EVAL_UNEVAL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int ED_MayHaveNoEffect (const ExprDesc* Expr)
|
||||||
|
/* Check if the expression may be present without effects */
|
||||||
|
{
|
||||||
|
return (Expr->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ED_MayHaveNoEffect(Expr) (((Expr)->Flags & E_EVAL_MAYBE_UNUSED) == E_EVAL_MAYBE_UNUSED)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_INLINE)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
|
||||||
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
|
||||||
@@ -411,6 +540,9 @@ ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type);
|
|||||||
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value);
|
ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value);
|
||||||
/* Replace Expr with an constant integer with the given value */
|
/* Replace Expr with an constant integer with the given value */
|
||||||
|
|
||||||
|
ExprDesc* ED_MakeConstBool (ExprDesc* Expr, long Value);
|
||||||
|
/* Replace Expr with a constant boolean expression with the given value */
|
||||||
|
|
||||||
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr);
|
ExprDesc* ED_FinalizeRValLoad (ExprDesc* Expr);
|
||||||
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
|
/* Finalize the result of LoadExpr to be an rvalue in the primary register */
|
||||||
|
|
||||||
@@ -519,7 +651,7 @@ int ED_IsNullPtr (const ExprDesc* Expr);
|
|||||||
|
|
||||||
int ED_IsBool (const ExprDesc* Expr);
|
int ED_IsBool (const ExprDesc* Expr);
|
||||||
/* Return true of the expression can be treated as a boolean, that is, it can
|
/* Return true of the expression can be treated as a boolean, that is, it can
|
||||||
** be an operand to a compare operation.
|
** be an operand to a compare operation with 0/NULL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void PrintExprDesc (FILE* F, ExprDesc* Expr);
|
void PrintExprDesc (FILE* F, ExprDesc* Expr);
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ void GotoStatement (void)
|
|||||||
CodeEntry *E;
|
CodeEntry *E;
|
||||||
unsigned char val;
|
unsigned char val;
|
||||||
|
|
||||||
|
ED_Init (&desc);
|
||||||
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* arr[foo], we only support simple foo for now */
|
/* arr[foo], we only support simple foo for now */
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
|
|||||||
Flags |= TypeOf (Expr->Type);
|
Flags |= TypeOf (Expr->Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ED_NeedsTest (Expr)) {
|
if (ED_YetToTest (Expr)) {
|
||||||
/* If we're only testing, we do not need to promote char to int.
|
/* If we're only testing, we do not need to promote char to int.
|
||||||
** CF_FORCECHAR does nothing if the type is not CF_CHAR.
|
** CF_FORCECHAR does nothing if the type is not CF_CHAR.
|
||||||
*/
|
*/
|
||||||
@@ -238,7 +238,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
|
|||||||
*/
|
*/
|
||||||
CHECK (Expr->BitOffs < CHAR_BITS);
|
CHECK (Expr->BitOffs < CHAR_BITS);
|
||||||
|
|
||||||
if (ED_NeedsTest (Expr)) {
|
if (ED_YetToTest (Expr)) {
|
||||||
g_testbitfield (Flags, Expr->BitOffs, Expr->BitWidth);
|
g_testbitfield (Flags, Expr->BitOffs, Expr->BitWidth);
|
||||||
} else {
|
} else {
|
||||||
g_extractbitfield (Flags, BitFieldFullWidthFlags, IsSignSigned (Expr->Type),
|
g_extractbitfield (Flags, BitFieldFullWidthFlags, IsSignSigned (Expr->Type),
|
||||||
@@ -256,7 +256,7 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
|
|||||||
LoadAddress (Flags, Expr);
|
LoadAddress (Flags, Expr);
|
||||||
|
|
||||||
/* Are we testing this value? */
|
/* Are we testing this value? */
|
||||||
if (ED_NeedsTest (Expr)) {
|
if (ED_YetToTest (Expr)) {
|
||||||
/* Yes, force a test */
|
/* Yes, force a test */
|
||||||
g_test (Flags);
|
g_test (Flags);
|
||||||
ED_TestDone (Expr);
|
ED_TestDone (Expr);
|
||||||
|
|||||||
@@ -122,8 +122,6 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg)
|
|||||||
/* Check for an optional initialization */
|
/* Check for an optional initialization */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
ExprDesc Expr;
|
|
||||||
|
|
||||||
/* Skip the '=' */
|
/* Skip the '=' */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -152,6 +150,9 @@ static void ParseRegisterDecl (Declaration* Decl, int Reg)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
ExprDesc Expr;
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Parse the expression */
|
/* Parse the expression */
|
||||||
hie1 (&Expr);
|
hie1 (&Expr);
|
||||||
|
|
||||||
@@ -207,8 +208,6 @@ static void ParseAutoDecl (Declaration* Decl)
|
|||||||
/* Check for an optional initialization */
|
/* Check for an optional initialization */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
ExprDesc Expr;
|
|
||||||
|
|
||||||
/* Skip the '=' */
|
/* Skip the '=' */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -246,6 +245,9 @@ static void ParseAutoDecl (Declaration* Decl)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
ExprDesc Expr;
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Allocate previously reserved local space */
|
/* Allocate previously reserved local space */
|
||||||
F_AllocLocalSpace (CurrentFunc);
|
F_AllocLocalSpace (CurrentFunc);
|
||||||
|
|
||||||
@@ -307,8 +309,6 @@ static void ParseAutoDecl (Declaration* Decl)
|
|||||||
/* Allow assignments */
|
/* Allow assignments */
|
||||||
if (CurTok.Tok == TOK_ASSIGN) {
|
if (CurTok.Tok == TOK_ASSIGN) {
|
||||||
|
|
||||||
ExprDesc Expr;
|
|
||||||
|
|
||||||
/* Skip the '=' */
|
/* Skip the '=' */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -332,6 +332,9 @@ static void ParseAutoDecl (Declaration* Decl)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
ExprDesc Expr;
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Allocate space for the variable */
|
/* Allocate space for the variable */
|
||||||
AllocStorage (DataLabel, g_usebss, Size);
|
AllocStorage (DataLabel, g_usebss, Size);
|
||||||
|
|
||||||
|
|||||||
@@ -1042,8 +1042,6 @@ static void DoError (void)
|
|||||||
static int DoIf (int Skip)
|
static int DoIf (int Skip)
|
||||||
/* Process #if directive */
|
/* Process #if directive */
|
||||||
{
|
{
|
||||||
ExprDesc Expr;
|
|
||||||
|
|
||||||
/* We're about to abuse the compiler expression parser to evaluate the
|
/* We're about to abuse the compiler expression parser to evaluate the
|
||||||
** #if expression. Save the current tokens to come back here later.
|
** #if expression. Save the current tokens to come back here later.
|
||||||
** NOTE: Yes, this is a hack, but it saves a complete separate expression
|
** NOTE: Yes, this is a hack, but it saves a complete separate expression
|
||||||
@@ -1078,7 +1076,7 @@ static int DoIf (int Skip)
|
|||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Call the expression parser */
|
/* Call the expression parser */
|
||||||
ConstExpr (hie1, &Expr);
|
ExprDesc Expr = NoCodeConstExpr (hie1);
|
||||||
|
|
||||||
/* End preprocessing mode */
|
/* End preprocessing mode */
|
||||||
Preprocessing = 0;
|
Preprocessing = 0;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Set when the preprocessor calls ConstExpr() recursively */
|
/* Set when the preprocessor calls NoCodeConstExpr() recursively */
|
||||||
extern unsigned char Preprocessing;
|
extern unsigned char Preprocessing;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,6 @@
|
|||||||
void ShiftExpr (struct ExprDesc* Expr)
|
void ShiftExpr (struct ExprDesc* Expr)
|
||||||
/* Parse the << and >> operators. */
|
/* Parse the << and >> operators. */
|
||||||
{
|
{
|
||||||
ExprDesc Expr2;
|
|
||||||
CodeMark Mark1;
|
CodeMark Mark1;
|
||||||
CodeMark Mark2;
|
CodeMark Mark2;
|
||||||
token_t Tok; /* The operator token */
|
token_t Tok; /* The operator token */
|
||||||
@@ -78,6 +77,10 @@ void ShiftExpr (struct ExprDesc* Expr)
|
|||||||
|
|
||||||
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
|
while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
|
||||||
|
|
||||||
|
ExprDesc Expr2;
|
||||||
|
ED_Init (&Expr2);
|
||||||
|
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
|
||||||
|
|
||||||
/* All operators that call this function expect an int on the lhs */
|
/* All operators that call this function expect an int on the lhs */
|
||||||
if (!IsClassInt (Expr->Type)) {
|
if (!IsClassInt (Expr->Type)) {
|
||||||
Error ("Integer expression expected");
|
Error ("Integer expression expected");
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ void ParseStaticAssert ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parse assertion condition */
|
/* Parse assertion condition */
|
||||||
ConstAbsIntExpr (hie1, &Expr);
|
Expr = NoCodeConstAbsIntExpr (hie1);
|
||||||
failed = !Expr.IVal;
|
failed = !Expr.IVal;
|
||||||
|
|
||||||
/* If there is a comma, we also have an error message. The message is optional because we
|
/* If there is a comma, we also have an error message. The message is optional because we
|
||||||
|
|||||||
@@ -152,6 +152,9 @@ static void ParseArg (ArgDesc* Arg, Type* Type)
|
|||||||
/* Remember the required argument type */
|
/* Remember the required argument type */
|
||||||
Arg->ArgType = Type;
|
Arg->ArgType = Type;
|
||||||
|
|
||||||
|
/* Init expression */
|
||||||
|
ED_Init (&Arg->Expr);
|
||||||
|
|
||||||
/* Read the expression we're going to pass to the function */
|
/* Read the expression we're going to pass to the function */
|
||||||
MarkedExprWithCheck (hie1, &Arg->Expr);
|
MarkedExprWithCheck (hie1, &Arg->Expr);
|
||||||
|
|
||||||
@@ -1180,6 +1183,8 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
|
|||||||
long ECount;
|
long ECount;
|
||||||
unsigned L;
|
unsigned L;
|
||||||
|
|
||||||
|
ED_Init (&Arg);
|
||||||
|
|
||||||
/* Setup the argument type string */
|
/* Setup the argument type string */
|
||||||
ArgType[1].C = T_CHAR | T_QUAL_CONST;
|
ArgType[1].C = T_CHAR | T_QUAL_CONST;
|
||||||
|
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ static void ReturnStatement (void)
|
|||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
const Type* ReturnType;
|
const Type* ReturnType;
|
||||||
|
|
||||||
|
ED_Init (&Expr);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (CurTok.Tok != TOK_SEMI) {
|
if (CurTok.Tok != TOK_SEMI) {
|
||||||
|
|
||||||
@@ -434,8 +435,6 @@ static void ContinueStatement (void)
|
|||||||
static void ForStatement (void)
|
static void ForStatement (void)
|
||||||
/* Handle a 'for' statement */
|
/* Handle a 'for' statement */
|
||||||
{
|
{
|
||||||
ExprDesc lval1;
|
|
||||||
ExprDesc lval3;
|
|
||||||
int HaveIncExpr;
|
int HaveIncExpr;
|
||||||
CodeMark IncExprStart;
|
CodeMark IncExprStart;
|
||||||
CodeMark IncExprEnd;
|
CodeMark IncExprEnd;
|
||||||
@@ -460,6 +459,10 @@ static void ForStatement (void)
|
|||||||
|
|
||||||
/* Parse the initializer expression */
|
/* Parse the initializer expression */
|
||||||
if (CurTok.Tok != TOK_SEMI) {
|
if (CurTok.Tok != TOK_SEMI) {
|
||||||
|
/* The value of the expression is unused */
|
||||||
|
ExprDesc lval1;
|
||||||
|
ED_Init (&lval1);
|
||||||
|
lval1.Flags = E_NEED_NONE;
|
||||||
Expression0 (&lval1);
|
Expression0 (&lval1);
|
||||||
}
|
}
|
||||||
ConsumeSemi ();
|
ConsumeSemi ();
|
||||||
@@ -485,6 +488,10 @@ static void ForStatement (void)
|
|||||||
/* Parse the increment expression */
|
/* Parse the increment expression */
|
||||||
HaveIncExpr = (CurTok.Tok != TOK_RPAREN);
|
HaveIncExpr = (CurTok.Tok != TOK_RPAREN);
|
||||||
if (HaveIncExpr) {
|
if (HaveIncExpr) {
|
||||||
|
/* The value of the expression is unused */
|
||||||
|
ExprDesc lval3;
|
||||||
|
ED_Init (&lval3);
|
||||||
|
lval3.Flags = E_NEED_NONE;
|
||||||
Expression0 (&lval3);
|
Expression0 (&lval3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,8 +597,10 @@ int Statement (int* PendingToken)
|
|||||||
{
|
{
|
||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
int GotBreak;
|
int GotBreak;
|
||||||
|
unsigned PrevErrorCount;
|
||||||
CodeMark Start, End;
|
CodeMark Start, End;
|
||||||
unsigned PrevErrorCount = ErrorCount;
|
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Assume no pending token */
|
/* Assume no pending token */
|
||||||
if (PendingToken) {
|
if (PendingToken) {
|
||||||
@@ -676,25 +685,24 @@ int Statement (int* PendingToken)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Remember the current code position */
|
/* Remember the current error count and code position */
|
||||||
|
PrevErrorCount = ErrorCount;
|
||||||
GetCodePos (&Start);
|
GetCodePos (&Start);
|
||||||
|
|
||||||
/* Actual statement */
|
/* Actual statement */
|
||||||
ExprWithCheck (hie0, &Expr);
|
Expr.Flags |= E_NEED_NONE;
|
||||||
/* Load the result only if it is an lvalue and the type is
|
Expression0 (&Expr);
|
||||||
** marked as volatile. Otherwise the load is useless.
|
|
||||||
*/
|
|
||||||
if (ED_IsLVal (&Expr) && IsQualVolatile (Expr.Type)) {
|
|
||||||
LoadExpr (CF_NONE, &Expr);
|
|
||||||
}
|
|
||||||
/* If the statement didn't generate code, and is not of type
|
/* If the statement didn't generate code, and is not of type
|
||||||
** void, emit a warning.
|
** void, emit a warning.
|
||||||
*/
|
*/
|
||||||
GetCodePos (&End);
|
GetCodePos (&End);
|
||||||
if (CodeRangeIsEmpty (&Start, &End) &&
|
if (!ED_YetToLoad (&Expr) &&
|
||||||
!IsTypeVoid (Expr.Type) &&
|
!ED_MayHaveNoEffect (&Expr) &&
|
||||||
|
CodeRangeIsEmpty (&Start, &End) &&
|
||||||
IS_Get (&WarnNoEffect) &&
|
IS_Get (&WarnNoEffect) &&
|
||||||
PrevErrorCount == ErrorCount) {
|
PrevErrorCount == ErrorCount) {
|
||||||
Warning ("Statement has no effect");
|
Warning ("Expression result unused");
|
||||||
}
|
}
|
||||||
CheckSemi (PendingToken);
|
CheckSemi (PendingToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ void SwitchStatement (void)
|
|||||||
SwitchCtrl* OldSwitch; /* Pointer to old switch control data */
|
SwitchCtrl* OldSwitch; /* Pointer to old switch control data */
|
||||||
SwitchCtrl SwitchData; /* New switch data */
|
SwitchCtrl SwitchData; /* New switch data */
|
||||||
|
|
||||||
|
|
||||||
/* Eat the "switch" token */
|
/* Eat the "switch" token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@@ -105,6 +104,8 @@ void SwitchStatement (void)
|
|||||||
** integer type.
|
** integer type.
|
||||||
*/
|
*/
|
||||||
ConsumeLParen ();
|
ConsumeLParen ();
|
||||||
|
|
||||||
|
ED_Init (&SwitchExpr);
|
||||||
Expression0 (&SwitchExpr);
|
Expression0 (&SwitchExpr);
|
||||||
if (!IsClassInt (SwitchExpr.Type)) {
|
if (!IsClassInt (SwitchExpr.Type)) {
|
||||||
Error ("Switch quantity is not an integer");
|
Error ("Switch quantity is not an integer");
|
||||||
@@ -211,12 +212,11 @@ void CaseLabel (void)
|
|||||||
long Val; /* Case label value */
|
long Val; /* Case label value */
|
||||||
unsigned CodeLabel; /* Code label for this case */
|
unsigned CodeLabel; /* Code label for this case */
|
||||||
|
|
||||||
|
|
||||||
/* Skip the "case" token */
|
/* Skip the "case" token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Read the selector expression */
|
/* Read the selector expression */
|
||||||
ConstAbsIntExpr (hie1, &CaseExpr);
|
CaseExpr = NoCodeConstAbsIntExpr (hie1);
|
||||||
Val = CaseExpr.IVal;
|
Val = CaseExpr.IVal;
|
||||||
|
|
||||||
/* Now check if we're inside a switch statement */
|
/* Now check if we're inside a switch statement */
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ unsigned Test (unsigned Label, int Invert)
|
|||||||
ExprDesc Expr;
|
ExprDesc Expr;
|
||||||
unsigned Result;
|
unsigned Result;
|
||||||
|
|
||||||
|
ED_Init (&Expr);
|
||||||
|
|
||||||
/* Read a boolean expression */
|
/* Read a boolean expression */
|
||||||
BoolExpr (hie0, &Expr);
|
BoolExpr (hie0, &Expr);
|
||||||
|
|
||||||
@@ -80,10 +82,8 @@ unsigned Test (unsigned Label, int Invert)
|
|||||||
/* Result is unknown */
|
/* Result is unknown */
|
||||||
Result = TESTEXPR_UNKNOWN;
|
Result = TESTEXPR_UNKNOWN;
|
||||||
|
|
||||||
/* If the expr hasn't set condition codes, set the force-test flag */
|
/* Set the test flag */
|
||||||
if (!ED_IsTested (&Expr)) {
|
ED_RequireTest (&Expr);
|
||||||
ED_MarkForTest (&Expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the value into the primary register */
|
/* Load the value into the primary register */
|
||||||
LoadExpr (CF_FORCECHAR, &Expr);
|
LoadExpr (CF_FORCECHAR, &Expr);
|
||||||
|
|||||||
@@ -371,6 +371,11 @@ void TypeCast (ExprDesc* Expr)
|
|||||||
GetBasicTypeName (NewType));
|
GetBasicTypeName (NewType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the new type is void, the cast expression can have no effects */
|
||||||
|
if (IsTypeVoid (NewType)) {
|
||||||
|
Expr->Flags |= E_EVAL_MAYBE_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
/* The result is always an rvalue */
|
/* The result is always an rvalue */
|
||||||
ED_MarkExprAsRVal (Expr);
|
ED_MarkExprAsRVal (Expr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,6 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR)
|
|||||||
|
|
||||||
define PRG_template
|
define PRG_template
|
||||||
|
|
||||||
# should compile, but gives an error
|
|
||||||
$(WORKDIR)/bug250.$1.$2.prg: bug250.c | $(WORKDIR)
|
|
||||||
@echo "FIXME: " $$@ "currently does not compile."
|
|
||||||
$(if $(QUIET),echo misc/bug250.$1.$2.prg)
|
|
||||||
$(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR)
|
|
||||||
|
|
||||||
# should compile, but gives an error
|
# should compile, but gives an error
|
||||||
$(WORKDIR)/bug760.$1.$2.prg: bug760.c | $(WORKDIR)
|
$(WORKDIR)/bug760.$1.$2.prg: bug760.c | $(WORKDIR)
|
||||||
@echo "FIXME: " $$@ "currently does not compile."
|
@echo "FIXME: " $$@ "currently does not compile."
|
||||||
|
|||||||
360
test/ref/pr1220.c
Normal file
360
test/ref/pr1220.c
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
/* PR #1220 - test constant ternary, AND and OR */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* test AND/OR, results as integers */
|
||||||
|
#define CONTEXT_A(x) do {\
|
||||||
|
s = 0, flags = 0, t = (x),\
|
||||||
|
printf("%3d %2X: %d\n", s, flags, t);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* test AND/OR in ternary context */
|
||||||
|
#define CONTEXT_B(x) do {\
|
||||||
|
s = 0, flags = 0,\
|
||||||
|
(x ? printf("%3d %2X: 1\n", s, flags) : printf("%3d %2X: 0\n", s, flags));\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int s, t;
|
||||||
|
unsigned flags;
|
||||||
|
|
||||||
|
int f(x)
|
||||||
|
/* The call to this function should be and only be skipped strictly according to
|
||||||
|
** the short-circuit evaluation rule.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
flags |= (x != 0) << s;
|
||||||
|
++s;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _A f(a)
|
||||||
|
#define _B f(b)
|
||||||
|
#define _C f(c)
|
||||||
|
#define _D f(d)
|
||||||
|
#define _T (f(0), -1)
|
||||||
|
#define _F (f(-1), 0)
|
||||||
|
|
||||||
|
void f0()
|
||||||
|
/* constant short-circuit */
|
||||||
|
{
|
||||||
|
printf("f0()\n");
|
||||||
|
|
||||||
|
CONTEXT_A(_T && _T && _T);
|
||||||
|
CONTEXT_A(_F && _F && _F);
|
||||||
|
|
||||||
|
CONTEXT_A(_T || _T || _T);
|
||||||
|
CONTEXT_A(_F || _F || _F);
|
||||||
|
|
||||||
|
CONTEXT_A(_T && _T || _T && _T);
|
||||||
|
CONTEXT_A(_F && _F || _F && _F);
|
||||||
|
CONTEXT_A(_T && _F || _T && _F);
|
||||||
|
CONTEXT_A(_F && _T || _F && _T);
|
||||||
|
|
||||||
|
CONTEXT_A((_T && _T) || (_T && _T));
|
||||||
|
CONTEXT_A((_F && _F) || (_F && _F));
|
||||||
|
CONTEXT_A((_T && _F) || (_T && _F));
|
||||||
|
CONTEXT_A((_F && _T) || (_F && _T));
|
||||||
|
|
||||||
|
CONTEXT_A((_T || _T) && (_T || _T));
|
||||||
|
CONTEXT_A((_F || _F) && (_F || _F));
|
||||||
|
CONTEXT_A((_T || _F) && (_T || _F));
|
||||||
|
CONTEXT_A((_F || _T) && (_F || _T));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f1(int a, int b, int c)
|
||||||
|
/* AND */
|
||||||
|
{
|
||||||
|
printf("f1(%d, %d, %d)\n", a, b, c);
|
||||||
|
|
||||||
|
CONTEXT_A(_A && _B && _C);
|
||||||
|
|
||||||
|
CONTEXT_A(_T && _B && _C);
|
||||||
|
CONTEXT_A(_A && _T && _C);
|
||||||
|
CONTEXT_A(_A && _B && _T);
|
||||||
|
|
||||||
|
CONTEXT_A(_F && _B && _C);
|
||||||
|
CONTEXT_A(_A && _F && _C);
|
||||||
|
CONTEXT_A(_A && _B && _F);
|
||||||
|
|
||||||
|
CONTEXT_A(_T && _T && _C);
|
||||||
|
CONTEXT_A(_A && _T && _T);
|
||||||
|
CONTEXT_A(_T && _B && _T);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2(int a, int b, int c)
|
||||||
|
/* OR */
|
||||||
|
{
|
||||||
|
printf("f2(%d, %d, %d)\n", a, b, c);
|
||||||
|
|
||||||
|
CONTEXT_A(_A || _B || _C);
|
||||||
|
|
||||||
|
CONTEXT_A(_T || _B || _C);
|
||||||
|
CONTEXT_A(_A || _T || _C);
|
||||||
|
CONTEXT_A(_A || _B || _T);
|
||||||
|
|
||||||
|
CONTEXT_A(_F || _B || _C);
|
||||||
|
CONTEXT_A(_A || _F || _C);
|
||||||
|
CONTEXT_A(_A || _B || _F);
|
||||||
|
|
||||||
|
CONTEXT_A(_F || _F || _C);
|
||||||
|
CONTEXT_A(_A || _F || _F);
|
||||||
|
CONTEXT_A(_F || _B || _F);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f3(int a, int b, int c, int d)
|
||||||
|
/* AND and OR */
|
||||||
|
{
|
||||||
|
printf("f3(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_A(_A && _B || _C && _D);
|
||||||
|
CONTEXT_A(_T && _T || _C && _D);
|
||||||
|
CONTEXT_A(_A && _B || _T && _T);
|
||||||
|
|
||||||
|
CONTEXT_A(_T && _B || _C && _D);
|
||||||
|
CONTEXT_A(_A && _T || _C && _D);
|
||||||
|
CONTEXT_A(_A && _B || _T && _D);
|
||||||
|
CONTEXT_A(_A && _B || _C && _T);
|
||||||
|
|
||||||
|
CONTEXT_A(_F && _B || _C && _D);
|
||||||
|
CONTEXT_A(_A && _F || _C && _D);
|
||||||
|
CONTEXT_A(_A && _B || _F && _D);
|
||||||
|
CONTEXT_A(_A && _B || _C && _F);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f4(int a, int b, int c, int d)
|
||||||
|
/* AND as top-level expression inside OR context */
|
||||||
|
{
|
||||||
|
printf("f4(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_A((_A && _B) || (_C && _D));
|
||||||
|
CONTEXT_A((_T && _T) || (_C && _D));
|
||||||
|
CONTEXT_A((_A && _B) || (_T && _T));
|
||||||
|
|
||||||
|
CONTEXT_A((_T && _B) || (_C && _D));
|
||||||
|
CONTEXT_A((_A && _T) || (_C && _D));
|
||||||
|
CONTEXT_A((_A && _B) || (_T && _D));
|
||||||
|
CONTEXT_A((_A && _B) || (_C && _T));
|
||||||
|
|
||||||
|
CONTEXT_A((_F && _B) || (_C && _D));
|
||||||
|
CONTEXT_A((_A && _F) || (_C && _D));
|
||||||
|
CONTEXT_A((_A && _B) || (_F && _D));
|
||||||
|
CONTEXT_A((_A && _B) || (_C && _F));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f5(int a, int b, int c, int d)
|
||||||
|
/* OR as top-level expression inside AND context */
|
||||||
|
{
|
||||||
|
printf("f5(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_A((_A || _B) && (_C || _D));
|
||||||
|
CONTEXT_A((_F || _F) && (_C || _D));
|
||||||
|
CONTEXT_A((_A || _B) && (_F || _F));
|
||||||
|
|
||||||
|
CONTEXT_A((_T || _B) && (_C || _D));
|
||||||
|
CONTEXT_A((_A || _T) && (_C || _D));
|
||||||
|
CONTEXT_A((_A || _B) && (_T || _D));
|
||||||
|
CONTEXT_A((_A || _B) && (_C || _T));
|
||||||
|
|
||||||
|
CONTEXT_A((_F || _B) && (_C || _D));
|
||||||
|
CONTEXT_A((_A || _F) && (_C || _D));
|
||||||
|
CONTEXT_A((_A || _B) && (_F || _D));
|
||||||
|
CONTEXT_A((_A || _B) && (_C || _F));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f0_B()
|
||||||
|
/* constant short-circuit */
|
||||||
|
{
|
||||||
|
printf("f0()\n");
|
||||||
|
|
||||||
|
CONTEXT_B(_T && _T && _T);
|
||||||
|
CONTEXT_B(_F && _F && _F);
|
||||||
|
|
||||||
|
CONTEXT_B(_T || _T || _T);
|
||||||
|
CONTEXT_B(_F || _F || _F);
|
||||||
|
|
||||||
|
CONTEXT_B(_T && _T || _T && _T);
|
||||||
|
CONTEXT_B(_F && _F || _F && _F);
|
||||||
|
CONTEXT_B(_T && _F || _T && _F);
|
||||||
|
CONTEXT_B(_F && _T || _F && _T);
|
||||||
|
|
||||||
|
CONTEXT_B((_T && _T) || (_T && _T));
|
||||||
|
CONTEXT_B((_F && _F) || (_F && _F));
|
||||||
|
CONTEXT_B((_T && _F) || (_T && _F));
|
||||||
|
CONTEXT_B((_F && _T) || (_F && _T));
|
||||||
|
|
||||||
|
CONTEXT_B((_T || _T) && (_T || _T));
|
||||||
|
CONTEXT_B((_F || _F) && (_F || _F));
|
||||||
|
CONTEXT_B((_T || _F) && (_T || _F));
|
||||||
|
CONTEXT_B((_F || _T) && (_F || _T));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f1_B(int a, int b, int c)
|
||||||
|
/* AND */
|
||||||
|
{
|
||||||
|
printf("f1(%d, %d, %d)\n", a, b, c);
|
||||||
|
|
||||||
|
CONTEXT_B(_A && _B && _C);
|
||||||
|
|
||||||
|
CONTEXT_B(_T && _B && _C);
|
||||||
|
CONTEXT_B(_A && _T && _C);
|
||||||
|
CONTEXT_B(_A && _B && _T);
|
||||||
|
|
||||||
|
CONTEXT_B(_F && _B && _C);
|
||||||
|
CONTEXT_B(_A && _F && _C);
|
||||||
|
CONTEXT_B(_A && _B && _F);
|
||||||
|
|
||||||
|
CONTEXT_B(_T && _T && _C);
|
||||||
|
CONTEXT_B(_A && _T && _T);
|
||||||
|
CONTEXT_B(_T && _B && _T);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f2_B(int a, int b, int c)
|
||||||
|
/* OR */
|
||||||
|
{
|
||||||
|
printf("f2(%d, %d, %d)\n", a, b, c);
|
||||||
|
|
||||||
|
CONTEXT_B(_A || _B || _C);
|
||||||
|
|
||||||
|
CONTEXT_B(_T || _B || _C);
|
||||||
|
CONTEXT_B(_A || _T || _C);
|
||||||
|
CONTEXT_B(_A || _B || _T);
|
||||||
|
|
||||||
|
CONTEXT_B(_F || _B || _C);
|
||||||
|
CONTEXT_B(_A || _F || _C);
|
||||||
|
CONTEXT_B(_A || _B || _F);
|
||||||
|
|
||||||
|
CONTEXT_B(_F || _F || _C);
|
||||||
|
CONTEXT_B(_A || _F || _F);
|
||||||
|
CONTEXT_B(_F || _B || _F);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f3_B(int a, int b, int c, int d)
|
||||||
|
/* AND and OR */
|
||||||
|
{
|
||||||
|
printf("f3(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_B(_A && _B || _C && _D);
|
||||||
|
CONTEXT_B(_T && _T || _C && _D);
|
||||||
|
CONTEXT_B(_A && _B || _T && _T);
|
||||||
|
|
||||||
|
CONTEXT_B(_T && _B || _C && _D);
|
||||||
|
CONTEXT_B(_A && _T || _C && _D);
|
||||||
|
CONTEXT_B(_A && _B || _T && _D);
|
||||||
|
CONTEXT_B(_A && _B || _C && _T);
|
||||||
|
|
||||||
|
CONTEXT_B(_F && _B || _C && _D);
|
||||||
|
CONTEXT_B(_A && _F || _C && _D);
|
||||||
|
CONTEXT_B(_A && _B || _F && _D);
|
||||||
|
CONTEXT_B(_A && _B || _C && _F);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f4_B(int a, int b, int c, int d)
|
||||||
|
/* AND as top-level expression inside OR context */
|
||||||
|
{
|
||||||
|
printf("f4(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_B((_A && _B) || (_C && _D));
|
||||||
|
CONTEXT_B((_T && _T) || (_C && _D));
|
||||||
|
CONTEXT_B((_A && _B) || (_T && _T));
|
||||||
|
|
||||||
|
CONTEXT_B((_T && _B) || (_C && _D));
|
||||||
|
CONTEXT_B((_A && _T) || (_C && _D));
|
||||||
|
CONTEXT_B((_A && _B) || (_T && _D));
|
||||||
|
CONTEXT_B((_A && _B) || (_C && _T));
|
||||||
|
|
||||||
|
CONTEXT_B((_F && _B) || (_C && _D));
|
||||||
|
CONTEXT_B((_A && _F) || (_C && _D));
|
||||||
|
CONTEXT_B((_A && _B) || (_F && _D));
|
||||||
|
CONTEXT_B((_A && _B) || (_C && _F));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void f5_B(int a, int b, int c, int d)
|
||||||
|
/* OR as top-level expression inside AND context */
|
||||||
|
{
|
||||||
|
printf("f5(%d, %d, %d, %d)\n", a, b, c, d);
|
||||||
|
|
||||||
|
CONTEXT_B((_A || _B) && (_C || _D));
|
||||||
|
CONTEXT_B((_F || _F) && (_C || _D));
|
||||||
|
CONTEXT_B((_A || _B) && (_F || _F));
|
||||||
|
|
||||||
|
CONTEXT_B((_T || _B) && (_C || _D));
|
||||||
|
CONTEXT_B((_A || _T) && (_C || _D));
|
||||||
|
CONTEXT_B((_A || _B) && (_T || _D));
|
||||||
|
CONTEXT_B((_A || _B) && (_C || _T));
|
||||||
|
|
||||||
|
CONTEXT_B((_F || _B) && (_C || _D));
|
||||||
|
CONTEXT_B((_A || _F) && (_C || _D));
|
||||||
|
CONTEXT_B((_A || _B) && (_F || _D));
|
||||||
|
CONTEXT_B((_A || _B) && (_C || _F));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
f0();
|
||||||
|
|
||||||
|
f1(0, 0, 0);
|
||||||
|
f2(0, 0, 0);
|
||||||
|
f3(0, 0, 0, 0);
|
||||||
|
f4(0, 0, 0, 0);
|
||||||
|
f5(0, 0, 0, 0);
|
||||||
|
|
||||||
|
f1(1, 1, 1);
|
||||||
|
f2(1, 1, 1);
|
||||||
|
f3(1, 1, 1, 1);
|
||||||
|
f4(1, 1, 1, 1);
|
||||||
|
f5(1, 1, 1, 1);
|
||||||
|
|
||||||
|
f3(1, 0, 1, 0);
|
||||||
|
f4(1, 0, 1, 0);
|
||||||
|
f5(1, 0, 1, 0);
|
||||||
|
f3(0, 1, 0, 1);
|
||||||
|
f4(0, 1, 0, 1);
|
||||||
|
f5(0, 1, 0, 1);
|
||||||
|
|
||||||
|
f0_B();
|
||||||
|
|
||||||
|
f1_B(0, 0, 0);
|
||||||
|
f2_B(0, 0, 0);
|
||||||
|
f3_B(0, 0, 0, 0);
|
||||||
|
f4_B(0, 0, 0, 0);
|
||||||
|
f5_B(0, 0, 0, 0);
|
||||||
|
|
||||||
|
f1_B(1, 1, 1);
|
||||||
|
f2_B(1, 1, 1);
|
||||||
|
f3_B(1, 1, 1, 1);
|
||||||
|
f4_B(1, 1, 1, 1);
|
||||||
|
f5_B(1, 1, 1, 1);
|
||||||
|
|
||||||
|
f3_B(1, 0, 1, 0);
|
||||||
|
f4_B(1, 0, 1, 0);
|
||||||
|
f5_B(1, 0, 1, 0);
|
||||||
|
f3_B(0, 1, 0, 1);
|
||||||
|
f4_B(0, 1, 0, 1);
|
||||||
|
f5_B(0, 1, 0, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user