Esempio n. 1
0
static void CheckInitializer(AstInitializer init, Type ty)
{
	int offset = 0, error = 0;
	struct initData header;
	InitData tail = &header;
	InitData prev, curr;

	header.next = NULL;
	if (IsScalarType(ty) && init->lbrace)
	{
		init = (AstInitializer)init->initials;
	}
	else if (ty->categ == ARRAY && ! (ty->bty->categ == CHAR || ty->bty->categ == UCHAR))
	{
		if (! init->lbrace)
		{
			Error(&init->coord, "Can't initialize array without brace");
			return;
		}
	}
	else if ((ty->categ == STRUCT || ty->categ == UNION) && ! init->lbrace)
	{
		init->expr = Adjust(CheckExpression(init->expr), 1);
		if (! CanAssign(ty, init->expr))
		{
			Error(&init->coord, "Wrong initializer");
		}
		else
		{
			ALLOC(init->idata);
			init->idata->expr = init->expr;
			init->idata->offset = 0;
			init->idata->next = NULL;
		}
		return;
	}

	CheckInitializerInternal(&tail, init, ty, &offset, &error);
	if (error)
		return;

	init->idata = header.next;
	prev = NULL;
	curr = init->idata;
	while (curr)
	{
		if (prev != NULL && prev->offset == curr->offset)
		{
			prev->expr = BORBitField(prev->expr, curr->expr);
			prev->next = curr->next;
			curr = curr->next;
		}
		else
		{
			prev = curr;
			curr = curr->next;
		}
	}
}
Esempio n. 2
0
static AstExpression CheckConditionalExpression(AstExpression expr)
{
	int qual;
	Type ty1, ty2;

	expr->kids[0] = Adjust(CheckExpression(expr->kids[0]), 1);

	if (! IsScalarType(expr->kids[0]->ty))
	{
		Error(&expr->coord, "The first expression shall be scalar type.");
	}
	expr->kids[1]->kids[0] = Adjust(CheckExpression(expr->kids[1]->kids[0]), 1);
	expr->kids[1]->kids[1] = Adjust(CheckExpression(expr->kids[1]->kids[1]), 1);

	ty1 = expr->kids[1]->kids[0]->ty;
	ty2 = expr->kids[1]->kids[1]->ty;
	if (BothArithType(ty1, ty2))
	{
		expr->ty = CommonRealType(ty1, ty2);
		expr->kids[1]->kids[0] = Cast(expr->ty, expr->kids[1]->kids[0]);
		expr->kids[1]->kids[1] = Cast(expr->ty, expr->kids[1]->kids[1]);

		return FoldConstant(expr);
	}
	else if (IsRecordType(ty1) && ty1 == ty2)
	{
		expr->ty = ty1;
	}
	else if (ty1->categ == VOID && ty2->categ == VOID)
	{
		expr->ty = T(VOID);
	}
	else if (IsCompatiblePtr(ty1, ty2))
	{
		qual = ty1->bty->qual | ty2->bty->qual;
		expr->ty  = PointerTo(Qualify(qual, CompositeType(Unqual(ty1->bty), Unqual(ty2->bty))));
	}
	else if (IsPtrType(ty1) && IsNullConstant(expr->kids[1]->kids[1]))
	{
		expr->ty = ty1;
	}
	else if (IsPtrType(ty2) && IsNullConstant(expr->kids[1]->kids[0]))
	{
		expr->ty = ty2;
	}
	else if (NotFunctionPtr(ty1) && IsVoidPtr(ty2) ||
	         NotFunctionPtr(ty2) && IsVoidPtr(ty1))
	{
		qual = ty1->bty->qual | ty2->bty->qual;
		expr->ty = PointerTo(Qualify(qual, T(VOID)));
	}
	else
	{
		Error(&expr->coord, "invalid operand for ? operator.");
		expr->ty = T(INT);
	}

	return expr;
}
Esempio n. 3
0
/*
 * Unmarshal an array argument.
 *
 * @param msg   The message
 * @param sig   The array element signature
 * @param arg   Pointer to the structure to return the array
 */
