// -*- mode: java; c-basic-offset: 4 -*- // // Copyright 2001-2002 by the Regents of the University of California. // All rights reserved. // // HARMONIA: C language module type checking // // RCS Info: $Revision: 1.1 $ on $Date: 2003/05/12 01:49:33 $ // $Source: /home/cs/harmonia/cvsroot/www/harmonia/projects/langs/c/c-typecheck.def,v $ // // Not usable yet, alas: // -*- mode: harmonia-astdef2; c-basic-offset: 4 -*- import "Node.def"; import "ParentNode.def"; import "ListNode.def"; import "AmbigNode.def"; import "GLRStateMixin.def"; include "common/stl.h" include "common/PooledString.h" include "lk/node/UltraRoot.h" include "c.h" phylum trans_unit { public virtual method void check_types(TypecheckContext *ctx) { } } // trans_unit -> SeqR0E0star:ext_decls operator TranslationUnit extends trans_unit { public virtual method void check_types(TypecheckContext *ctx) { for (ext_decls_iterator i = get_ext_decls(); i; ++i) i.get_ext_decl()->check_types(ctx); } } operator no_trans_unit extends trans_unit { } operator trans_unit_sym extends trans_unit { public virtual method void check_types(TypecheckContext *ctx) { trans_unit::phylum_cast(primary_alternative())->check_types(ctx); } } phylum ext_decl { public virtual method void check_types(TypecheckContext *ctx) { } } // ext_decl -> SeqR1E0star:specs declr:declr SeqR1E2star:decls comp_stmt:body operator FunctionDefinition extends ext_decl { public virtual method void check_types(TypecheckContext *ctx) { decl::TypeInfo base_type_info; for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->check_types(ctx); for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->specify(ctx, &base_type_info); CType *base_type = decl::assemble_base_type(ctx, this, &base_type_info); CType *maybe_func_type = get_declr()->build_type(ctx, base_type); if (!maybe_func_type->is_function()) { set_semant_error(this, "Function definition must have " "function type, not %s", maybe_func_type->name().c_str()); return; } FunctionType *func_type = (FunctionType *)maybe_func_type; CType *ret_type = func_type->return_type; Localizer save(&ctx->return_type); ctx->return_type = ret_type; get_body()->check_types(ctx); } } // ext_decl -> decl:decl operator OtherExtDeclaration extends ext_decl { public virtual method void check_types(TypecheckContext *ctx) { get_decl()->check_types(ctx); } } operator no_ext_decl extends ext_decl { } operator ext_decl_sym extends ext_decl { public virtual method void check_types(TypecheckContext *ctx) { ext_decl::phylum_cast(primary_alternative())->check_types(ctx); } } phylum decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) {} public virtual method void check_types(TypecheckContext *ctx) {} } // decl_spec -> stor_class_spec:spec operator StorageDeclSpec extends decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { get_spec()->specify(ctx, base_info); } } // decl_spec -> type_spec:spec operator TypeSpecDeclSpec extends decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { get_spec()->specify(ctx, base_info); } public virtual method void check_types(TypecheckContext *ctx) { get_spec()->check_types(ctx); } } // decl_spec -> type_qual:qual operator TypeQualDeclSpec extends decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { get_qual()->specify(base_info); } } // decl_spec -> INLINE:qual operator FunctionQualDeclSpec extends decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { // base_info->is_inline = true; } } operator no_decl_spec extends decl_spec { } operator decl_spec_sym extends decl_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { decl_spec::phylum_cast(primary_alternative())->specify(ctx, base_info); } public virtual method void check_types(TypecheckContext *ctx) { decl_spec::phylum_cast(primary_alternative())->check_types(ctx); } } phylum declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return base_type; } } // declr -> OptR46E0:ptr direct_declr:direct operator Declarator extends declr { public slot CType *c_type; versioned Semantics attribute type_name = TypedVal(c_type ? strdup(c_type->name().c_str()) : "null"); public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { CType *type = base_type; if (has_ptr()) type = get_ptr_ptr()->point_to(ctx, type); type = get_direct()->build_type(ctx, type); Declarator *link = (Declarator *)linkage_link.value(); if (link) { CType *comp = CType::composite_type(link->c_type, type); if (!comp) set_semant_error(this, "Identifier redefined with " "incompatible type %s (was %s)", type->name().c_str(), link->c_type->name().c_str()); else type = comp; } else if (decl_context == KnR_PARAM || decl_context == DEF_PARAM || decl_context == DECL_PARAM) { type = type->param_adjust(); } c_type = type; return type; } } operator no_declr extends declr { } operator declr_sym extends declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return declr::phylum_cast(primary_alternative()) ->build_type(ctx, base_type); } } phylum decl { public enum TypeBits { VOID = 1, CHAR = 2, SHORT = 4, INT = 8, LONG = 16, LONG_LONG = 32, FLOAT = 64, DOUBLE = 128, SIGNED = 256, UNSIGNED = 512, _BOOL = 1024, _COMPLEX = 2048, _IMAGINARY = 4096, STRUCT_UNION_ENUM = 8192, TYPEDEF_NAME = 16384, TYPEDEF_TYPEDEF = 32768 }; public enum AggrDeclType { NO_AGGREGATE, AGGREGATE_REF, AGGREGATE_DEF }; public struct TypeInfo : public Collectable { StorageClass storage; int spec_bits; AggrDeclType aggregate; unsigned int /* Qualifiers */ quals; CType *specified_type; TypeInfo() : storage(NO_STORAGE), spec_bits(0), aggregate(NO_AGGREGATE), quals(0), specified_type(0) {} } public virtual method void check_types(TypecheckContext *ctx) { } public static method CType *assemble_base_type(TypecheckContext *ctx, Node *node, TypeInfo *info) { CType *base_type; if (info->spec_bits & (_COMPLEX|_IMAGINARY) && !(info->spec_bits & (FLOAT|DOUBLE))) set_semant_error(node, "Only floating-point types can be " "'_Complex' or '_Imaginary'"); if (info->spec_bits & VOID) { base_type = &ctx->the_VoidType; } else if (info->spec_bits & CHAR) { if (info->spec_bits & SIGNED) base_type = &ctx->the_SignedCharType; else if (info->spec_bits & UNSIGNED) base_type = &ctx->the_UnsignedCharType; else base_type = &ctx->the_PlainCharType; } else if (info->spec_bits & SHORT) { if (info->spec_bits & UNSIGNED) base_type = &ctx->the_UnsignedShortType; else base_type = &ctx->the_ShortIntType; } else if (info->spec_bits & FLOAT) { if (info->spec_bits & _COMPLEX) base_type = &ctx->the_ComplexFloatType; else if (info->spec_bits & _IMAGINARY) base_type = &ctx->the_ImaginaryFloatType; else base_type = &ctx->the_FloatType; } else if (info->spec_bits & DOUBLE) { if (info->spec_bits & LONG) { if (info->spec_bits & _COMPLEX) base_type = &ctx->the_ComplexLongDoubleType; else if (info->spec_bits & _IMAGINARY) base_type = &ctx->the_ImaginaryLongDoubleType; else base_type = &ctx->the_LongDoubleType; } else { if (info->spec_bits & _COMPLEX) base_type = &ctx->the_ComplexDoubleType; else if (info->spec_bits & _IMAGINARY) base_type = &ctx->the_ImaginaryDoubleType; else base_type = &ctx->the_DoubleType; } } else if (info->spec_bits & LONG_LONG) { if (info->spec_bits & UNSIGNED) base_type = &ctx->the_UnsignedLongLongType; else base_type = &ctx->the_LongLongIntType; } else if (info->spec_bits & LONG) { if (info->spec_bits & UNSIGNED) base_type = &ctx->the_UnsignedLongType; else base_type = &ctx->the_LongIntType; } else if (info->spec_bits & INT) { if (info->spec_bits & UNSIGNED) base_type = &ctx->the_UnsignedIntType; else base_type = &ctx->the_SignedIntType; // XXX bitfields } else if (info->spec_bits & _BOOL) { base_type = &ctx->the_BoolType; } else if (info->spec_bits & UNSIGNED) { base_type = &ctx->the_UnsignedIntType; } else if (info->spec_bits & SIGNED) { base_type = &ctx->the_SignedIntType; } else if (info->spec_bits & TYPEDEF_NAME) { if (info->specified_type) base_type = info->specified_type; else { set_semant_error(node, "Undefined typename"); base_type = &ctx->the_UnimplementedType; } } else if (info->spec_bits & STRUCT_UNION_ENUM) { if (info->specified_type) base_type = info->specified_type; else { base_type = &ctx->the_UnimplementedType; } } else if (info->spec_bits) { base_type = &ctx->the_UnimplementedType; } else { set_semant_error(node, "C99 forbids a declaration with no type"); base_type = &ctx->the_SignedIntType; } base_type = base_type->qualified_by(info->quals); return base_type; } } // decl -> SeqR1E0star:specs SeqR7E1star:declrs SEMI operator Declaration extends decl { public virtual method void check_types(TypecheckContext *ctx) { TypeInfo base_type_info; for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->check_types(ctx); for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->specify(ctx, &base_type_info); CType *base_type = assemble_base_type(ctx, this, &base_type_info); //string msg = "Base type: " + base_type->name(); //set_string_prop(MOUSE_OVER_MSG, msg.c_str()); //compute_synth_attrs(true); bool has_declrs = get_declrs(); if (base_type_info.aggregate == NO_AGGREGATE && !has_declrs) set_semant_error(this, "Declaration declares neither an aggregate" " nor any declarators"); for (declrs_iterator i = get_declrs(); i; ++i) i.get_declr()->check_types(ctx, base_type); } } operator no_decl extends decl { } operator decl_sym extends decl { public virtual method void check_types(TypecheckContext *ctx) { decl::phylum_cast(primary_alternative())->check_types(ctx); } } phylum comp_stmt { public virtual method void check_types(TypecheckContext *ctx) { } } // comp_stmt -> LBRACE SeqR87E1star:items RBRACE operator BlockStatement extends comp_stmt { public virtual method void check_types(TypecheckContext *ctx) { for (items_iterator i = get_items(); i; ++i) i.get_item_()->check_types(ctx); } } operator no_comp_stmt extends comp_stmt { } operator comp_stmt_sym extends comp_stmt { public virtual method void check_types(TypecheckContext *ctx) { comp_stmt::phylum_cast(primary_alternative())->check_types(ctx); } } phylum stor_class_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { } } // stor_class_spec -> AUTO operator AutoStrClassSpec extends stor_class_spec { } // stor_class_spec -> REGISTER operator RegisterStrClassSpec extends stor_class_spec { } // stor_class_spec -> STATIC operator StaticStrClassSpec extends stor_class_spec { } // stor_class_spec -> EXTERN operator ExternStrClassSpec extends stor_class_spec { } // stor_class_spec -> TYPEDEF operator TypedefStrClassSpec extends stor_class_spec { } operator no_stor_class_spec extends stor_class_spec { } operator stor_class_spec_sym extends stor_class_spec { } phylum type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { error("Unexpected call to type_spec::specify\n"); } public virtual method void check_types(TypecheckContext *ctx) {} public virtual method StructUnionType *get_struct_union_type() { error("Unexpected call to type_spec::get_struct_union_type\n"); return 0; } } // type_spec -> VOID operator VoidTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else base_info->spec_bits |= decl::VOID; } } // type_spec -> CHAR operator CharTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "Too many 'char's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::INT) set_semant_error(this, "'char' and 'int' are mutually exclusive"); else if (base_info->spec_bits & decl::FLOAT) set_semant_error(this, "'char' and 'float' are " "mutually exclusive"); else if (base_info->spec_bits & decl::DOUBLE) set_semant_error(this, "'char' and 'double' are " "mutually exclusive"); else if (base_info->spec_bits & decl::SHORT) set_semant_error(this, "'char's can't be 'short'"); else if (base_info->spec_bits & decl::LONG) set_semant_error(this, "'char's can't be 'long'"); else if (base_info->spec_bits & decl::_COMPLEX) set_semant_error(this, "Only floating-point types " "can be '_Complex'"); else if (base_info->spec_bits & decl::_IMAGINARY) set_semant_error(this, "Only floating-point types " "can be '_Imaginary'"); else base_info->spec_bits |= decl::CHAR; } } // type_spec -> SHORT operator ShortTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::SHORT) set_semant_error(this, "Too many 'short's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::LONG) set_semant_error(this, "'short' and 'long' are " "mutually exclusive"); else if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "'char's can't be 'short'"); else if (base_info->spec_bits & decl::_COMPLEX) set_semant_error(this, "Only floating-point types " "can be '_Complex'"); else if (base_info->spec_bits & decl::_IMAGINARY) set_semant_error(this, "Only floating-point types " "can be '_Imaginary'"); else base_info->spec_bits |= decl::SHORT; } } // type_spec -> INT operator IntTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::INT) set_semant_error(this, "Too many 'int's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "'char' and 'int' are mutually exclusive"); else if (base_info->spec_bits & decl::FLOAT) set_semant_error(this, "'float' and 'int' are mutually exclusive"); else if (base_info->spec_bits & decl::DOUBLE) set_semant_error(this, "'double' and 'int' are " "mutually exclusive"); else if (base_info->spec_bits & decl::_COMPLEX) set_semant_error(this, "Only floating-point types " "can be '_Complex'"); else if (base_info->spec_bits & decl::_IMAGINARY) set_semant_error(this, "Only floating-point types " "can be '_Imaginary'"); else base_info->spec_bits |= decl::INT; } } // type_spec -> LONG operator LongTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::LONG_LONG) set_semant_error(this, "Too many 'longs's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::SHORT) set_semant_error(this, "'short' and 'long' are " "mutually exclusive"); else if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "'char's can't be 'long'"); else if (base_info->spec_bits & decl::FLOAT) set_semant_error(this, "'float's can't be 'long'"); else if (base_info->spec_bits & (decl::DOUBLE|decl::_COMPLEX|decl::_IMAGINARY) && base_info->spec_bits & decl::LONG) set_semant_error(this, "Only integers can be 'long long'"); else { if (base_info->spec_bits & decl::LONG) base_info->spec_bits |= decl::LONG_LONG; else base_info->spec_bits |= decl::LONG; } } } // type_spec -> FLOAT operator FloatTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::FLOAT) set_semant_error(this, "Too many 'float's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "'char' and 'float' are " "mutually exclusive"); else if (base_info->spec_bits & decl::INT) set_semant_error(this, "'float' and 'int' are mutually exclusive"); else if (base_info->spec_bits & decl::DOUBLE) set_semant_error(this, "'float' and 'double' are " "mutually exclusive"); else if (base_info->spec_bits & decl::SHORT) set_semant_error(this, "'float's can't be 'short'"); else if (base_info->spec_bits & decl::LONG) set_semant_error(this, "'float's can't be 'long'"); else if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "Floating point types can't be " "declared 'signed'"); else if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "Floating point types can't be 'unsigned'"); else base_info->spec_bits |= decl::FLOAT; } } // type_spec -> DOUBLE operator DoubleTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::DOUBLE) set_semant_error(this, "Too many 'double's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::CHAR) set_semant_error(this, "'char' and 'double' are " "mutually exclusive"); else if (base_info->spec_bits & decl::INT) set_semant_error(this, "'double' and 'int' are " "mutually exclusive"); else if (base_info->spec_bits & decl::FLOAT) set_semant_error(this, "'float' and 'double' are " "mutually exclusive"); else if (base_info->spec_bits & decl::SHORT) set_semant_error(this, "'double's can't be 'short'"); else if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "Floating point types can't be " "declared 'signed'"); else if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "Floating point types can't be 'unsigned'"); else if (base_info->spec_bits & decl::LONG_LONG) set_semant_error(this, "Only integers can be 'long long'"); else base_info->spec_bits |= decl::DOUBLE; } } // type_spec -> SIGNED operator SignedTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "Too many 'signed's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "'signed' and 'unsigned' are mutually " "exclusive"); else if (base_info->spec_bits & (decl::FLOAT|decl::DOUBLE)) set_semant_error(this, "Floating point types can't be " "declared 'signed'"); else base_info->spec_bits |= decl::SIGNED; } } // type_spec -> UNSIGNED operator UnsignedTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "Too many 'unsigned's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "'signed' and 'unsigned' are mutually " "exclusive"); else if (base_info->spec_bits & (decl::FLOAT|decl::DOUBLE)) set_semant_error(this, "Floating point types can't be 'unsigned'"); else base_info->spec_bits |= decl::UNSIGNED; } } // type_spec -> _BOOL operator BooleanTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else base_info->spec_bits |= decl::_BOOL; } } // type_spec -> _COMPLEX operator ComplexTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::_COMPLEX) set_semant_error(this, "Too many '_Complex'es in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_IMAGINARY) set_semant_error(this, "'_Complex' and '_Imaginary' are " "mutually exclusive"); else if (base_info->spec_bits & (decl::CHAR|decl::INT|decl::SHORT)) set_semant_error(this, "Only floating-point types " "can be '_Complex'"); else if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "Floating point types can't be " "declared 'signed'"); else if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "Floating point types can't be 'unsigned'"); else if (base_info->spec_bits & decl::LONG_LONG) set_semant_error(this, "Only integers can be 'long long'"); else base_info->spec_bits |= decl::_COMPLEX; } } // type_spec -> _IMAGINARY operator ImaginaryTypeSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::_IMAGINARY) set_semant_error(this, "Too many '_Imaginary's in type"); else if (base_info->spec_bits & decl::STRUCT_UNION_ENUM) set_semant_error(this, "A struct, union, or enum specifier is not" " allowed with any other type specifier"); else if (base_info->spec_bits & decl::VOID) set_semant_error(this, "'void' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_BOOL) set_semant_error(this, "'_Bool' is not allowed with " "any other type specifier"); else if (base_info->spec_bits & decl::_COMPLEX) set_semant_error(this, "'_Complex' and '_Imaginary' are " "mutually exclusive"); else if (base_info->spec_bits & (decl::CHAR|decl::INT|decl::SHORT)) set_semant_error(this, "Only floating-point types " "can be '_Imaginary'"); else if (base_info->spec_bits & decl::SIGNED) set_semant_error(this, "Floating point types can't be " "declared 'signed'"); else if (base_info->spec_bits & decl::UNSIGNED) set_semant_error(this, "Floating point types can't be 'unsigned'"); else if (base_info->spec_bits & decl::LONG_LONG) set_semant_error(this, "Only integers can be 'long long'"); else base_info->spec_bits |= decl::_IMAGINARY; } } // type_spec -> STRUCT OptR28E1:name LBRACE SeqR28E3star:decls RBRACE operator StructDefinitionSpec extends type_spec { public slot CompleteStructUnionType struct_type; public virtual method StructUnionType *get_struct_union_type() { return &struct_type; } public virtual method void check_types(TypecheckContext *ctx) { if (has_name()) struct_type.tag = get_name_name()->pooled_string(); else struct_type.tag = "(unnamed)"; struct_type.is_union = false; for (decls_iterator i = get_decls(); i; ++i) i.get_decl()->check_member(ctx, &struct_type); } public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "A struct specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_DEF; base_info->specified_type = &struct_type; } } } // type_spec -> UNION OptR28E1:name LBRACE SeqR28E3star:decls RBRACE operator UnionDefinitionSpec extends type_spec { public slot CompleteStructUnionType union_type; public virtual method StructUnionType *get_struct_union_type() { return &union_type; } public virtual method void check_types(TypecheckContext *ctx) { if (has_name()) union_type.tag = get_name_name()->pooled_string(); else union_type.tag = "(unnamed)"; union_type.is_union = true; for (decls_iterator i = get_decls(); i; ++i) i.get_decl()->check_member(ctx, &union_type); } public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "A union specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_DEF; base_info->specified_type = &union_type; } } } // type_spec -> STRUCT IDSYM:name operator StructReferenceSpec extends type_spec { public slot StructUnionType *struct_type; public virtual method StructUnionType *get_struct_union_type() { return struct_type; } public virtual method void check_types(TypecheckContext *ctx) { Node *def = (Node *)definition.value(); if (def) struct_type = ((StructDefinitionSpec*)def) ->get_struct_union_type(); else { CompleteStructUnionType *complete_type = 0; if (completion.value()) { complete_type = (CompleteStructUnionType *) (((StructDefinitionSpec *)completion.value()) ->get_struct_union_type()); } struct_type = new IncompleteStructUnionType(get_name()->pooled_string(), false, complete_type); } } public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "A struct specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_REF; base_info->specified_type = struct_type; } } } // type_spec -> UNION IDSYM:name operator UnionReferenceSpec extends type_spec { public slot StructUnionType *union_type; public virtual method StructUnionType *get_struct_union_type() { return union_type; } public virtual method void check_types(TypecheckContext *ctx) { Node *def = (Node *)definition.value(); if (def) union_type = ((StructDefinitionSpec*)def) ->get_struct_union_type(); else { CompleteStructUnionType *complete_type = 0; if (completion.value()) { complete_type = (CompleteStructUnionType *) (((UnionDefinitionSpec *)completion.value()) ->get_struct_union_type()); } union_type = new IncompleteStructUnionType(get_name()->pooled_string(), true, complete_type); } } public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "A union specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_REF; base_info->specified_type = union_type; } } } // type_spec -> ENUM OptR28E1:name LBRACE SeqR32E3star:enums OptR32E4 RBRACE operator DefinedEnumSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "An enum specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_DEF; base_info->specified_type = &ctx->the_SignedIntType; } } } // type_spec -> ENUM IDSYM:name operator ReferencedEnumSpec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits) set_semant_error(this, "An enum specifier is not allowed " "with any other type specifier"); else { base_info->spec_bits |= decl::STRUCT_UNION_ENUM; assert(base_info->aggregate == decl::NO_AGGREGATE); base_info->aggregate = decl::AGGREGATE_REF; base_info->specified_type = &ctx->the_SignedIntType; } } } // type_spec -> IDSYM:type_name operator TypedefTypeSpec extends type_spec depends on Declarator { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { if (base_info->spec_bits & decl::TYPEDEF_NAME) base_info->spec_bits |= decl::TYPEDEF_TYPEDEF; else base_info->spec_bits |= decl::TYPEDEF_NAME; Declarator *def = (Declarator *)definition.value(); if (def) base_info->specified_type = def->c_type; } } operator no_type_spec extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { } } operator type_spec_sym extends type_spec { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { type_spec::phylum_cast(primary_alternative())->specify(ctx, base_info); } public virtual method void check_types(TypecheckContext *ctx) { type_spec::phylum_cast(primary_alternative())->check_types(ctx); } } phylum type_qual { public virtual method void specify(decl::TypeInfo *base_info) {} } // type_qual -> CONST operator ConstTypeQualifier extends type_qual { public virtual method void specify(decl::TypeInfo *base_info) { base_info->quals |= CONST_QUAL; } } // type_qual -> VOLATILE operator VolatileTypeQualifier extends type_qual { public virtual method void specify(decl::TypeInfo *base_info) { base_info->quals |= VOLATILE_QUAL; } } // type_qual -> RESTRICT operator RestrictTypeQualifier extends type_qual { public virtual method void specify(decl::TypeInfo *base_info) { base_info->quals |= RESTRICT_QUAL; } } operator no_type_qual extends type_qual { } operator type_qual_sym extends type_qual { public virtual method void specify(decl::TypeInfo *base_info) { type_qual::phylum_cast(primary_alternative())->specify(base_info); } } phylum init_declr { public virtual method void check_types(TypecheckContext *ctx, CType *base_type) { } } // init_declr -> declr:declr OptR38E1:init operator InitDeclr extends init_declr { public virtual method void check_types(TypecheckContext *ctx, CType *base_type) { CType *type = get_declr()->build_type(ctx, base_type); if (has_init()) get_init_init()->check_type(ctx, type); } } operator no_init_declr extends init_declr { } operator init_declr_sym extends init_declr { public virtual method void check_types(TypecheckContext *ctx, CType *base_type) { init_declr::phylum_cast(primary_alternative()) ->check_types(ctx, base_type); } } phylum type_name { public virtual method CType *get_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } } // type_name -> SeqR13E0star:spec_quals OptR13E1:declr operator TypeName extends type_name depends on decl { public virtual method CType *get_type(TypecheckContext *ctx) { decl::TypeInfo base_info; for (spec_quals_iterator i = get_spec_quals(); i; ++i) i.get_spec_qual()->specify(ctx, &base_info); CType *base_type = decl::assemble_base_type(ctx, this, &base_info); if (has_declr()) return get_declr_declr()->build_type(ctx, base_type); else return base_type; } } operator no_type_name extends type_name { } operator type_name_sym extends type_name { public virtual method CType *get_type(TypecheckContext *ctx) { return type_name::phylum_cast(primary_alternative())->get_type(ctx); } } phylum type_spec_qual { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) {} public virtual method void check_types(TypecheckContext *ctx) {} } // type_spec_qual -> type_spec:spec operator TypeSpecifier extends type_spec_qual { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { get_spec()->specify(ctx, base_info); } public virtual method void check_types(TypecheckContext *ctx) { get_spec()->check_types(ctx); } } // type_spec_qual -> type_qual:qual operator TypeQualifier extends type_spec_qual { } operator no_type_spec_qual extends type_spec_qual { } operator type_spec_qual_sym extends type_spec_qual { public virtual method void specify(TypecheckContext *ctx, decl::TypeInfo *base_info) { type_spec_qual::phylum_cast(primary_alternative()) ->specify(ctx, base_info); } public virtual method void check_types(TypecheckContext *ctx) { type_spec_qual::phylum_cast(primary_alternative()) ->check_types(ctx); } } phylum abst_declr { public slot CType *c_type; public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return base_type; } } // abst_declr -> pointer:ptr operator PointerAbstDecl extends abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { CType *type = base_type; type = get_ptr()->point_to(ctx, type); c_type = type; return type; } } // abst_declr -> OptR46E0:ptr direct_abst_declr:direct operator DirectAbstDecl extends abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { CType *type = base_type; if (has_ptr()) type = get_ptr_ptr()->point_to(ctx, type); type = get_direct()->build_type(ctx, type); c_type = type; return type; } } operator no_abst_declr extends abst_declr { } operator abst_declr_sym extends abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return abst_declr::phylum_cast(primary_alternative()) ->build_type(ctx, base_type); } } phylum struct_decl { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members) { } } // struct_decl -> SeqR13E0star:spec_quals SeqR61E1star:declrs SEMI operator StructDecl extends struct_decl { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members) { decl::TypeInfo base_type_info; for (spec_quals_iterator i = get_spec_quals(); i; ++i) i.get_spec_qual()->check_types(ctx); for (spec_quals_iterator i = get_spec_quals(); i; ++i) i.get_spec_qual()->specify(ctx, &base_type_info); CType *base_type = decl::assemble_base_type(ctx, this, &base_type_info); //string msg = "Base type: " + base_type->name(); //set_string_prop(MOUSE_OVER_MSG, msg.c_str()); //compute_synth_attrs(true); bool has_declrs = get_declrs(); if (base_type_info.aggregate == decl::NO_AGGREGATE && !has_declrs) set_semant_error(this, "Declaration declares neither an aggregate" " nor any declarators"); for (declrs_iterator i = get_declrs(); i; ++i) i.get_declr()->check_member(ctx, members, base_type); } } operator no_struct_decl extends struct_decl { } operator struct_decl_sym extends struct_decl { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members) { struct_decl::phylum_cast(primary_alternative()) ->check_member(ctx, members); } } phylum enum_ { } // enum_ -> IDSYM:name OptR45E1:init operator EnumerationItem extends enum_ { } operator no_enum_ extends enum_ { } operator enum__sym extends enum_ { } phylum init_ { public virtual method void check_type(TypecheckContext *ctx, CType *declared_type) { } } // init_ -> assign_expr:expr operator ExprInit extends init_ { public virtual method void check_type(TypecheckContext *ctx, CType *declared_type) { ExprType analyzed_type = get_expr()->determine_type(ctx); if (!analyzed_type) return; analyzed_type = analyzed_type.to_rvalue(); if (!analyzed_type) set_semant_error(this, "Can't initialize with non-rvalue %s", analyzed_type.name().c_str()); else // This will set its own error messages ExprType::assign_compat(declared_type->unqualified(), analyzed_type, "initialization", this); } } // init_ -> LBRACE SeqR44E1star:inits OptR32E4 RBRACE operator BlockInit extends init_ { } operator no_init_ extends init_ { } operator init__sym extends init_ { public virtual method void check_type(TypecheckContext *ctx, CType *declared_type) { init_::phylum_cast(primary_alternative()) ->check_type(ctx, declared_type); } } phylum designator { } // designator -> LBRACK expr:idx RBRACK operator ArrayElemDesignator extends designator { } // designator -> DOT IDSYM:field operator FieldDesignator extends designator { } operator no_designator extends designator { } operator designator_sym extends designator { } phylum expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return ExprType(ERROR_CLASS, 0); } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { return false; } public virtual method bool has_addr(TypecheckContext *ctx) { return false; } public virtual method ExprType determine_type_logical( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } if (!left.ty->is_scalar()) { set_semant_error(node, "Left arg of `%s' must have scalar type," " not %s", op_sym, left.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } if (!right.ty->is_scalar()) { set_semant_error(node, "Right arg of `%s' must have scalar type," " not %s", op_sym, right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExpressionClass result_cl; ExprType result; if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; result.ty = &ctx->the_SignedIntType; string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public virtual method ExprType determine_type_integer( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } IntegerType *left_int, *right_int; if (left.ty->is_integer()) left_int = (IntegerType *)left.ty; else { set_semant_error(node, "Left arg of `%s' must have integer type," " not %s", op_sym, left.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } if (right.ty->is_integer()) right_int = (IntegerType *)right.ty; else { set_semant_error(node, "Right arg of `%s' must have integer type," " not %s", op_sym, right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExpressionClass result_cl; ExprType result; if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; result.ty = IntegerType::usual_conv(left_int, right_int); string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public static method ExprType determine_type_equality( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } ExprType result; if (left.ty->is_arithmetic() && right.ty->is_arithmetic()) { ArithmeticType *left_a = (ArithmeticType*)left.ty; ArithmeticType *right_a = (ArithmeticType*)right.ty; CType *common = ArithmeticType::usual_conv(&left_a, &right_a); if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; } else if (left.ty->is_pointer() && right.ty->is_pointer()) { CType *left_ref_uq = ((PointerType*)left.ty)->referent_type ->unqualified(); CType *right_ref_uq = ((PointerType*)right.ty)->referent_type ->unqualified(); if (CType::composite_type(left_ref_uq, right_ref_uq)) { // Pointers to possibly qualified compatible types -- okay } else if (left_ref_uq->is_void() || right_ref_uq->is_void()) { CType *non_void = (left_ref_uq->is_void()) ? right_ref_uq : left_ref_uq; if (non_void->is_function()) set_semant_error(node, "Can't compare function pointer " "and void pointer in %s %s %s", left.ty->name().c_str(), op_sym, right.ty->name().c_str()); // Otherwise, you can compare void to anything } else { set_semant_error(node, "Incompatible pointer types in " "comparison %s %s %s", left.ty->name().c_str(), op_sym, right.ty->name().c_str()); } result.cl = RVALUE; } else if (left.ty->is_pointer() && right.is_null_const() || right.ty->is_pointer() && left.is_null_const()) { // Any pointer can be compared to null result.cl = RVALUE; } else { set_semant_error(node, "Wrong types to `%s': %s %s %s", op_sym, left.ty->name().c_str(), op_sym, right.ty->name().c_str()); result.cl = RVALUE; } result.ty = &ctx->the_SignedIntType; string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public static method ExprType determine_type_relational( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } ExprType result; if (left.ty->is_arithmetic() && right.ty->is_arithmetic()) { ArithmeticType *left_a = (ArithmeticType*)left.ty; ArithmeticType *right_a = (ArithmeticType*)right.ty; if (left_a->domain() != REAL_DOMAIN) set_semant_error(node, "Left arg to `%s' must have real type," " not %s", op_sym, left_a->name().c_str()); if (right_a->domain() != REAL_DOMAIN) set_semant_error(node, "Right arg to `%s' must have real type," " not %s", op_sym, right_a->name().c_str()); CType *common = ArithmeticType::usual_conv(&left_a, &right_a); if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; } else if (left.ty->is_pointer() && right.ty->is_pointer()) { CType *left_ref_uq = ((PointerType*)left.ty)->referent_type ->unqualified(); CType *right_ref_uq = ((PointerType*)right.ty)->referent_type ->unqualified(); if (left_ref_uq->is_function() || right_ref_uq->is_function()) set_semant_error(node, "Can't compare function pointers for " "order in %s %s %s", left.ty->name().c_str(), op_sym, right.ty->name().c_str()); else if (left_ref_uq->is_complete() != right_ref_uq->is_complete()) set_semant_error(node, "Can't compare complete and incomplete" " types in %s %s %s", left.ty->name().c_str(), op_sym, right.ty->name().c_str()); else if (!CType::composite_type(left_ref_uq, right_ref_uq)) set_semant_error(node, "Incompatible types in comparison " "%s %s %s", left.ty->name().c_str(), op_sym, right.ty->name().c_str()); result.cl = RVALUE; } else { set_semant_error(node, "Wrong types to `%s': %s %s %s", op_sym, left.ty->name().c_str(), op_sym, right.ty->name().c_str()); result.cl = RVALUE; } result.ty = &ctx->the_SignedIntType; string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public virtual method ExprType determine_type_shift( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } IntegerType *left_int, *right_int; if (left.ty->is_integer()) left_int = (IntegerType *)left.ty; else { set_semant_error(node, "Left arg of shift must have integer type," " not %s", left.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } if (right.ty->is_integer()) right_int = (IntegerType *)right.ty; else { set_semant_error(node, "Shift amount must have integer type," " not %s", right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExpressionClass result_cl; if (left.is_int_const() && right.is_int_const()) result_cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result_cl = ARITH_CONST; else result_cl = RVALUE; IntegerType *result = left_int->promote(); string msg = string(op_name) + " has type " + result->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return ExprType(result_cl, result); } public virtual method ExprType determine_type_arithmetic( TypecheckContext *ctx, Node *node, expr *left_expr, expr *right_expr, const char *op_sym, const char *op_name) { ExprType left, right, tmp; if (!(left = left_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = right_expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(node, "Can't use %s as left arg to `%s'", left.name().c_str(), op_sym); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(node, "Can't use %s as right arg to `%s'", right.name().c_str(), op_sym); } ArithmeticType *left_a, *right_a; if (left.ty->is_arithmetic()) left_a = (ArithmeticType *)left.ty; else { set_semant_error(node, "Left arg of `%s' must have arithemtic " "type, not %s", op_sym, left.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } if (right.ty->is_arithmetic()) right_a = (ArithmeticType *)right.ty; else { set_semant_error(node, "Right arg of `%s' must have arithemtic " "type, not %s", op_sym, right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; result.ty = ArithmeticType::usual_conv(&left_a, &right_a); string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public virtual method ExprType determine_type_unary( TypecheckContext *ctx, Node *node, expr *expr, const char *op_sym, const char *op_name) { ExprType type, tmp; if (!(type = expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(node, "Can't use %s as arg to `%s'", type.name().c_str(), op_sym); } ArithmeticType *type_a; if (type.ty->is_arithmetic()) type_a = (ArithmeticType *)type.ty; else { set_semant_error(node, "Arg of `%s' must have arithmetic " "type, not %s", op_sym, type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (type.is_int_const()) result.cl = INTEGER_CONST; else if (type.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; if (type_a->is_integer()) type_a = ((IntegerType *)type_a)->promote(); result.ty = type_a; string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } public virtual method ExprType determine_type_crement( TypecheckContext *ctx, Node *node, expr *expr, const char *op_sym, const char *op_name) { ExprType type, tmp; if (!(type = expr->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_mod_lvalue())) { type = tmp; } else { set_semant_error(node, "Can't use %s as arg to `%s'", type.name().c_str(), op_sym); } if (!(type.ty->is_arithmetic() && ((ArithmeticType *)type.ty)->domain() == REAL_DOMAIN) && !type.ty->is_pointer()) { set_semant_error(node, "Arg of `%s' must have pointer or real " "arithemtic type, not %s", op_sym, type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExprType result; result.cl = RVALUE; if (type.ty->is_integer()) type.ty = ((IntegerType *)type.ty)->promote(); result.ty = type.ty; string msg = string(op_name) + " has type " + result.ty->name(); node->set_string_prop(MOUSE_OVER_MSG, msg.c_str()); node->compute_synth_attrs(true); return result; } } // expr -> expr:pred QUESTION Opt(exprs):texpr COLON expr:fexpr operator TernaryOp extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType pred, middle, right, tmp; if (!(pred = get_pred()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (has_texpr()) { if (!(middle = get_texpr_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); } else { middle = pred; /* a GCC extension */ } if (!(right = get_fexpr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = pred.to_rvalue())) { pred = tmp; } else { set_semant_error(this, "Can't use %s as predicate in `?:'", pred.name().c_str()); } if ((tmp = middle.to_rvalue())) { middle = tmp; } else { set_semant_error(this, "Can't use %s as middle arg of `?:'", middle.name().c_str()); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(this, "Can't use %s as right arg of `?:'", right.name().c_str()); } if (!pred.ty->is_scalar()) set_semant_error(this, "Predicate of ternary op must have scalar " "type, not %s", pred.ty->name().c_str()); ExprType result; if (middle.ty->is_arithmetic() && right.ty->is_arithmetic()) { ArithmeticType *middle_converted = (ArithmeticType*)middle.ty; ArithmeticType *right_converted = (ArithmeticType*)right.ty; result.ty = ArithmeticType::usual_conv(&middle_converted, &right_converted); if (pred.is_int_const() && middle.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (pred.is_int_const() && middle.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; } else if (middle.ty->is_struct_union() && right.ty->is_struct_union()) { StructUnionType *middle_su = (StructUnionType *)middle.ty; StructUnionType *right_su = (StructUnionType *)right.ty; StructUnionType *common = StructUnionType::are_same(middle_su, right_su); if (common) { result.ty = common; result.cl = RVALUE; } else { set_semant_error(this, "Different struct/union types in `?:':" " %s vs. %s", middle_su->name().c_str(), right_su->name().c_str()); return ExprType(ERROR_CLASS, 0); } } else if (middle.ty->is_void() && right.ty->is_void()) { result.cl = RVALUE; result.ty = &ctx->the_VoidType; } else if ((middle.ty->is_pointer() || middle.is_null_const()) && (right.ty->is_pointer() || right.is_null_const())) { if (!middle.ty->is_pointer()) { // Middle must be an arithmetic 0 result.ty = right.ty; } else if (!right.ty->is_pointer()) { // Right must be an arithmetic 0 result.ty = middle.ty; } else { CType *middle_ref = ((PointerType *)middle.ty)->referent_type; CType *right_ref = ((PointerType *)right.ty)->referent_type; unsigned quals = middle_ref->qualifiers() | right_ref->qualifiers(); CType *middle_ref_uq = middle_ref->unqualified(); CType *right_ref_uq = right_ref->unqualified(); CType *comp = CType::composite_type(middle_ref_uq, right_ref_uq); if (comp) { result.ty = comp->qualified_by(quals)->pointer_to(); } else if (middle_ref_uq->is_void() || right_ref_uq->is_void()) { result.ty = ctx->the_VoidType.qualified_by(quals) ->pointer_to(); } else { set_semant_error(this, "Incompatible pointer types %s " "and %s in conditional operator", middle.ty->name().c_str(), right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } } result.cl = RVALUE; } else { set_semant_error(this, "Incompatible types in conditional: " "? %s : %s", middle.ty->name().c_str(), right.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } string msg = "Conditional op has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> expr:left LOR expr:right operator LogicalOr extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_logical(ctx, this, get_left(), get_right(), "||", "Logical OR"); } } // expr -> expr:left LAND expr:right operator LogicalAnd extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_logical(ctx, this, get_left(), get_right(), "&&", "Logical AND"); } } // expr -> expr:left BOR expr:right operator BitwiseOr extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_integer(ctx, this, get_left(), get_right(), "|", "Bitwise OR"); } } // expr -> expr:left BXOR expr:right operator BitwiseXor extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_integer(ctx, this, get_left(), get_right(), "^", "Bitwise XOR"); } } // expr -> expr:left BAND expr:right operator BitwiseAnd extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_integer(ctx, this, get_left(), get_right(), "&", "Bitwise AND"); } } // expr -> expr:left EQ expr:right operator Equals extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_equality(ctx, this, get_left(), get_right(), "==", "Equals"); } } // expr -> expr:left NE expr:right operator NotEquals extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_equality(ctx, this, get_left(), get_right(), "!=", "Not-equals"); } } // expr -> expr:left LT expr:right operator LessThan extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_relational(ctx, this, get_left(), get_right(), "<", "Less-than"); } } // expr -> expr:left GT expr:right operator GreaterThan extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_relational(ctx, this, get_left(), get_right(), ">", "Greater-than"); } } // expr -> expr:left LE expr:right operator LessThanEquals extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_relational(ctx, this, get_left(), get_right(), "<=", "Less-than-or-equals"); } } // expr -> expr:left GE expr:right operator GreaterThanEquals extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_relational(ctx, this, get_left(), get_right(), ">=", "Greater-than-or-equals"); } } // expr -> expr:left LSHIFT expr:right operator LeftShift extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_shift(ctx, this, get_left(), get_right(), "<<", "Left shift"); } } // expr -> expr:left RSHIFT expr:right operator RightShift extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_shift(ctx, this, get_left(), get_right(), ">>", "Right shift"); } } // expr -> expr:left PLUS expr:right operator Add extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType left, right, tmp; if (!(left = get_left()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = get_right()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(this, "Can't use %s as left arg to `+'", left.name().c_str()); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(this, "Can't use %s as right arg to `+'", right.name().c_str()); } ExprType result; if (left.ty->is_arithmetic() && right.ty->is_arithmetic()) { ArithmeticType *left_converted = (ArithmeticType*)left.ty; ArithmeticType *right_converted = (ArithmeticType*)right.ty; result.ty = ArithmeticType::usual_conv(&left_converted, &right_converted); if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; } else if (left.ty->is_integer() && right.ty->is_ptr_to_object() || right.ty->is_integer() && left.ty->is_ptr_to_object()) { ExprType int_type; ExprType pointer_type; if (left.ty->is_integer()) { int_type = left; pointer_type = right; } else { pointer_type = left; int_type = right; } result.ty = pointer_type.ty; if (int_type.is_int_const() && pointer_type.is_addr_const()) result.cl = CONSTANT; else result.cl = RVALUE; } else { set_semant_error(this, "Wrong types to `+': %s + %s", left.ty->name().c_str(), right.ty->name().c_str()); result.ty = 0; result.cl = ERROR_CLASS; return result; } string msg = "Sum has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { bignum_t left, right; if (!get_left()->int_const_expr(ctx, &left)) return false; if (!get_right()->int_const_expr(ctx, &right)) return false; *value = left + right; return true; } } // expr -> expr:left MINUS expr:right operator Subtract extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType left, right, tmp; if (!(left = get_left()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = get_right()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_rvalue())) { left = tmp; } else { set_semant_error(this, "Can't use %s as left arg to `-'", left.name().c_str()); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(this, "Can't use %s as right arg to `-'", right.name().c_str()); } ExprType result; if (left.ty->is_arithmetic() && right.ty->is_arithmetic()) { ArithmeticType *left_converted = (ArithmeticType*)left.ty; ArithmeticType *right_converted = (ArithmeticType*)right.ty; result.ty = ArithmeticType::usual_conv(&left_converted, &right_converted); if (left.is_int_const() && right.is_int_const()) result.cl = INTEGER_CONST; else if (left.is_arith_const() && right.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; } else if (right.ty->is_integer() && left.ty->is_ptr_to_object()) { result.ty = left.ty; if (right.is_int_const() && left.is_addr_const()) result.cl = CONSTANT; else result.cl = RVALUE; } else if (left.ty->is_pointer() && right.ty->is_pointer()) { CType *left_ref_uq = ((PointerType *)left.ty)->referent_type ->unqualified(); CType *right_ref_uq = ((PointerType *)right.ty)->referent_type ->unqualified(); if (!CType::composite_type(left_ref_uq, right_ref_uq)) set_semant_error(this, "Incompatible pointer types in " "difference: %s - %s", left.ty->name().c_str(), right.ty->name().c_str()); result.ty = ctx->the_PtrdiffType; result.cl = RVALUE; } else { set_semant_error(this, "Wrong types to `-': %s - %s", left.ty->name().c_str(), right.ty->name().c_str()); result.ty = 0; result.cl = ERROR_CLASS; return result; } string msg = "Difference has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> expr:left TIMES expr:right operator Multiply extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_arithmetic(ctx, this, get_left(), get_right(), "*", "Multiply"); } } // expr -> expr:left DIV expr:right operator Divide extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_arithmetic(ctx, this, get_left(), get_right(), "/", "Divide"); } } // expr -> expr:left MOD expr:right operator Modulo extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_integer(ctx, this, get_left(), get_right(), "%", "Modulus"); } } // expr -> LPAREN type_name:name RPAREN expr:expr operator TypeCast extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType expr_type; if (!(expr_type = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); CType *type = get_name()->get_type(ctx); if (type->unqualified()->is_void()) { return ExprType(VOID_EXPR, type); } else { if (!expr_type.ty->is_scalar()) set_semant_error(this, "Can't cast value of non-scalar type " "%s", expr_type.ty->name().c_str()); if (!type->unqualified()->is_scalar()) set_semant_error(this, "Can't cast to non-scalar type %s", type->name().c_str()); ExprType result; result.ty = type; if (expr_type.is_arith_const() && type->is_integer()) result.cl = INTEGER_CONST; else if (expr_type.is_null_const() && type->is_pointer()) result.cl = NULL_CONST; else if (expr_type.is_int_const() && !type->is_integer()) result.cl = ARITH_CONST; else /* GCC would have "result.cl = expr_type.cl" to allow lvalues */ result = result.to_rvalue(); string msg = "Cast has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } } // expr -> BAND expr:expr operator AddressOf extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type, tmp; if (!(type = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_lvalue())) { type = tmp; } else if (type.cl == FUNC_DESIG || get_expr()->has_addr(ctx)) { // okay } else { set_semant_error(this, "Can't use %s as arg to `&'", type.name().c_str()); } if (type.ty->is_bitfield()) set_semant_error(this, "Can't take pointer to bitfield type %s", type.ty->name().c_str()); ExprType result; result.ty = type.ty->pointer_to(); result.cl = RVALUE; // XXX sometimes should be ADDR_CONST string msg = "Address-of has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> PLUS expr:expr operator Positive extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_unary(ctx, this, get_expr(), "+", "Unary plus"); } } // expr -> MINUS expr:expr operator Negate extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_unary(ctx, this, get_expr(), "-", "Unary minus"); } } // expr -> BNOT expr:expr operator BitwiseNegate extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type, tmp; if (!(type = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(this, "Can't use %s as arg to `~'", type.name().c_str()); } IntegerType *type_int; if (type.ty->is_integer()) type_int = (IntegerType *)type.ty; else { set_semant_error(this, "Arg of `~' must have arithemtic " "type, not %s", type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (type.is_int_const()) result.cl = INTEGER_CONST; else if (type.is_arith_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; type_int = type_int->promote(); result.ty = type_int; string msg = "Bitwise complement has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> NOT expr:expr operator LogicalNot extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type, tmp; if (!(type = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(this, "Can't use %s as arg to `!'", type.name().c_str()); } if (!type.ty->is_scalar()) { set_semant_error(this, "Arg of `!' must have scalar " "type, not %s", type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (type.is_int_const()) result.cl = INTEGER_CONST; else if (type.is_const()) result.cl = ARITH_CONST; else result.cl = RVALUE; result.ty = &ctx->the_SignedIntType; string msg = "Logical not has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> expr:func LPAREN SeqR127E2star:exprs RPAREN operator FunctionCall extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type, tmp; if (!(type = get_func()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(this, "Can't use %s as function in function call", type.name().c_str()); } FunctionType *func_type = NULL; if (type.ty->is_pointer()) { PointerType *ptr_type = (PointerType *)type.ty; CType *ref_t = ptr_type->referent_type->unqualified(); if (ref_t->is_function()) func_type = (FunctionType *)ref_t; } if (!func_type) { set_semant_error(this, "Function in function call must have " "pointer to function type, not %s", type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } int proto_args = 0; if (!(func_type->flags & UNKNOWN_ARGS)) proto_args = (int)func_type->parameters.size(); int argnum = 0; for (exprs_iterator i = get_exprs(); i; ++i, argnum++) { ExprType tmp, arg_type = i.get_expr()->determine_type(ctx); if (!arg_type) continue; if (!(tmp = arg_type.to_rvalue())) { set_semant_error(i.get_expr()->cast_to_Node(), "Can't use %s as argument in function call", arg_type.name().c_str()); } else { arg_type = tmp; } if (argnum < proto_args) { CType *param_type = func_type->parameters[argnum]; ExprType::assign_compat(param_type, arg_type, "function call", i.get_expr()->cast_to_Node()); } else if (!(func_type->flags & (UNKNOWN_ARGS|ELLIPTICAL))) { set_semant_error(this, "Too many args (%d vs. %d) in " "call to %s", argnum + 1, proto_args, func_type->name().c_str()); } else { CType *promoted = arg_type.ty->arg_promote(); // Can we do anythin with this? I think the rules about // argument promotion can only be enforced dynamically } } if (argnum < proto_args) { set_semant_error(this, "Too few args (%d vs. %d) in call to %s", argnum, proto_args, func_type->name().c_str()); } ExprType result; result.ty = func_type->return_type; if (result.ty->is_void()) result.cl = VOID_EXPR; else result.cl = RVALUE; string msg = "Function call has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> INC expr:expr operator PreIncrement extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_crement(ctx, this, get_expr(), "++", "Prefix increment"); } } // expr -> DEC expr:expr operator PreDecrement extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_crement(ctx, this, get_expr(), "--", "Prefix decrement"); } } // expr -> expr:expr INC operator PostIncrement extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_crement(ctx, this, get_expr(), "++", "Postfix increment"); } } // expr -> expr:expr DEC operator PostDecrement extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::determine_type_crement(ctx, this, get_expr(), "--", "Postfix decrement"); } } // expr -> SIZEOF expr:expr operator VarSizeof extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType expr_type = get_expr()->determine_type(ctx); CType *type = expr_type.ty; ExprType result; if (type && type->is_array() && ((ArrayType *)type)->qualifiers & VARIABLE_LEN_QUAL) result.cl = RVALUE; /* C99 runtime sizeof! */ else result.cl = INTEGER_CONST; result.ty = ctx->the_SizeType; return result; } } // expr -> SIZEOF LPAREN type_name:type RPAREN operator TypeSizeof extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { CType *type = get_type()->get_type(ctx); ExprType result; if (type->is_array() && ((ArrayType *)type)->qualifiers & VARIABLE_LEN_QUAL) result.cl = RVALUE; /* C99 runtime sizeof! */ else result.cl = INTEGER_CONST; result.ty = ctx->the_SizeType; return result; } } // expr -> LPAREN exprs:expr RPAREN operator ParenthExpr extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return get_expr()->determine_type(ctx); } public virtual method bool has_addr(TypecheckContext *ctx) { return get_expr()->has_addr(ctx); } } // expr -> int_const:val operator IntegerConstant extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type; type.ty = get_val()->determine_type(ctx); bool unused; bignum_t value = get_val()->get_value(ctx, &unused); if (value) type.cl = INTEGER_CONST; else type.cl = NULL_CONST; string msg = "Integer constant has type " + type.name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return type; } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { bool unused; *value = get_val()->get_value(ctx, &unused); return true; } } // expr -> char_const:val operator CharacterConstant extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { CType *type = get_val()->determine_type(ctx); string msg = "Character constant has type " + type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return ExprType(INTEGER_CONST, type); } } // expr -> float_const:val operator FloatingConstant extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { CType *type = get_val()->determine_type(ctx); string msg = "Floating point constant has type " + type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return ExprType(ARITH_CONST, type); } } // expr -> str_const:val operator StringConstant extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { CType *type = get_val()->determine_type(ctx); string msg = "String constant has type " + type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return ExprType(ARRAY_LVALUE, type); } } // expr -> LPAREN type_name:type RPAREN LBRACE SeqR44E1star:inits OptR32E4 RBRACE operator CompoundLiteral extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { CType *type = get_type()->get_type(ctx); if (type->is_function() || !type->is_complete() && !type->is_array()) { set_semant_error(this, "Compound literal must specify object or " "incomplete array type, not %s", type->name().c_str()); return ExprType(ERROR_CLASS, 0); } else { if (type->is_array()) { ArrayType *array_type = (ArrayType *)type; if (array_type->qualifiers & VARIABLE_LEN_QUAL) set_semant_error(this, "Compound literal may not have " "variable length array type %s", array_type->name().c_str()); } ExprType result; result.ty = type; if (result.ty->is_array()) result.cl = ARRAY_LVALUE; else result.cl = ACCESS_LVALUE; string msg = "Compound literal has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } } // expr -> IDSYM:name operator VariableExpr extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { Declarator *def = (Declarator *)declarator.value(); if (def && def->c_type) { CType *type = def->c_type; string msg = "`" + string(get_name()->pooled_string().chars()) + "' has type " + type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); if (type->is_function()) return ExprType(FUNC_DESIG, type); else if (type->is_array()) return ExprType(ARRAY_LVALUE, type); else return ExprType(MOD_LVALUE, type); } else { return ExprType(ERROR_CLASS, 0); } } } // expr -> expr:expr DOT IDSYM:field operator StructAccess extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType orig_arg, arg; if (!(orig_arg = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(arg = orig_arg.to_rvalue())) { set_semant_error(this, "Can't use %s as argument to . operator", arg.name().c_str()); } if (arg.ty->unqualified()->is_pointer()) { CType *ref = ((PointerType *)arg.ty->unqualified())->referent_type; if (ref->unqualified()->is_struct_union()) { bool union_p = ((StructUnionType*)ref->unqualified()) ->is_union; set_semant_error(this, "`.' on pointer to %s should be `->'", union_p ? "union" : "structure"); return ExprType(ERROR_CLASS, 0); } } else if (!arg.ty->unqualified()->is_struct_union()) { set_semant_error(this, "Left arg to '.' must have structure or" " union type, not %s", arg.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } else if (!arg.ty->unqualified()->completion()->is_complete()) { set_semant_error(this, "Can't dereference incomplete %s type %s", ((StructUnionType *)arg.ty)->is_union ? "union" : "struct", arg.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } unsigned quals = arg.ty->qualifiers(); CompleteStructUnionType *obj = (CompleteStructUnionType *) (arg.ty->unqualified()->completion()); PooledString field = get_field()->pooled_string(); CType *val = obj->table.resolve(field); if (!val) { set_semant_error(this, "%s has no member %s", obj->name().c_str(), field.chars()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (val->is_array()) result.cl = orig_arg.is_lvalue() ? ARRAY_LVALUE : ARRAY_RVALUE; else if (orig_arg.is_lvalue()) { if (quals & CONST_QUAL || val->qualifiers() & CONST_QUAL) result.cl = ACCESS_LVALUE; else result.cl = MOD_LVALUE; } else result.cl = RVALUE; result.ty = val->qualified_by(quals); string msg = string(obj->is_union ? "Union" : "Structure") + " member has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> expr:expr PTR IDSYM:field operator PointerAccess extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType arg, orig_arg; if (!(orig_arg = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(arg = orig_arg.to_rvalue())) { set_semant_error(this, "Can't use %s as argument to -> operator", arg.name().c_str()); } if (arg.ty->unqualified()->is_struct_union()) { bool union_p = ((StructUnionType *)arg.ty->unqualified()) ->is_union; set_semant_error(this, "`->' on %s should be `.'", union_p ? "union" : "structure"); return ExprType(ERROR_CLASS, 0); } else if (!arg.ty->unqualified()->is_pointer()) { set_semant_error(this, "Left arg to '->' must have pointer to" " structure or union type, not %s", arg.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } CType *ref = ((PointerType *)arg.ty->unqualified())->referent_type; unsigned quals = ref->qualifiers(); CType *ref_uq = ref->unqualified(); if (!ref_uq->is_struct_union()) { set_semant_error(this, "Left arg to '->' must be pointer to" " structure or union, not to %s", ref->name().c_str()); return ExprType(ERROR_CLASS, 0); } else if (!ref_uq->completion()->is_complete()) { set_semant_error(this, "Can't dereference incomplete %s type %s", ((StructUnionType *)ref_uq)->is_union ? "union" : "struct", ref->name().c_str()); return ExprType(ERROR_CLASS, 0); } CompleteStructUnionType *obj = (CompleteStructUnionType *)(ref_uq->completion()); PooledString field = get_field()->pooled_string(); CType *val = obj->table.resolve(field); if (!val) { set_semant_error(this, "%s has no member %s", obj->name().c_str(), field.chars()); return ExprType(ERROR_CLASS, 0); } ExprType result; if (val->is_array()) result.cl = orig_arg.is_lvalue() ? ARRAY_LVALUE : ARRAY_RVALUE; else if (orig_arg.is_lvalue()) { if (quals & CONST_QUAL || val->qualifiers() & CONST_QUAL) result.cl = ACCESS_LVALUE; else result.cl = MOD_LVALUE; } else result.cl = RVALUE; result.ty = val->qualified_by(quals); string msg = "Indirect " + string(obj->is_union ? "union" : "structure") + " member has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } } // expr -> expr:expr LBRACK exprs:index RBRACK operator ArrayAccess extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType outside, inside, tmp; if (!(outside = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = outside.to_rvalue())) { outside = tmp; } else { set_semant_error(this, "Can't use %s as object of subscript" " operator", outside.name().c_str()); } if (!(inside = get_index()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = inside.to_rvalue())) { inside = tmp; } else { set_semant_error(this, "Can't use %s as inside of subscript" " operator", inside.name().c_str()); } if (inside.ty->is_pointer() + outside.ty->is_pointer() != 1) { set_semant_error(this, "Exactly one arg to array subscript " "operator must be a pointer in %s[%s]", outside.ty->name().c_str(), inside.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } PointerType *ptr_type; CType *other_type; if (outside.ty->is_pointer()) { ptr_type = (PointerType*)outside.ty; other_type = inside.ty; } else { ptr_type = (PointerType*)inside.ty; other_type = outside.ty; } if (!other_type->is_integer()) { set_semant_error(this, "Array index must have integer type, not " "%s", other_type->name().c_str()); return ExprType(ERROR_CLASS, 0); } IntegerType *idx_type = (IntegerType *)other_type; ExprType result; result.ty = ptr_type->referent_type; if (result.ty->is_array()) result.cl = ARRAY_LVALUE; else if (result.ty->qualifiers() & CONST_QUAL) result.cl = ACCESS_LVALUE; else result.cl = MOD_LVALUE; string msg = "Array index has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } public virtual method bool has_addr(TypecheckContext *ctx) { return true; } } // expr -> TIMES expr:expr operator PointerDereference extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type, tmp; if (!(type = get_expr()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(this, "Can't use %s as arg to `*'", type.name().c_str()); } PointerType *type_p; if (type.ty->is_pointer()) type_p = (PointerType *)type.ty; else { set_semant_error(this, "Arg of `*' must have pointer " "type, not %s", type.ty->name().c_str()); return ExprType(ERROR_CLASS, 0); } CType *referent = type_p->referent_type; ExprType result; if (referent->unqualified()->is_function()) result.cl = FUNC_DESIG; else if (referent->unqualified()->is_object()) { if (referent->qualifiers() & CONST_QUAL) result.cl = ACCESS_LVALUE; else result.cl = MOD_LVALUE; } else if (referent->unqualified()->is_void()) result.cl = VOID_EXPR; else result.cl = RVALUE; result.ty = referent; string msg = "Pointer dereference has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } public virtual method bool has_addr(TypecheckContext *ctx) { return true; } } operator no_expr extends expr { } operator expr_sym extends expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return expr::phylum_cast(primary_alternative()) ->determine_type(ctx); } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { return expr::phylum_cast(primary_alternative()) ->int_const_expr(ctx, value); } public virtual method bool has_addr(TypecheckContext *ctx) { return expr::phylum_cast(primary_alternative())->has_addr(ctx); } } phylum arg_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return ExprType(ERROR_CLASS, 0); } } operator ExpressionArgument extends arg_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return get_expr()->determine_type(ctx); } } operator arg_expr_sym extends arg_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return arg_expr::phylum_cast(primary_alternative()) ->determine_type(ctx); } } phylum designation { } // designation -> SeqR41E0star:desigs ASSIGN operator Designation extends designation { } operator no_designation extends designation { } operator designation_sym extends designation { } phylum inner_init { } // inner_init -> OptR42E0:desig init_:init operator InnerInitializer extends inner_init { } operator no_inner_init extends inner_init { } operator inner_init_sym extends inner_init { } phylum assign_expr depends on expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return ExprType(ERROR_CLASS, 0); } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { return false; } public virtual method bool has_addr(TypecheckContext *ctx) { return false; } } // assign_expr -> expr:left ASSIGN assign_expr:right operator NormalAssign extends assign_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType left, right, tmp; if (!(left = get_left()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if (!(right = get_right()->determine_type(ctx))) return ExprType(ERROR_CLASS, 0); if ((tmp = left.to_mod_lvalue())) { left = tmp; } else { set_semant_error(this, "Can't assign to %s", left.name().c_str()); } if ((tmp = right.to_rvalue())) { right = tmp; } else { set_semant_error(this, "Can't use %s as right arg to `='", right.name().c_str()); } CType *left_uq = left.ty->unqualified(); if (ExprType::assign_compat(left_uq, right, "assigment", this)) { ExprType result; result.ty = left_uq; result.cl = RVALUE; string msg = "Assignment has type " + result.ty->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return result; } else { return ExprType(ERROR_CLASS, 0); } } } // assign_expr -> expr:left MULASSIGN assign_expr:right operator MultiplyAssign extends assign_expr { } // assign_expr -> expr:left DIVASSIGN assign_expr:right operator DivideAssign extends assign_expr { } // assign_expr -> expr:left MODASSIGN assign_expr:right operator ModAssign extends assign_expr { } // assign_expr -> expr:left ADDASSIGN assign_expr:right operator AddAssign extends assign_expr { } // assign_expr -> expr:left SUBASSIGN assign_expr:right operator SubtractAssign extends assign_expr { } // assign_expr -> expr:left SHLASSIGN assign_expr:right operator ShiftLeftAssign extends assign_expr { } // assign_expr -> expr:left SHRASSIGN assign_expr:right operator ShiftRightAssign extends assign_expr { } // assign_expr -> expr:left ANDASSIGN assign_expr:right operator AndAssign extends assign_expr { } // assign_expr -> expr:left XORASSIGN assign_expr:right operator XorAssign extends assign_expr { } // assign_expr -> expr:left ORASSIGN assign_expr:right operator OrAssign extends assign_expr { } // assign_expr -> expr:expr operator SimpleExpression extends assign_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { ExprType type = get_expr()->determine_type(ctx); // string msg = "Simple expression has type " + type->name(); // set_string_prop(MOUSE_OVER_MSG, msg.c_str()); // compute_synth_attrs(true); return type; } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { return get_expr()->int_const_expr(ctx, value); } public virtual method bool has_addr(TypecheckContext *ctx) { return get_expr()->has_addr(ctx); } } operator no_assign_expr extends assign_expr { } operator assign_expr_sym extends assign_expr { public virtual method ExprType determine_type(TypecheckContext *ctx) { return assign_expr::phylum_cast(primary_alternative()) ->determine_type(ctx); } public virtual method bool int_const_expr(TypecheckContext *ctx, bignum_t *value) { return assign_expr::phylum_cast(primary_alternative()) ->int_const_expr(ctx, value); } public virtual method bool has_addr(TypecheckContext *ctx) { return assign_expr::phylum_cast(primary_alternative())->has_addr(ctx); } } phylum pointer { public virtual method CType *point_to(TypecheckContext *ctx, CType *base_type) { return base_type; } } // pointer -> TIMES SeqR51E2star:quals OptR46E0:ptr operator Pointer extends pointer depends on decl { public virtual method CType *point_to(TypecheckContext *ctx, CType *base_type) { decl::TypeInfo quals_info; CType *type = base_type->pointer_to(); for (quals_iterator i = get_quals(); i; ++i) i.get_qual()->specify(&quals_info); type = type->qualified_by(quals_info.quals); if (has_ptr()) return get_ptr_ptr()->point_to(ctx, type); else return type; } } operator no_pointer extends pointer { } operator pointer_sym extends pointer { public virtual method CType *point_to(TypecheckContext *ctx, CType *base_type) { return pointer::phylum_cast(primary_alternative()) ->point_to(ctx, base_type); } } phylum direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return base_type; } } // direct_declr -> IDSYM:name operator DeclarNameDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *type) { string name = get_name()->pooled_string().chars(); // if (!type->is_complete()) // set_semant_error(this, "Can't declare variable `%s' with " // "incomplete type %s", name.c_str(), // type->name().c_str()); string msg = name + " has type " + type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); return type; } } // direct_declr -> LPAREN OptR46E0:ptr direct_declr:direct RPAREN operator ParenNameDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { CType *type = base_type; if (has_ptr()) type = get_ptr_ptr()->point_to(ctx, type); type = get_direct()->build_type(ctx, type); return type; } } // direct_declr -> direct_declr:declr LBRACK SeqR51E2star:quals OptR51E3:expr RBRACK operator BasicArrayDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Array elements may not have function type"); if (!base_type->is_complete()) set_semant_error(this, "Array elements may not have incomplete type"); decl::TypeInfo decl_info; for (quals_iterator i = get_quals(); i; ++i) i.get_qual()->specify(&decl_info); unsigned quals = decl_info.quals; CType *type; if (has_expr()) { ExprType size_type = get_expr_expr()->determine_type(ctx); bignum_t size; if (size_type.is_int_const()) { get_expr_expr()->int_const_expr(ctx, &size); } else if (size_type && size_type.ty->is_integer()) { quals |= VARIABLE_LEN_QUAL; } else { set_semant_error(this, "Array size expression must have " "integer type"); size = 1; } type = base_type->array_of(size, quals); } else { type = base_type->array_of(0, quals|INCOMPLETE_QUAL); } return get_declr()->build_type(ctx, type); } } // direct_declr -> direct_declr:declr LBRACK SeqR51E2star:quals1 STATIC SeqR51E2star:quals2 assign_expr:expr RBRACK operator StaticArrayDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Array elements may not have function type"); if (!base_type->is_complete()) set_semant_error(this, "Array elements may not have incomplete type"); decl::TypeInfo decl_info; for (quals1_iterator i = get_quals1(); i; ++i) i.get_qual()->specify(&decl_info); for (quals2_iterator i = get_quals2(); i; ++i) i.get_qual()->specify(&decl_info); unsigned quals = decl_info.quals; ExprType size_type = get_expr()->determine_type(ctx); bignum_t size; if (size_type.is_int_const()) { get_expr()->int_const_expr(ctx, &size); } else if (size_type && size_type.ty->is_integer()) { quals |= VARIABLE_LEN_QUAL; } else { set_semant_error(this, "Array size expression must have " "integer type"); size = 1; } CType *type = base_type->array_of(size, quals|STATIC_QUAL); return get_declr()->build_type(ctx, type); } } // direct_declr -> direct_declr:declr LBRACK SeqR51E2star:quals TIMES RBRACK operator VariableArrayDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Array elements may not have function type"); if (!base_type->is_complete()) set_semant_error(this, "Array elements may not have incomplete type"); decl::TypeInfo decl_info; for (quals_iterator i = get_quals(); i; ++i) i.get_qual()->specify(&decl_info); unsigned quals = decl_info.quals; CType *type = base_type->array_of(0, quals|VARIABLE_LEN_QUAL); return get_declr()->build_type(ctx, type); } } // direct_declr -> direct_declr:declr LPAREN param_type_list:params RPAREN operator TypeFuncListDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Function may not return function type"); if (base_type->is_array()) set_semant_error(this, "Function may not return array type"); CType *type = get_params()->build_type(ctx, base_type); return get_declr()->build_type(ctx, type); } } // direct_declr -> direct_declr:declr LPAREN SeqR55E2star:idents RPAREN operator IDFuncListDirDeclr extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Function may not return function type"); if (base_type->is_array()) set_semant_error(this, "Function may not return array type"); type_vector no_params; CType *type = base_type->function_taking(UNKNOWN_ARGS, no_params); return get_declr()->build_type(ctx, type); } } operator no_direct_declr extends direct_declr { } operator direct_declr_sym extends direct_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return direct_declr::phylum_cast(primary_alternative()) ->build_type(ctx, base_type); } } phylum direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return base_type; } } // direct_abst_declr -> LPAREN abst_declr:declr RPAREN operator ParenAbstDecl extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return get_declr()->build_type(ctx, base_type); } } // direct_abst_declr -> OptR57E0:declr LBRACK OptR51E3:expr RBRACK operator ArrayAbstDecl extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Array elements may not have function type"); if (!base_type->is_complete()) set_semant_error(this, "Array elements may not have incomplete type"); unsigned quals = 0; CType *type; if (has_expr()) { ExprType size_type = get_expr_expr()->determine_type(ctx); bignum_t size; if (size_type.is_int_const()) { get_expr_expr()->int_const_expr(ctx, &size); } else if (size_type && size_type.ty->is_integer()) { quals |= VARIABLE_LEN_QUAL; } else { set_semant_error(this, "Array size expression must have " "integer type"); size = 1; } type = base_type->array_of(size, quals); } else { type = base_type->array_of(0, quals|INCOMPLETE_QUAL); } if (has_declr()) return get_declr_declr()->build_type(ctx, type); else return type; } } // direct_abst_declr -> OptR57E0:declr LBRACK TIMES RBRACK operator VariableAbstDecl extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Array elements may not have function type"); if (!base_type->is_complete()) set_semant_error(this, "Array elements may not have incomplete type"); CType *type = base_type->array_of(0, VARIABLE_LEN_QUAL); if (has_declr()) return get_declr_declr()->build_type(ctx, type); else return type; } } // direct_abst_declr -> direct_abst_declr:declr LPAREN OptR59E2:params RPAREN operator NestedFuncAbstDecl extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Function may not return function type"); if (base_type->is_array()) set_semant_error(this, "Function may not return array type"); CType *type; if (has_params()) { type = get_params_params()->build_type(ctx, base_type); } else { type_vector no_params; type = base_type->function_taking(UNKNOWN_ARGS, no_params); } return get_declr()->build_type(ctx, type); } } // direct_abst_declr -> LPAREN OptR59E2:params RPAREN operator FuncAbstDecl extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { if (base_type->is_function()) set_semant_error(this, "Function may not return function type"); if (base_type->is_array()) set_semant_error(this, "Function may not return array type"); CType *type; if (has_params()) { type = get_params_params()->build_type(ctx, base_type); } else { type_vector no_params; type = base_type->function_taking(UNKNOWN_ARGS, no_params); } return type; } } operator no_direct_abst_declr extends direct_abst_declr { } operator direct_abst_declr_sym extends direct_abst_declr { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return direct_abst_declr::phylum_cast(primary_alternative()) ->build_type(ctx, base_type); } } phylum param_type_list { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return base_type; } } // param_type_list -> SeqR67E0star:decls OptR67E1:dotdotdot operator ParameterTypeList extends param_type_list { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { unsigned flags = 0; type_vector params; if (has_dotdotdot()) flags |= ELLIPTICAL; for (decls_iterator i = get_decls(); i; ++i) params.push_back(i.get_decl()->get_type(ctx)); if (params.size() == 1 && params[0]->is_void()) { params = type_vector(); } else { for (type_vector::iterator i = params.begin(); i != params.end(); i++) { if (!(*i)->is_complete()) { set_semant_error(this, "Function declared with incomplete " "argument type %s", (*i)->name().c_str()); } } } return base_type->function_taking(flags, params); } } operator no_param_type_list extends param_type_list { } operator param_type_list_sym extends param_type_list { public virtual method CType *build_type(TypecheckContext *ctx, CType *base_type) { return param_type_list::phylum_cast(primary_alternative()) ->build_type(ctx, base_type); } } phylum struct_declr { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members, CType *base_type) { } } // struct_declr -> declr:declr operator StructDeclr extends struct_declr { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members, CType *base_type) { CType *type = get_declr()->build_type(ctx, base_type); IDSYM *name_node = get_declr()->find_name(); PooledString ident = name_node->pooled_string(); members->table.add(ident, type); } } // struct_declr -> OptR63E0:declr COLON expr:expr operator BitfieldDeclr extends struct_declr { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members, CType *base_type) { if (!base_type->unqualified()->is_integer()) { set_semant_error(this, "Bitfield must have integer type, not %s", base_type->name().c_str()); return; } unsigned quals = base_type->qualifiers(); IntegerType *int_type = (IntegerType *)base_type->unqualified(); if (!int_type->bitfield_okay()) { set_semant_error(this, "Bitfield must have _Bool, int, or " "unsigned int type, not %s", int_type->name().c_str()); return; } ExprType width_type = get_expr()->determine_type(ctx); bignum_t width; if (width_type.is_int_const()) { get_expr()->int_const_expr(ctx, &width); } else { set_semant_error(this, "Bitfield width expression must be " "an integer constant"); width = 1; } if (width > int_type->bitfield_width()) { set_semant_error(this, "Bitfield width cannot be larger than " "width (%d bit%s) of %s", int_type->bitfield_width(), (int_type->bitfield_width() > 1 ? "s" : ""), int_type->name().c_str()); width = 1; } base_type = int_type->bitfield_of(width)->qualified_by(quals); if (has_declr()) { CType *type = get_declr_declr()->build_type(ctx, base_type); IDSYM *name_node = get_declr_declr()->find_name(); PooledString ident = name_node->pooled_string(); members->table.add(ident, type); } } } operator no_struct_declr extends struct_declr { } operator struct_declr_sym extends struct_declr { public virtual method void check_member(TypecheckContext *ctx, CompleteStructUnionType *members, CType *base_type) { struct_declr::phylum_cast(primary_alternative()) ->check_member(ctx, members, base_type); } } phylum param_decl { public virtual method CType *get_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } } // param_decl -> SeqR1E0star:specs declr:declr operator NamedParamDecl extends param_decl { public virtual method CType *get_type(TypecheckContext *ctx) { decl::TypeInfo base_info; for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->specify(ctx, &base_info); CType *base_type = decl::assemble_base_type(ctx, this, &base_info); return get_declr()->build_type(ctx, base_type); } } // param_decl -> SeqR1E0star:specs OptR13E1:declr operator UnnamedParamDecl extends param_decl { public virtual method CType *get_type(TypecheckContext *ctx) { decl::TypeInfo base_info; for (specs_iterator i = get_specs(); i; ++i) i.get_spec()->specify(ctx, &base_info); CType *base_type = decl::assemble_base_type(ctx, this, &base_info); if (has_declr()) return get_declr_declr()->build_type(ctx, base_type); else return base_type; } // if (ctx->decl_cx == DEF_PARAM && // base_type.spec_bits != decl::VOID) // set_semant_error(this, "Unnamed params not allowed in " // "function definition"); } operator no_param_decl extends param_decl { } operator param_decl_sym extends param_decl { public virtual method CType *get_type(TypecheckContext *ctx) { return param_decl::phylum_cast(primary_alternative())->get_type(ctx); } } phylum for_init { public virtual method void check_types(TypecheckContext *ctx) { } } // for_init -> OptR68E0:expr SEMI operator ExpressionInit extends for_init { public virtual method void check_types(TypecheckContext *ctx) { if (has_expr()) { ExprType type = get_expr_expr()->determine_type(ctx); } } } // for_init -> decl:decl operator DeclarationInit extends for_init { public virtual method void check_types(TypecheckContext *ctx) { get_decl()->check_types(ctx); } } operator no_for_init extends for_init { } operator for_init_sym extends for_init { public virtual method void check_types(TypecheckContext *ctx) { for_init::phylum_cast(primary_alternative())->check_types(ctx); } } phylum exprs { public virtual method ExprType determine_type(TypecheckContext *ctx) { return ExprType(ERROR_CLASS, 0); } public virtual method bool has_addr(TypecheckContext *ctx) { return false; } } // exprs -> exprs:left COMMA assign_expr:right operator CommaList extends exprs { } // exprs -> assign_expr:expr operator SingleExpr extends exprs { public virtual method ExprType determine_type(TypecheckContext *ctx) { return get_expr()->determine_type(ctx); } public virtual method bool has_addr(TypecheckContext *ctx) { return get_expr()->has_addr(ctx); } } operator no_exprs extends exprs { } operator exprs_sym extends exprs { public virtual method ExprType determine_type(TypecheckContext *ctx) { return exprs::phylum_cast(primary_alternative())->determine_type(ctx); } public virtual method bool has_addr(TypecheckContext *ctx) { return exprs::phylum_cast(primary_alternative())->has_addr(ctx); } } phylum stmt { public virtual method void check_types(TypecheckContext *ctx) { } } // stmt -> IDSYM:label COLON stmt:stmt operator LabeledStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { get_stmt()->check_types(ctx); } } // stmt -> CASE expr:expr COLON stmt:stmt operator CaseLabelStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_expr()->determine_type(ctx); if (type && !type.is_int_const()) set_semant_error(this, "Case label expression must be integer " "constant expression"); get_stmt()->check_types(ctx); } } // stmt -> DEFAULT COLON stmt:stmt operator DefaultLabelStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { get_stmt()->check_types(ctx); } } // stmt -> OptR68E0:expr SEMI operator ExprStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { if (has_expr()) { ExprType type = get_expr_expr()->determine_type(ctx); } } } // stmt -> comp_stmt:stmt operator CompoundStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { get_stmt()->check_types(ctx); } } // stmt -> IF LPAREN exprs:pred RPAREN stmt:t_stmt operator IfNoElseStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_pred()->determine_type(ctx); if (type && !type.ty->is_scalar()) set_semant_error(this, "Predicate in `if' statement must have " "scalar type, not %s", type.ty->name().c_str()); get_t_stmt()->check_types(ctx); } } // stmt -> IF LPAREN exprs:pred RPAREN stmt:t_stmt ELSE stmt:f_stmt operator IfElseStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_pred()->determine_type(ctx); if (type && !type.ty->is_scalar()) set_semant_error(this, "Predicate in `if' statement must have " "scalar type, not %s", type.ty->name().c_str()); get_t_stmt()->check_types(ctx); get_f_stmt()->check_types(ctx); } } // stmt -> SWITCH LPAREN exprs:val RPAREN stmt:stmt operator SwitchStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_val()->determine_type(ctx); if (type && !type.ty->is_integer()) set_semant_error(this, "Expression in `switch' statement must have" " integer type, not %s", type.ty->name().c_str()); get_stmt()->check_types(ctx); } } // stmt -> WHILE LPAREN exprs:val RPAREN stmt:stmt operator WhileStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_val()->determine_type(ctx); if (type && !type.ty->is_scalar()) set_semant_error(this, "Predicate in `while' statement must have " "scalar type, not %s", type.ty->name().c_str()); get_stmt()->check_types(ctx); } } // stmt -> DO stmt:stmt WHILE LPAREN exprs:val RPAREN SEMI operator DoWhileStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { ExprType type = get_val()->determine_type(ctx); if (type && !type.ty->is_scalar()) set_semant_error(this, "Predicate in do-while statement must have " "scalar type, not %s", type.ty->name().c_str()); get_stmt()->check_types(ctx); } } // stmt -> FOR LPAREN for_init:init OptR80E3:pred SEMI OptR80E5:inc RPAREN stmt:stmt operator ForStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { get_init()->check_types(ctx); if (has_pred()) { ExprType type = get_pred_expr()->determine_type(ctx); if (type && !type.ty->is_scalar()) set_semant_error(this, "Predicate in `for' statement must" " have scalar type, not %s", type.ty->name().c_str()); } if (has_inc()) { ExprType type = get_inc_expr()->determine_type(ctx); } get_stmt()->check_types(ctx); } } // stmt -> GOTO IDSYM:label SEMI operator GotoStatement extends stmt { } // stmt -> CONTINUE SEMI operator ContinueStatement extends stmt { } // stmt -> BREAK SEMI operator BreakStatement extends stmt { } // stmt -> RETURN OptR84E1:ret SEMI operator ReturnStatement extends stmt { public virtual method void check_types(TypecheckContext *ctx) { if (has_ret()) { ExprType tmp, type = get_ret_expr()->determine_type(ctx); if (!type) return; if ((tmp = type.to_rvalue())) { type = tmp; } else { set_semant_error(this, "Can't use %s as arg to return", type.name().c_str()); } if (ctx->return_type->is_void()) { set_semant_error(this, "Attempt to return a value of type %s " "from a function declared to return void", type.ty->name().c_str()); } else { // This sets its own error messages ExprType::assign_compat(ctx->return_type->unqualified(), type, "return", this); } } else { if (!ctx->return_type->is_void()) { set_semant_error(this, "Return of no value from a function " "declared to return %s", ctx->return_type->name().c_str()); return; } } string msg = "Return type declared to be " + ctx->return_type->name(); set_string_prop(MOUSE_OVER_MSG, msg.c_str()); compute_synth_attrs(true); } } operator no_stmt extends stmt { } operator stmt_sym extends stmt { public virtual method void check_types(TypecheckContext *ctx) { stmt::phylum_cast(primary_alternative())->check_types(ctx); } } phylum block_item { public virtual method void check_types(TypecheckContext *ctx) { } } // block_item -> decl:decl operator DeclarationItem extends block_item { public virtual method void check_types(TypecheckContext *ctx) { get_decl()->check_types(ctx); } } // block_item -> stmt:stmt operator StatementItem extends block_item { public virtual method void check_types(TypecheckContext *ctx) { get_stmt()->check_types(ctx); } } operator no_block_item extends block_item { } operator block_item_sym extends block_item { public virtual method void check_types(TypecheckContext *ctx) { block_item::phylum_cast(primary_alternative())->check_types(ctx); } } phylum int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { return 0; } public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } public static method bignum_t parse_int(const char *s, bool *decimal) { bignum_t value; if (s[0] == '0') { if (!s[1] || s[1] == 'u' || s[1] == 'U' || s[1] == 'l' || s[1] == 'L') { *decimal = true; return 0; } else if (s[1] == 'x' || s[1] == 'X') { *decimal = false; sscanf(&s[2], "%llx", &value); return value; } else if (s[1] >= '1' && s[1] <= '9') { *decimal = false; sscanf(&s[1], "%llo", &value); return value; } else { // error("Unexpected character after '0' in integer\n"); return 0; } } else { // assert(s[0] >= '1' && s[0] <= '9'); *decimal = true; sscanf(s, "%lld", &value); return value; } } } // int_const -> INT_CONST:it operator PlainIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (decimal) { if (value <= ctx->the_SignedIntType.max_val()) return &ctx->the_SignedIntType; else if (value <= ctx->the_LongIntType.max_val()) return &ctx->the_LongIntType; else if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_LongLongIntType; } } else { if (value <= ctx->the_SignedIntType.max_val()) return &ctx->the_SignedIntType; else if (value <= ctx->the_UnsignedIntType.max_val()) return &ctx->the_UnsignedIntType; else if (value <= ctx->the_LongIntType.max_val()) return &ctx->the_LongIntType; else if (value <= ctx->the_UnsignedLongType.max_val()) return &ctx->the_UnsignedLongType; else if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } } // int_const -> INT_CONST_U:it operator UnsignedIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (value <= ctx->the_UnsignedIntType.max_val()) return &ctx->the_UnsignedIntType; else if (value <= ctx->the_UnsignedLongType.max_val()) return &ctx->the_UnsignedLongType; else if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } // int_const -> INT_CONST_L:it operator LongIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (decimal) { if (value <= ctx->the_LongIntType.max_val()) return &ctx->the_LongIntType; else if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_LongLongIntType; } } else { if (value <= ctx->the_LongIntType.max_val()) return &ctx->the_LongIntType; else if (value <= ctx->the_UnsignedLongType.max_val()) return &ctx->the_UnsignedLongType; else if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } } // int_const -> INT_CONST_UL:it operator UnsignedLongIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (value <= ctx->the_UnsignedLongType.max_val()) return &ctx->the_UnsignedLongType; else if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } // int_const -> INT_CONST_LL:it operator LongLongIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (decimal) { if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_LongLongIntType; } } else { if (value <= ctx->the_LongLongIntType.max_val()) return &ctx->the_LongLongIntType; else if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } } // int_const -> INT_CONST_ULL:it operator UnsignedLongLongIntegerConstant extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { const char *s = get_it()->pooled_string().chars(); return int_const::parse_int(s, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { bool decimal; bignum_t value = get_value(ctx, &decimal); if (value <= ctx->the_UnsignedLongLongType.max_val()) return &ctx->the_UnsignedLongLongType; else { set_semant_error(this, "Integer constant too big"); return &ctx->the_UnsignedLongLongType; } } } operator no_int_const extends int_const { } operator int_const_sym extends int_const { public virtual method bignum_t get_value(TypecheckContext *ctx, bool *decimal) { return int_const::phylum_cast(primary_alternative()) ->get_value(ctx, decimal); } public virtual method CType *determine_type(TypecheckContext *ctx) { return int_const::phylum_cast(primary_alternative()) ->determine_type(ctx); } } phylum char_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } } // char_const -> CHAR_CONST:it operator PlainCharacterConstant extends char_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_SignedIntType; } } // char_const -> WIDE_CHAR_CONST:it operator WideCharacterConstant extends char_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return ctx->the_WideCharType; } } operator no_char_const extends char_const { } operator char_const_sym extends char_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return char_const::phylum_cast(primary_alternative()) ->determine_type(ctx); } } phylum float_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } } // float_const -> FLOAT_CONST:it operator FloatConstant extends float_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_FloatType; } } // float_const -> DOUBLE_CONST:it operator DoubleConstant extends float_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_DoubleType; } } // float_const -> LONGDOUBLE_CONST:it operator LongDoubleConstant extends float_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_LongDoubleType; } } operator no_float_const extends float_const { } operator float_const_sym extends float_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return float_const::phylum_cast(primary_alternative()) ->determine_type(ctx); } } phylum str_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return &ctx->the_UnimplementedType; } public static method string unquote(PooledString ps) { string s = ps.chars(); s = s.substr(1, s.length() - 2); return s; } public static method int real_length(const char *s) { const char *p = s; int len; for (len = 0; *p; len++) { if (*p == '\\') { p++; switch (*p) { case 'u': p += 4+1; break; case 'U': p += 8+1; break; case 'x': p++; while (isxdigit(*p)) p++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': p++; if (*p >= '0' && *p < '8') p++; if (*p >= '0' && *p < '8') p++; break; default: p++; } } else { p++; } } return len; } } // str_const -> SeqR151E0star:strs operator PlainStringConstant extends str_const { public virtual method CType *determine_type(TypecheckContext *ctx) { int len = 0; for (strs_iterator i = get_strs(); i; ++i) len += real_length(unquote(i.get_str()->pooled_string()).c_str()); return ctx->the_PlainCharType.array_of(len + 1); } } // str_const -> SeqR152E0star:strs operator WideStringConstant extends str_const { public virtual method CType *determine_type(TypecheckContext *ctx) { int len = 0; for (strs_iterator i = get_strs(); i; ++i) len += real_length(unquote(i.get_str()->pooled_string()).c_str()); return ctx->the_WideCharType->array_of(len + 1); } } operator no_str_const extends str_const { } operator str_const_sym extends str_const { public virtual method CType *determine_type(TypecheckContext *ctx) { return str_const::phylum_cast(primary_alternative()) ->determine_type(ctx); } }