static AJ_Status UnmarshalArray(AJ_Message* msg, const char** sig, AJ_Arg* arg, uint8_t pad)
{
    AJ_Status status;
    AJ_IOBuffer* ioBuf = &msg->bus->sock.rx;
    char typeId = **sig;
    uint32_t numBytes;

    /*
     * Get the byte count for the array
     */
    status = LoadBytes(ioBuf, 4, pad);
    if (status != AJ_OK) {
        return status;
    }
    EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1);
    numBytes = *((uint32_t*)ioBuf->readPtr);
    ioBuf->readPtr += 4;
    /*
     * We are already aligned on 4 byte boundary but there may be padding after the array length if
     * the array element types align on an 8 byte boundary.
     */
    pad = PadForType(typeId, ioBuf);
    status = LoadBytes(ioBuf, numBytes, pad);
    if (status != AJ_OK) {
        return status;
    }
    arg->val.v_data = ioBuf->readPtr;
    arg->sigPtr = *sig;
    arg->len = numBytes;
    if (IsScalarType(typeId)) {
        /*
         * For scalar types we do an inplace endian swap (if needed) and return a pointer into the read buffer.
         */
        EndianSwap(msg, typeId, (void*)arg->val.v_data, arg->len);
        ioBuf->readPtr += numBytes;
        arg->typeId = typeId;
        arg->flags = AJ_ARRAY_FLAG;
    } else {
        /*
         * For all other types the elements must be individually unmarshalled.
         */
        arg->typeId = AJ_ARG_ARRAY;
    }
    /*
     * Consume the array element signature.
     */
    *sig += CompleteTypeSigLen(*sig);
    return status;
}
Esempio n. 4
0
AJ_Status AJ_UnmarshalArgs(AJ_Message* msg, const char* sig, ...)
{
    AJ_Status status = AJ_OK;
    AJ_Arg arg;
    va_list argp;

    va_start(argp, sig);
    while (*sig) {
        uint8_t typeId = (uint8_t)*sig++;
        void* val = va_arg(argp, void*);

        if (!IsBasicType(typeId)) {
            status = AJ_ERR_UNEXPECTED;
            break;
        }
        status = AJ_UnmarshalArg(msg, &arg);
        if (status != AJ_OK) {
            break;
        }
        if (arg.typeId != typeId) {
            status = AJ_ERR_UNMARSHAL;
            break;
        }
        if (IsScalarType(typeId)) {
            switch (SizeOfType(typeId)) {
            case 1:
                *((uint8_t*)val) = *arg.val.v_byte;
                break;

            case 2:
                *((uint16_t*)val) = *arg.val.v_uint16;
                break;

            case 4:
                *((uint32_t*)val) = *arg.val.v_uint32;
                break;

            case 8:
                *((uint64_t*)val) = *arg.val.v_uint64;
                break;
            }
        } else {
            *((const char**)val) = arg.val.v_string;
        }
    }
    va_end(argp);
    return status;
}
Esempio n. 5
0
CastExpression_up CastExpression::CreateBaseTypeCast(
                                                Type cast_type,
                                                Expression_up cast_expression,
                                                bool is_explicit )
{
    Type expression_type = cast_expression->GetType().GetType();
    if( IsScalarType( expression_type ) )
        return Create( cast_type, std::move(cast_expression), is_explicit );

    assert( IsVectorType( expression_type ) &&
            "Unhandled type in CreateBaseTypeCase" );

    // Find the correct cast_type
    return Create( GetVectorType( cast_type,
                                  GetNumElementsInType( expression_type ) ),
                   std::move(cast_expression),
                   is_explicit );
}
Esempio n. 6
0
AJ_Status AJ_MarshalArgs(AJ_Message* msg, const char* sig, ...)
{
    AJ_Status status = AJ_OK;
    AJ_Arg arg;
    va_list argp;

    va_start(argp, sig);
    while (*sig) {
        uint8_t u8;
        uint16_t u16;
        uint32_t u32;
        uint64_t u64;
        uint8_t typeId = (uint8_t)*sig++;
        void* val;
        if (!IsBasicType(typeId)) {
            status = AJ_ERR_UNEXPECTED;
            break;
        }
        if (IsScalarType(typeId)) {
            if (SizeOfType(typeId) == 8) {
                u64 = va_arg(argp, uint64_t);
                val = &u64;
            } else if (SizeOfType(typeId) == 4) {
                u32 = va_arg(argp, uint32_t);
                val = &u32;
            } else if (SizeOfType(typeId) == 2) {
                u16 = (uint16_t)va_arg(argp, uint32_t);
                val = &u16;
            } else {
                u8 = (uint8_t)va_arg(argp, uint32_t);
                val = &u8;
            }
        } else {
            val = va_arg(argp, char*);
        }
        InitArg(&arg, typeId, val);
        status = AJ_MarshalArg(msg, &arg);
        if (status != AJ_OK) {
            break;
        }
    }
    va_end(argp);
    return status;
}
Esempio n. 7
0
static AstInitializer CheckInitializerInternal(InitData *tail, AstInitializer init, Type ty, 
                                               int *offset, int *error)
{
	AstInitializer p;
	int size = 0;
	InitData initd;

	if (IsScalarType(ty))
	{
		p = init;
		if (init->lbrace)
		{
			Error(&init->coord, "Can't use brace-enclosed initializer list for scalar");
			*error = 1;
			p = (AstInitializer)init->initials;
		}
		
		p->expr = Adjust(CheckExpression(p->expr), 1);
		if (! CanAssign(ty, p->expr))
		{
			Error(&init->coord, "Wrong initializer");
			*error = 1;
		}
		else
		{
			p->expr = Cast(ty, p->expr);
		}
		ALLOC(initd);
		initd->offset = *offset;
		initd->expr = p->expr;
		initd->next = NULL;
		(*tail)->next = initd;
		*tail = initd;

		return (AstInitializer)init->next;
	}
	else if (ty->categ == UNION)
	{
		p = init->lbrace ? (AstInitializer)init->initials : init;
		ty = ((RecordType)ty)->flds->ty;

		p = CheckInitializerInternal(tail, p, ty, offset, error);

		if (init->lbrace)
		{
			if (p != NULL)
			{
				Error(&init->coord, "too many initializer for union");
			}
			return (AstInitializer)init->next;
		}

		return p;
	}
	else if (ty->categ == ARRAY)
	{
		int start = *offset;
		p = init->lbrace ? (AstInitializer)init->initials : init;

		if (((init->lbrace && ! p->lbrace && p->next == NULL) || ! init->lbrace) &&
		    p->expr->op == OP_STR && ty->categ / 2 == p->expr->ty->categ / 2)
		{
			size = p->expr->ty->size;
			if (ty->size == 0 || ty->size == size)
			{
				ty->size = size;
			}
			else if (ty->size == size - 1)
			{
				p->expr->ty->size = size - 1;
			}
			else if (ty->size < size)
			{
				Error(&init->coord, "string is too long");
				*error = 1;
			}
			ALLOC(initd);
			initd->offset = *offset;
			initd->expr = p->expr;
			initd->next = NULL;
			(*tail)->next = initd;
			*tail = initd;

			return (AstInitializer)init->next;
		}

		while (p != NULL)
		{
			p = CheckInitializerInternal(tail, p, ty->bty, offset, error);
			size += ty->bty->size;
			*offset = start + size;
			if (ty->size == size)
				break;
		}
		
		if (ty->size == 0)
		{
			ty->size = size;
		}
		else if (ty->size < size)
		{
			Error(&init->coord, "too many initializer");
			*error = 1;
		}
	
		if (init->lbrace)
		{
			return (AstInitializer)init->next;
		}
		return p;
	}
	else if (ty->categ == STRUCT)
	{
		int start = *offset;
		Field fld = ((RecordType)ty)->flds;
		p = init->lbrace ? (AstInitializer)init->initials : init;
		
		while (fld && p)
		{
			*offset = start + fld->offset;
			p = CheckInitializerInternal(tail, p, fld->ty, offset, error);
			if (fld->bits != 0)
			{
				(*tail)->expr = PlaceBitField(fld, (*tail)->expr);
			}
			fld = fld->next;
		}

		if (init->lbrace)
		{
			if (p != NULL)
			{
				Error(&init->coord, "too many initializer");
				*error = 1;
			}
			*offset = ty->size;
			return (AstInitializer)init->next;
		}

		return (AstInitializer)p;
	}

	return init;
}
Esempio n. 8
0
GLOBAL void ConstFoldCast(Node *node)
{
  Node *expr;
  Node *from_type, *to_type;
  BasicType from_basic, to_basic;

  /* this function works on both casts and implicitcasts */
  switch (node->typ) {
  case Cast:
    expr = node->u.cast.expr;
    break;
  case ImplicitCast:
    expr = node->u.implicitcast.expr;
    if (expr == NULL)
      return;
    break;
  default:
    UNREACHABLE;
  }

  if (!NodeIsConstant(expr))
    return;

  to_type = NodeDataType(node);
  from_type = NodeDataType(expr);


  /* can only constant-fold scalar expressions (integral, floating,
     and pointer) */

  if (IsScalarType(to_type) && IsScalarType(from_type)) {
    from_basic = BasicTypeOfConstantValue(from_type);
    to_basic = BasicTypeOfConstantValue(to_type);

    switch (to_basic) {
    case Slonglong:
    case Ulonglong:
    case Longdouble:
      /* fix: cannot represent these types internally, so no constant-folding
	 occurs. */
      return;
    default:
      break;
    }

    switch (from_basic) {
    case Sint:
      { int eval = NodeConstantSintValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    case Uint:
      { unsigned eval = NodeConstantUintValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    case Slong:
      { long eval = NodeConstantSlongValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    case Ulong:
      { unsigned long eval = NodeConstantUlongValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    case Float:
      { float eval = NodeConstantFloatValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    case Double:
      { double eval = NodeConstantDoubleValue(expr);
	switch (to_basic) {
	case Sint:
	  NodeSetSintValue(node, eval);   return;
	case Uint:
	  NodeSetUintValue(node, eval);   return;
	case Slong:
	  NodeSetSlongValue(node, eval);  return;
	case Ulong:
	  NodeSetUlongValue(node, eval);  return;
	case Float:
	  NodeSetFloatValue(node, eval);  return;
	case Double:
	  NodeSetDoubleValue(node, eval); return;
	default:
	  UNREACHABLE;
	}
      }
    default:
      UNREACHABLE;
    }
  }
}
Esempio n. 9
0
/*
 * Unmarshal a single argument
 */
static AJ_Status Unmarshal(AJ_Message* msg, const char** sig, AJ_Arg* arg)
{
    AJ_Status status;
    AJ_IOBuffer* ioBuf = &msg->bus->sock.rx;
    char typeId;
    uint32_t pad;
    uint32_t sz;

    memset(arg, 0, sizeof(AJ_Arg));

    if (!*sig || !**sig) {
        return AJ_ERR_END_OF_DATA;
    }

    typeId = **sig;
    *sig += 1;
    pad = PadForType(typeId, ioBuf);

    if (IsScalarType(typeId)) {
        sz = SizeOfType(typeId);
        status = LoadBytes(ioBuf, sz, pad);
        if (status != AJ_OK) {
            return status;
        }
        /*
         * For numeric types we just return a pointer into the buffer
         */
        arg->typeId = typeId;
        arg->val.v_byte = ioBuf->readPtr;
        arg->len = 0;
        ioBuf->readPtr += sz;
        EndianSwap(msg, typeId, (void*)arg->val.v_data, 1);
    } else if (TYPE_FLAG(typeId) & (AJ_STRING | AJ_VARIANT)) {
        /*
         * Length field for a signature is 1 byte, for regular strings its 4 bytes
         */
        uint32_t lenSize = ALIGNMENT(typeId);
        /*
         * Read the string length. Note the length doesn't include the terminating NUL
         * so an empty string in encoded as two zero bytes.
         */
        status = LoadBytes(ioBuf, lenSize, pad);
        if (status != AJ_OK) {
            return status;
        }
        if (lenSize == 4) {
            EndianSwap(msg, AJ_ARG_UINT32, ioBuf->readPtr, 1);
            sz = *((uint32_t*)ioBuf->readPtr);
        } else {
            sz = (uint32_t)(*ioBuf->readPtr);
        }
        ioBuf->readPtr += lenSize;
        status = LoadBytes(ioBuf, sz + 1, 0);
        if (status != AJ_OK) {
            return status;
        }
        arg->typeId = typeId;
        arg->len = sz;
        arg->val.v_string = (char*)ioBuf->readPtr;
        ioBuf->readPtr += sz + 1;
        /*
         * If unmarshalling a variant store offset to start of signature
         */
        if (typeId == AJ_ARG_VARIANT) {
            msg->varOffset = (uint8_t)(sz + 1);
        }
    } else if (typeId == AJ_ARG_ARRAY) {
        status = UnmarshalArray(msg, sig, arg, pad);
    } else if ((typeId == AJ_ARG_STRUCT) || (typeId == AJ_ARG_DICT_ENTRY)) {
        arg->typeId = typeId;
        status = UnmarshalStruct(msg, sig, arg, pad);
    } else {
        status = AJ_ERR_UNMARSHAL;
    }
    return status;
}
Esempio n. 10
0
static AJ_Status Marshal(AJ_Message* msg, const char** sig, AJ_Arg* arg)
{
    AJ_Status status = AJ_OK;
    AJ_IOBuffer* ioBuf = &msg->bus->sock.tx;
    char typeId = **sig;
    uint32_t pad = PadForType(typeId, ioBuf);
    size_t sz;

    if (!arg) {
        return AJ_ERR_NULL;
    }
    *sig += 1;
    if (IsScalarType(arg->typeId)) {
        if (arg->flags & AJ_ARRAY_FLAG) {
            if ((typeId != AJ_ARG_ARRAY) || (**sig != arg->typeId)) {
                return AJ_ERR_MARSHAL;
            }
            *sig += 1;
            sz = arg->len;
            status = WriteBytes(msg, &sz, 4, pad);
            if (status == AJ_OK) {
                /*
                 * May need to pad if the elements required 8 byte alignment
                 */
                pad = PadForType(arg->typeId, ioBuf);
            }
        } else {
            if (typeId != arg->typeId) {
                return AJ_ERR_MARSHAL;
            }
            sz = SizeOfType(typeId);
        }
        if (status == AJ_OK) {
            status = WriteBytes(msg, arg->val.v_data, sz, pad);
        }
    } else if (TYPE_FLAG(typeId) & (AJ_STRING | AJ_VARIANT)) {
        if (typeId != arg->typeId) {
            return AJ_ERR_MARSHAL;
        }
        sz = arg->len ? arg->len : strlen(arg->val.v_string);
        /*
         * Length field for a signature is 1 byte, for regular strings its 4 bytes
         */
        if (ALIGNMENT(typeId) == 1) {
            uint8_t szu8 = (uint8_t)sz;
            if (sz > 255) {
                return AJ_ERR_MARSHAL;
            }
            status = WriteBytes(msg, &szu8, 1, pad);
        } else {
            status = WriteBytes(msg, &sz, 4, pad);
        }
        if (status == AJ_OK) {
            status = WriteBytes(msg, arg->val.v_string, sz, 0);
            /*
             * String must be NUL terminated on the wire
             */
            if (status == AJ_OK) {
                status = WritePad(msg, 1);
            }
            /*
             * If marshalling a variant store offset to start of signature
             */
            if (typeId == AJ_ARG_VARIANT) {
                msg->varOffset = (uint8_t)(sz + 1);
            }
        }
    } else if (TYPE_FLAG(typeId) & AJ_CONTAINER) {
        if (typeId != arg->typeId) {
            return AJ_ERR_MARSHAL;
        }
        status = MarshalContainer(msg, sig, arg, pad);
    } else {
        return AJ_ERR_MARSHAL;
    }
    return status;
}
Esempio n. 11
0
static AstExpression CheckUnaryExpression(AstExpression expr)
{
	Type ty;

	switch (expr->op)
	{
	case OP_PREINC:
	case OP_PREDEC:
		return TransformIncrement(expr);

	case OP_ADDRESS:
		expr->kids[0] = CheckExpression(expr->kids[0]);
		ty = expr->kids[0]->ty;
		if (expr->kids[0]->op == OP_DEREF)
		{
			expr->kids[0]->kids[0]->lvalue = 0;
			return expr->kids[0]->kids[0];
		}
		else if (expr->kids[0]->op == OP_INDEX)
		{
			expr->kids[0]->op = OP_ADD;
			expr->kids[0]->ty = PointerTo(ty);
			expr->kids[0]->lvalue = 0;
			return expr->kids[0];
		}
		else if (IsFunctionType(ty) || 
			     (expr->kids[0]->lvalue && ! expr->kids[0]->bitfld && ! expr->kids[0]->inreg))
		{
			expr->ty = PointerTo(ty);
			return expr;
		}
		break;

	case OP_DEREF:
		expr->kids[0] = Adjust(CheckExpression(expr->kids[0]), 1);
		ty = expr->kids[0]->ty;
		if (expr->kids[0]->op == OP_ADDRESS)
		{
			expr->kids[0]->kids[0]->ty = ty->bty;
			return expr->kids[0]->kids[0];
		}
		else if (expr->kids[0]->op == OP_ADD && expr->kids[0]->kids[0]->isarray)
		{
			expr->kids[0]->op = OP_INDEX;
			expr->kids[0]->ty = ty->bty;
			expr->kids[0]->lvalue = 1;
			return expr->kids[0];
		}
		if (IsPtrType(ty))
		{
			expr->ty = ty->bty;
			if (IsFunctionType(expr->ty))
			{
				return expr->kids[0];
			}
			expr->lvalue = 1;
			return expr;
		}
		break;

	case OP_POS:
	case OP_NEG:
		expr->kids[0] = Adjust(CheckExpression(expr->kids[0]), 1);
		if (IsArithType(expr->kids[0]->ty))
		{
			expr->kids[0] = DoIntegerPromotion(expr->kids[0]);
			expr->ty = expr->kids[0]->ty;
			return expr->op == OP_POS ? expr->kids[0] : FoldConstant(expr);
		}
		break;

	case OP_COMP:
		expr->kids[0] = Adjust(CheckExpression(expr->kids[0]), 1);
		if (IsIntegType(expr->kids[0]->ty))
		{
			expr->kids[0] = DoIntegerPromotion(expr->kids[0]);
			expr->ty = expr->kids[0]->ty;
			return FoldConstant(expr);
		}
		break;

	case OP_NOT:
		expr->kids[0] = Adjust(CheckExpression(expr->kids[0]), 1);
		if (IsScalarType(expr->kids[0]->ty))
		{
			expr->ty = T(INT);
			return FoldConstant(expr);
		}
		break;

	case OP_SIZEOF:
		if (expr->kids[0]->kind == NK_Expression)
		{
			expr->kids[0] = CheckExpression(expr->kids[0]);
			if (expr->kids[0]->bitfld)
				goto err;
			ty = expr->kids[0]->ty;
		}
		else
		{
			ty = CheckTypeName((AstTypeName)expr->kids[0]);
		}
		if (IsFunctionType(ty) || ty->size == 0)
			goto err;

		expr->ty = T(UINT);
		expr->op = OP_CONST;
		expr->val.i[0] = ty->size;
		return expr;

	case OP_CAST:
		return CheckTypeCast(expr);

	default:
		assert(0);
	}

err:
	REPORT_OP_ERROR;

}