// $Id: symbol.cpp,v 1.11 1999/03/09 14:37:17 shields Exp $ copyright notice #include "config.h" #include <sys/stat.h> #include <assert.h> #include "stream.h" #include "control.h" #include "ast.h" #include "semantic.h" #include "table.h" #include "zip.h" #ifdef UNIX_FILE_SYSTEM #include <dirent.h> #elif defined(WIN32_FILE_SYSTEM) #include <windows.h> #endif char *FileSymbol::java_suffix = StringConstant::U8S__DO_java; int FileSymbol::java_suffix_length = strlen(java_suffix); char *FileSymbol::class_suffix = StringConstant::U8S__DO_class; int FileSymbol::class_suffix_length = strlen(class_suffix); bool MethodSymbol::IsFinal() { return ((AccessFlags *) this) -> ACC_FINAL() || ((AccessFlags *) this) -> ACC_PRIVATE() || containing_type -> ACC_FINAL(); } wchar_t *MethodSymbol::Header(Semantic *sem, LexStream::TokenIndex token_location) { if (! this -> IsTyped()) this -> ProcessMethodSignature(sem, token_location); if (! header) { bool is_constructor = false; for (MethodSymbol *constr = containing_type -> FindConstructorSymbol(); constr; constr = constr -> next_method) { if (this == constr) { is_constructor = true; break; } } int length = this -> Type() -> ContainingPackage() -> PackageNameLength() + this -> Type() -> ExternalNameLength() + (is_constructor ? containing_type -> NameLength() : this -> NameLength()) + 5; // '/' after package_name // ' ' after type // '(' after name // ')' after all parameters // ';' to terminate for (int i = 0; i < NumFormalParameters(); i++) { VariableSymbol *formal = FormalParameter(i); length += (formal -> Type() -> ContainingPackage() -> PackageNameLength() + formal -> Type() -> ExternalNameLength() + formal -> NameLength() + 4); // '/' after package_name // ' ' after type // ',' and ' ' to separate this formal parameter from the next one } header = new wchar_t[length + 1]; // +1 for '\0' wchar_t *s = header; if (is_constructor) { for (wchar_t *s2 = this -> containing_type -> Name(); *s2; s2++) *s++ = *s2; } else { PackageSymbol *package = this -> Type() -> ContainingPackage(); wchar_t *package_name = package -> PackageName(); if (package -> PackageNameLength() > 0 && wcscmp(package_name, StringConstant::US__DO_) != 0) { while (*package_name) { *s++ = (*package_name == U_SLASH ? (wchar_t) U_DOT : *package_name); package_name++; } *s++ = U_DOT; } for (wchar_t *s2 = this -> Type() -> ExternalName(); *s2; s2++) *s++ = *s2; *s++ = U_SPACE; for (wchar_t *s3 = Name(); *s3; s3++) *s++ = *s3; } *s++ = U_LEFT_PARENTHESIS; if (NumFormalParameters() > 0) { for (int k = 0; k < NumFormalParameters(); k++) { VariableSymbol *formal = FormalParameter(k); PackageSymbol *package = formal -> Type() -> ContainingPackage(); wchar_t *package_name = package -> PackageName(); if (package -> PackageNameLength() > 0 && wcscmp(package_name, StringConstant::US__DO_) != 0) { while (*package_name) { *s++ = (*package_name == U_SLASH ? (wchar_t) U_DOT : *package_name); package_name++; } *s++ = U_DOT; } for (wchar_t *s2 = formal -> Type() -> ExternalName(); *s2; s2++) *s++ = *s2; *s++ = U_SPACE; for (wchar_t *s3 = formal -> Name(); *s3; s3++) *s++ = *s3; *s++ = U_COMMA; *s++ = U_SPACE; } s -= 2; // remove the last ',' and ' ' } *s++ = U_RIGHT_PARENTHESIS; *s++ = U_SEMICOLON; *s = U_NULL; assert((s - header) <= length); } return header; } MethodSymbol *SymbolTable::FindOverloadMethod(MethodSymbol *base_method, AstMethodDeclarator *method_declarator) { for (MethodSymbol *method = base_method; method; method = method -> next_method) { assert(method -> IsTyped()); if (method -> NumFormalParameters() == method_declarator -> NumFormalParameters()) { int i; for (i = method -> NumFormalParameters() - 1; i >= 0; i--) { AstFormalParameter *parameter = method_declarator -> FormalParameter(i); if (method -> FormalParameter(i) -> Type() != parameter -> parameter_symbol -> Type()) break; } if (i < 0) return method; } } return(MethodSymbol *) NULL; } void TypeSymbol::ProcessTypeHeaders() { AstClassDeclaration *class_declaration = declaration -> ClassDeclarationCast(); if (class_declaration) semantic_environment -> sem -> ProcessTypeHeaders(class_declaration); else semantic_environment -> sem -> ProcessTypeHeaders((AstInterfaceDeclaration *) declaration); } void TypeSymbol::ProcessMembers() { AstClassDeclaration *class_declaration = declaration -> ClassDeclarationCast(); if (class_declaration) semantic_environment -> sem -> ProcessMembers(class_declaration -> semantic_environment, class_declaration -> class_body); else semantic_environment -> sem -> ProcessMembers((AstInterfaceDeclaration *) declaration); } void TypeSymbol::CompleteSymbolTable() { AstClassDeclaration *class_declaration = declaration -> ClassDeclarationCast(); if (class_declaration) semantic_environment -> sem -> CompleteSymbolTable(class_declaration -> semantic_environment, class_declaration -> identifier_token, class_declaration -> class_body); else semantic_environment -> sem -> CompleteSymbolTable((AstInterfaceDeclaration *) declaration); } void TypeSymbol::ProcessExecutableBodies() { AstClassDeclaration *class_declaration = declaration -> ClassDeclarationCast(); if (class_declaration) semantic_environment -> sem -> ProcessExecutableBodies(class_declaration -> semantic_environment, class_declaration -> class_body); else semantic_environment -> sem -> ProcessExecutableBodies((AstInterfaceDeclaration *) declaration); } void TypeSymbol::RemoveCompilationReferences() { if (semantic_environment) { semantic_environment = NULL; declaration = NULL; // // TODO: What else needs to be reset? // if (table) { for (int i = 0; i < table -> NumVariableSymbols(); i++) table -> VariableSym(i) -> declarator = NULL; for (int j = 0; j < table -> NumMethodSymbols(); j++) table -> MethodSym(j) -> method_or_constructor_declaration = NULL; for (int k = 0; k < table -> NumTypeSymbols(); k++) table -> TypeSym(k) -> declaration = NULL; for (int l = 0; l < table -> NumAnonymousSymbols(); l++) table -> AnonymousSym(l) -> declaration = NULL; } } return; } TypeSymbol *TypeSymbol::GetArrayType(Semantic *sem, int num_dimensions_) { if (num_dimensions_ == 0) return this; if (num_dimensions_ < NumArrays()) return Array(num_dimensions_); if (NumArrays() == 0) AddArrayType(this); TypeSymbol *previous_array_type = Array(array -> Length() - 1); wchar_t *name = new wchar_t[this -> ExternalNameLength() + (num_dimensions_ * 2) + 1]; wcscpy(name, previous_array_type -> ExternalName()); for (int num = array -> Length(), len = previous_array_type -> ExternalNameLength() + 2; num <= num_dimensions_; num++, len = len + 2) { wcscat(name, StringConstant::US__LB__RB_); NameSymbol *name_sym = sem -> control.FindOrInsertName(name, len); AccessFlags acc_flags; acc_flags.SetACC_PUBLIC(); acc_flags.SetACC_FINAL(); TypeSymbol *type = new TypeSymbol(name_sym); type -> MarkHeaderProcessed(); type -> MarkConstructorMembersProcessed(); type -> MarkMethodMembersProcessed(); type -> MarkFieldMembersProcessed(); type -> MarkLocalClassProcessingCompleted(); type -> MarkSourceNoLongerPending(); type -> outermost_type = type; type -> SetFlags(acc_flags); type -> super = sem -> control.Object(); // // All arrays implement the interfaces java.io.Serializable and // java.io.Cloneable // if (sem -> control.option.one_one) type -> AddInterface(sem -> control.Serializable()); type -> AddInterface(sem -> control.Cloneable()); type -> base_type = this; type -> num_dimensions = num; type -> SetOwner(this -> ContainingPackage()); type -> table = new SymbolTable(3); // only 2 elements will be added to this table type -> SetSignature(sem -> control); MethodSymbol *method = type -> InsertMethodSymbol(sem -> control.clone_name_symbol); method -> SetType(sem -> control.Object()); method -> SetContainingType(type); method -> SetFlags(acc_flags); method -> SetBlockSymbol(new BlockSymbol(1)); // the associated symbol table will remain empty VariableSymbol *symbol = type -> InsertVariableSymbol(sem -> control.length_name_symbol); symbol -> SetFlags(acc_flags); symbol -> SetOwner(type); symbol -> SetType(sem -> control.int_type); type -> CompressSpace(); // space optimization AddArrayType(type); } delete [] name; return Array(num_dimensions_); } void TypeSymbol::SetLocation() { if (! declaration) file_location = new FileLocation(file_symbol); else { AstClassDeclaration *class_declaration = declaration -> ClassDeclarationCast(); AstInterfaceDeclaration *interface_declaration = declaration -> InterfaceDeclarationCast(); file_location = new FileLocation(semantic_environment -> sem -> lex_stream, (class_declaration ? class_declaration -> identifier_token : (interface_declaration ? interface_declaration -> identifier_token : ((AstClassInstanceCreationExpression *) declaration) -> class_body_opt -> left_brace_token))); } return; } void TypeSymbol::SetSignature(Control &control) { if (this -> num_dimensions > 0) { char *type_signature; TypeSymbol *subtype = this -> ArraySubtype(); int signature_len = strlen(subtype -> SignatureString()) + 1; // +1 for '[' type_signature = new char[signature_len + 1]; // +1 for '\0' type_signature[0] = U_LEFT_BRACKET; strcpy(type_signature + 1, subtype -> SignatureString()); this -> signature = control.Utf8_pool.FindOrInsert(type_signature, signature_len); this -> fully_qualified_name = this -> signature; delete [] type_signature; } else { wchar_t *package_name = this -> ContainingPackage() -> PackageName(); wchar_t *type_name = this -> ExternalName(); int len = this -> ContainingPackage() -> PackageNameLength() + this -> ExternalNameLength() + 4; // +1 for 'L' +1 for '/' +1 for ';' +1 for '\0' wchar_t *type_signature = new wchar_t[len]; wcscpy(type_signature, StringConstant::US_L); if (this -> ContainingPackage() -> PackageNameLength() > 0 && wcscmp(package_name, StringConstant::US__DO_) != 0) { wcscat(type_signature, package_name); wcscat(type_signature, StringConstant::US__SL_); } wcscat(type_signature, type_name); this -> fully_qualified_name = control.ConvertUnicodeToUtf8(type_signature + 1); // +1 to skip the initial L'L' wcscat(type_signature, StringConstant::US__SC_); this -> signature = control.ConvertUnicodeToUtf8(type_signature); delete [] type_signature; } return; } int SymbolTable::primes[] = {DEFAULT_HASH_SIZE, 101, 401, MAX_HASH_SIZE}; void SymbolTable::Rehash() { hash_size = primes[++prime_index]; delete [] base; base = (Symbol **) memset(new Symbol *[hash_size], 0, hash_size * sizeof(Symbol *)); int k; for (k = 0; k < NumTypeSymbols(); k++) { TypeSymbol *symbol = TypeSym(k); int i = symbol -> name_symbol -> index % hash_size; symbol -> next = base[i]; base[i] = symbol; } for (k = 0; k < NumMethodSymbols(); k++) { MethodSymbol *symbol = MethodSym(k); if (symbol -> next != symbol) // not an overload { int i = symbol -> name_symbol -> index % hash_size; symbol -> next = base[i]; base[i] = symbol; } } for (k = 0; k < NumVariableSymbols(); k++) { VariableSymbol *symbol = VariableSym(k); int i = symbol -> name_symbol -> index % hash_size; symbol -> next = base[i]; base[i] = symbol; } for (k = 0; k < NumOtherSymbols(); k++) { Symbol *symbol = OtherSym(k); if (! symbol -> BlockCast()) { int i = symbol -> Identity() -> index % hash_size; symbol -> next = base[i]; base[i] = symbol; } } return; } SymbolTable::SymbolTable(int hash_size_) : anonymous_symbol_pool(NULL), type_symbol_pool(NULL), method_symbol_pool(NULL), variable_symbol_pool(NULL), other_symbol_pool(NULL), constructor(NULL) { hash_size = (hash_size_ <= 0 ? 1 : hash_size_); prime_index = -1; do { if (hash_size < primes[prime_index + 1]) break; prime_index++; } while (primes[prime_index] < MAX_HASH_SIZE); base = (Symbol **) memset(new Symbol *[hash_size], 0, hash_size * sizeof(Symbol *)); } SymbolTable::~SymbolTable() { /* int n; int num_slots = 0; int total = 0; for (n = 0; n < hash_size; n++) { int num = 0; for (Symbol *s = base[n]; s; s = s -> next) num++; if (num > 0) { num_slots++; total += num; } } if (num_slots > 0) { cout << "\nDestroying a symbol table with base size " << hash_size << " containing " << num_slots << " non-empty slots\n"; for (n = 0; n < hash_size; n++) { int num = 0; for (Symbol *s = base[n]; s; s = s -> next) num++; if (num > 0) cout << " slot " << n << " contains " << num << " element(s)\n"; } } if (hash_size < total) total = total; */ for (int i = 0; i < NumAnonymousSymbols(); i++) delete AnonymousSym(i); delete anonymous_symbol_pool; for (int j = 0; j < NumTypeSymbols(); j++) delete TypeSym(j); delete type_symbol_pool; for (int k = 0; k < NumMethodSymbols(); k++) delete MethodSym(k); delete method_symbol_pool; for (int l = 0; l < NumVariableSymbols(); l++) delete VariableSym(l); delete variable_symbol_pool; for (int m = 0; m < NumOtherSymbols(); m++) delete OtherSym(m); delete other_symbol_pool; delete [] base; return; } PackageSymbol::~PackageSymbol() { delete [] package_name; delete table; } void PackageSymbol::SetPackageName() { this -> package_name_length = (owner ? owner -> PackageNameLength() + 1 : 0) + NameLength(); // +1 for '/' this -> package_name = new wchar_t[package_name_length + 1]; // +1 for '\0' if (owner) { wcscpy(this -> package_name, owner -> PackageName()); wcscat(this -> package_name, StringConstant::US__SL_); } else this -> package_name[0] = U_NULL; wcscat(this -> package_name, this -> Name()); assert(wcslen(this -> package_name) == this -> package_name_length); return; } TypeSymbol::TypeSymbol(NameSymbol *name_symbol_) : semantic_environment(NULL), declaration(NULL), file_symbol(NULL), file_location(NULL), name_symbol(name_symbol_), external_name_symbol(NULL), owner(NULL), outermost_type(NULL), super(NULL), base_type(NULL), index(CycleChecker::OMEGA), incremental_index(CycleChecker::OMEGA), status(0), local(NULL), non_local(NULL), supertypes_closure(NULL), subtypes(NULL), subtypes_closure(NULL), innertypes_closure(NULL), dependents(new SymbolSet()), parents(new SymbolSet()), dependents_closure(NULL), parents_closure(NULL), num_dimensions(0), class_literal_class(NULL), class_literal_method(NULL), static_initializer_method(NULL), block_initializer_method(NULL), signature(NULL), fully_qualified_name(NULL), class_literal_name(NULL), table(NULL), expanded_type_table(NULL), expanded_field_table(NULL), expanded_method_table(NULL), package(NULL), class_name(NULL), local_constructor_call_environments(NULL), private_access_methods(NULL), private_access_constructors(NULL), constructor_parameters(NULL), generated_constructors(NULL), enclosing_instances(NULL), class_literals(NULL), nested_types(NULL), interfaces(NULL), anonymous_types(NULL), array(NULL), nested_type_signatures(NULL) { Symbol::_kind = TYPE; } TypeSymbol::~TypeSymbol() { delete semantic_environment; delete local; delete non_local; delete supertypes_closure; delete subtypes; delete subtypes_closure; delete innertypes_closure; delete dependents; delete parents; delete table; delete expanded_type_table; delete expanded_field_table; delete expanded_method_table; delete file_location; delete [] class_name; for (int i = 1; i < NumArrays(); i++) delete Array(i); for (int k = 0; k < NumNestedTypeSignatures(); k++) delete [] NestedTypeSignature(k); delete nested_type_signatures; delete local_constructor_call_environments; delete private_access_methods; delete private_access_constructors; delete constructor_parameters; delete generated_constructors; delete enclosing_instances; delete class_literals; delete nested_types; delete interfaces; delete anonymous_types; delete array; } MethodSymbol::~MethodSymbol() { for (int i = 0; i < NumThrowsSignatures(); i++) delete [] ThrowsSignature(i); delete throws_signatures; delete formal_parameters; delete throws; delete initializer_constructors; delete block_symbol; // overload(s) delete [] header; } BlockSymbol::BlockSymbol(int hash_size) : table(hash_size > 0 ? new SymbolTable(hash_size) : (SymbolTable *) NULL), max_variable_index(-1), try_variable_index(0) { Symbol::_kind = BLOCK; } BlockSymbol::~BlockSymbol() { delete table; } PathSymbol::PathSymbol(NameSymbol *name_symbol_) : name_symbol(name_symbol_), zipfile(NULL) { Symbol::_kind = PATH; } PathSymbol::~PathSymbol() { if (zipfile) delete zipfile; } DirectorySymbol::DirectorySymbol(NameSymbol *name_symbol_, Symbol *owner_) : name_symbol(name_symbol_), owner(owner_), mtime(0), table(NULL), directory_name(NULL), entries(NULL) { Symbol::_kind = _DIRECTORY; } DirectorySymbol::~DirectorySymbol() { delete [] directory_name; delete entries; delete table; } void DirectorySymbol::SetDirectoryName() { PathSymbol *path_symbol = owner -> PathCast(); if (path_symbol) { if (strcmp(path_symbol -> Utf8Name(), StringConstant::U8S__DO_) == 0) { this -> directory_name_length = this -> Utf8NameLength(); this -> directory_name = new char[this -> directory_name_length + 1]; // +1 for '\0' strcpy(this -> directory_name, this -> Utf8Name()); } else { this -> directory_name_length = path_symbol -> Utf8NameLength(); this -> directory_name = new char[this -> directory_name_length + 1]; // +1 for '\0' strcpy(this -> directory_name, path_symbol -> Utf8Name()); } } else { DirectorySymbol *owner_directory = owner -> DirectoryCast(); if (this -> Name()[this -> NameLength() - 1] == U_SLASH || // An absolute file name ? strcmp(owner_directory -> DirectoryName(), StringConstant::U8S__DO_) == 0) // or is the owner "." ? { this -> directory_name_length = this -> Utf8NameLength(); this -> directory_name = new char[this -> directory_name_length + 1]; // +1 for '\0' strcpy(this -> directory_name, this -> Utf8Name()); } else { int owner_length = owner_directory -> DirectoryNameLength(); char *owner_name = owner_directory -> DirectoryName(); this -> directory_name_length = owner_length + this -> Utf8NameLength() + (owner_name[owner_length - 1] != U_SLASH ? 1 : 0); // +1 for '/' this -> directory_name = new char[this -> directory_name_length + 1]; // +1 for '\0' strcpy(this -> directory_name, owner_directory -> DirectoryName()); if (owner_name[owner_length - 1] != U_SLASH) strcat(this -> directory_name, StringConstant::U8S__SL_); strcat(this -> directory_name, this -> Utf8Name()); } } assert(strlen(this -> directory_name) == this -> directory_name_length); return; } void DirectorySymbol::ResetDirectory() { assert(! this -> IsZip()); // // TODO: the stat function does not work for directories in that the "modified" time stamp associated // with a directory is not updated when a file contained in the directory is changed. // For now, we always reread the directory. // // struct stat status; // if ((::SystemStat(this -> DirectoryName(), &status) == 0) && status.st_mtime > mtime) // { // this -> mtime = status.st_mtime; // // delete this -> entries; // this -> entries = new DirectoryTable(); // // ReadDirectory(); // } // // else if (! entries) // if we cannot read the directory, allocate a default directory. // this -> entries = new DirectoryTable(); // delete this -> entries; this -> entries = new DirectoryTable(); ReadDirectory(); return; } void DirectorySymbol::ReadDirectory() { #ifdef UNIX_FILE_SYSTEM DIR *directory = opendir(this -> DirectoryName()); if (directory) { for (dirent *entry = readdir(directory); entry; entry = readdir(directory)) { int length = strlen(entry -> d_name); // // Check if the file is a java source, a java class file or a subdirectory. // Since packages cannot start with '.', we skip all files that start with // a dot. That includes this directory "." and its parent ".." // if ((length > FileSymbol::java_suffix_length && FileSymbol::IsJavaSuffix(&entry -> d_name[length - FileSymbol::java_suffix_length])) || (length > FileSymbol::class_suffix_length && FileSymbol::IsClassSuffix(&entry -> d_name[length - FileSymbol::class_suffix_length])) || ((Case::Index(entry -> d_name, U_DOT) < 0) && SystemIsDirectory(entry -> d_name))) entries -> InsertEntry((DirectorySymbol *) this, entry -> d_name, length); } closedir(directory); } #elif defined(WIN32_FILE_SYSTEM) char *directory_name = new char[this -> DirectoryNameLength() + 3]; // +2 for "/*" +1 for '\0' strcpy(directory_name, this -> DirectoryName()); if (directory_name[this -> DirectoryNameLength() - 1] != U_SLASH) strcat(directory_name, StringConstant::U8S__SL_); strcat(directory_name, StringConstant::U8S__ST_); WIN32_FIND_DATA entry; HANDLE file_handle = FindFirstFile(directory_name, &entry); if (file_handle != INVALID_HANDLE_VALUE) { do { int length = strlen(entry.cFileName); // // Check if the file is a java source, a java class file or a subdirectory. // Since packages cannot start with '.', we skip all files that start with // a dot. That includes this directory "." and its parent ".." // bool is_java = (length > FileSymbol::java_suffix_length && FileSymbol::IsJavaSuffix(&entry.cFileName[length - FileSymbol::java_suffix_length])), is_class = (length > FileSymbol::class_suffix_length && FileSymbol::IsClassSuffix(&entry.cFileName[length - FileSymbol::class_suffix_length])); if (is_java || is_class || (entry.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY && Case::Index(entry.cFileName, U_DOT) < 0)) { char *clean_name = new char[length + 1]; for (int i = 0; i < length; i++) clean_name[i] = (entry.cFileName[i] == U_BACKSLASH ? U_SLASH : entry.cFileName[i]); if (is_java) strcpy(&clean_name[length - FileSymbol::java_suffix_length], FileSymbol::java_suffix); else if (is_class) strcpy(&clean_name[length - FileSymbol::class_suffix_length], FileSymbol::class_suffix); DirectoryEntry *entry = entries -> InsertEntry((DirectorySymbol *) this, clean_name, length); if (! is_java) entries -> InsertCaseInsensitiveEntry(entry); delete [] clean_name; } } while (FindNextFile(file_handle, &entry)); FindClose(file_handle); } delete [] directory_name; #endif return; } DirectorySymbol *FileSymbol::OutputDirectory() { return (output_directory ? output_directory : output_directory = Control::GetOutputDirectory(this)); } void FileSymbol::SetFileName() { PathSymbol *path_symbol = this -> PathSym(); char *directory_name = directory_symbol -> DirectoryName(); int directory_name_length = directory_symbol -> DirectoryNameLength(); bool dot_directory = (strcmp(directory_name, StringConstant::U8S__DO_) == 0); this -> file_name_length = (dot_directory ? 0 : directory_name_length) + this -> Utf8NameLength() + (path_symbol -> IsZip() // For zip files we need "()" for regular directory, we need 1 '/' ? 2 : (dot_directory || directory_name[directory_name_length - 1] == U_SLASH ? 0 : 1)) + (kind == JAVA ? java_suffix_length : class_suffix_length); file_name = new char[file_name_length + 1]; // +1 for '\0' if (dot_directory) file_name[0] = U_NULL; else { strcpy(file_name, directory_symbol -> DirectoryName()); if (path_symbol -> IsZip()) strcat(file_name, StringConstant::U8S__LP_); else if (directory_name[directory_name_length - 1] != U_SLASH) strcat(file_name, StringConstant::U8S__SL_); } strcat(file_name, this -> Utf8Name()); strcat(file_name, kind == JAVA ? FileSymbol::java_suffix : FileSymbol::class_suffix); if (path_symbol -> IsZip()) strcat(file_name, StringConstant::U8S__RP_); assert(strlen(this -> file_name) == this -> file_name_length); return; } void FileSymbol::CleanUp() { delete lex_stream; lex_stream = NULL; if (compilation_unit) { delete compilation_unit -> ast_pool; compilation_unit = NULL; } delete semantic; semantic = NULL; return; } void TypeSymbol::SetClassName() { int length; if (semantic_environment -> sem -> control.option.directory) { DirectorySymbol *output_directory = file_symbol -> OutputDirectory(); int directory_length = output_directory -> DirectoryNameLength(); char *directory_name = output_directory -> DirectoryName(); length = directory_length + this -> ExternalUtf8NameLength() + FileSymbol::class_suffix_length + 1; // +1 for / class_name = new char[length + 1]; // +1 for '\0' strcpy(class_name, directory_name); if (directory_name[directory_length - 1] != U_SLASH) strcat(class_name, StringConstant::U8S__SL_); } else { char *file_name = semantic_environment -> sem -> lex_stream -> FileName(); int n; for (n = semantic_environment -> sem -> lex_stream -> FileNameLength() - 1; n >= 0; n--) { if (file_name[n] == U_SLASH) break; } n++; length = n + this -> ExternalUtf8NameLength() + FileSymbol::class_suffix_length; class_name = new char[length + 1]; // +1 for '\0' strncpy(class_name, file_name, n); class_name[n] = U_NULL; } strcat(class_name, ExternalUtf8Name()); strcat(class_name, FileSymbol::class_suffix); assert(strlen(this -> class_name) <= length); return; } void TypeSymbol::ProcessNestedTypeSignatures(Semantic *sem, LexStream::TokenIndex tok) { for (int i = 0; i < NumNestedTypeSignatures(); i++) { int length = strlen(NestedTypeSignature(i)); wchar_t *nested_class_name = new wchar_t[length + 1]; sem -> ConvertUtf8ToUnicode(nested_class_name, NestedTypeSignature(i), length); NameSymbol *name_symbol = sem -> control.FindOrInsertName(nested_class_name, length); delete [] nested_class_name; delete [] NestedTypeSignature(i); sem -> ProcessNestedType(this, name_symbol, tok); } delete nested_type_signatures; nested_type_signatures = NULL; return; } void MethodSymbol::ProcessMethodThrows(Semantic *sem, LexStream::TokenIndex tok) { if (throws_signatures) { assert(sem); // // Process throws clause // for (int i = 0; i < NumThrowsSignatures(); i++) { int length = strlen(ThrowsSignature(i)); wchar_t *type_name = new wchar_t[length + 1]; sem -> ConvertUtf8ToUnicode(type_name, ThrowsSignature(i), length); this -> AddThrows(sem -> ReadType(this -> containing_type, type_name, tok)); delete [] type_name; delete [] ThrowsSignature(i); } delete throws_signatures; throws_signatures = NULL; } return; } void MethodSymbol::SetSignature(Control &control, VariableSymbol *this0_variable) { int len = 2 + strlen(this -> Type() -> SignatureString()); // +1 for '(' +1 for ')' if (this0_variable) len += strlen(this0_variable -> Type() -> SignatureString()); for (int i = 0; i < this -> NumFormalParameters(); i++) { TypeSymbol *formal_type = this -> FormalParameter(i) -> Type(); len += strlen(formal_type -> SignatureString()); } char *method_signature = new char[len + 1]; // +1 for '\0' method_signature[0] = U_LEFT_PARENTHESIS; int k = 1; if (this0_variable) { for (char *str = this0_variable -> Type() -> SignatureString(); *str; str++, k++) method_signature[k] = *str; } for (int j = 0; j < this -> NumFormalParameters(); j++) { TypeSymbol *formal_type = this -> FormalParameter(j) -> Type(); for (char *str = formal_type -> SignatureString(); *str; str++, k++) method_signature[k] = *str; } method_signature[k++] = U_RIGHT_PARENTHESIS; for (char *str = this -> Type() -> SignatureString(); *str; str++, k++) method_signature[k] = *str; method_signature[k] = U_NULL; this -> signature = control.Utf8_pool.FindOrInsert(method_signature, len); delete [] method_signature; return; } void MethodSymbol::ProcessMethodSignature(Semantic *sem, LexStream::TokenIndex token_location) { if (! this -> type_) { assert(sem); int num_parameters = 0; char *signature = this -> SignatureString(); signature++; // +1 to skip initial '(' // // For the constructor of an inner type, skip the "this$0" argument. // if (this -> containing_type -> IsInner() && this -> Identity() == sem -> control.init_name_symbol) { if (*signature != U_RIGHT_PARENTHESIS) { // // Move to next signature // char *str; for (str = signature; *str == U_LEFT_BRACKET; str++) ; if (*str == U_L) { for (str++; *str != U_SEMICOLON; str++) ; } int len = str - signature + 1; signature += len; // make signature point to next type } } while (*signature != U_RIGHT_PARENTHESIS) { // // Make up a name for each parameter... Recall that for an inner class we need to skip the this$0 parameter // NameSymbol *name_symbol = sem -> control.MakeParameter(++num_parameters); VariableSymbol *symbol = new VariableSymbol(name_symbol); symbol -> SetType(sem -> ProcessSignature(this -> containing_type, signature, token_location)); symbol -> MarkComplete(); this -> AddFormalParameter(symbol); // // Move to next signature // char *str; for (str = signature; *str == U_LEFT_BRACKET; str++) ; if (*str == U_L) { for (str++; *str != U_SEMICOLON; str++) ; } int len = str - signature + 1; signature += len; // make signature point to next type } signature++; // skip L')' // // Now set the type of the method. // this -> SetType(sem -> ProcessSignature(this -> containing_type, signature, token_location)); // // Create a symbol table for this method for consistency... and in order // to release the space used by the variable paramaters later. // BlockSymbol *block_symbol = new BlockSymbol(num_parameters); for (int k = 0; k < num_parameters; k++) block_symbol -> InsertVariableSymbol((*this -> formal_parameters)[k]); block_symbol -> CompressSpace(); // space optimization this -> SetBlockSymbol(block_symbol); } return; } void MethodSymbol::CleanUp() { BlockSymbol *block_symbol = new BlockSymbol(this -> NumFormalParameters()); // // Make a copy of each parameter into the new pared-down symbol table and // fix the FormalParameter information to identify the new symbol. // for (int k = 0; k < this -> NumFormalParameters(); k++) { VariableSymbol *formal_parameter = (*formal_parameters)[k], *symbol = block_symbol -> InsertVariableSymbol(formal_parameter -> Identity()); symbol -> SetType(formal_parameter -> Type()); symbol -> MarkComplete(); (*formal_parameters)[k] = symbol; } // // Destroy the old symbol and replace it by the new one. // delete this -> block_symbol; block_symbol -> CompressSpace(); // space optimization this -> SetBlockSymbol(block_symbol); this -> method_or_constructor_declaration = NULL; // remove reference to Ast structure return; } void VariableSymbol::ProcessVariableSignature(Semantic *sem, LexStream::TokenIndex token_location) { if (! this -> type_) { assert(sem); this -> SetType(sem -> ProcessSignature((TypeSymbol *) owner, signature_string, token_location)); } return; } bool TypeSymbol::IsNestedIn(TypeSymbol *type) { for (SemanticEnvironment *env = this -> semantic_environment; env != NULL; env = env -> previous) { if (env -> Type() == type) return true; } return false; } bool TypeSymbol::CanAccess(TypeSymbol *type) { assert(semantic_environment); SemanticEnvironment *env = this -> semantic_environment; // // Note that this case is only possible in the current environment (i.e., it is not recursively applicable) // as it is not possible to declare an inner class (even an anonymous one) within an explicit // constructor invocation. This is the case precisely because of the unavailability of the "this" // which one would need to pass to the inner class in question. See comment below... // if (env -> explicit_constructor_invocation && env -> explicit_constructor_invocation -> SuperCallCast()) { // // If we are processing a super call statement in the constructor of an inner class then // we have access to the this$0 (passed to the constructor of the inner class as parameter) but // not to the "this" of the inner class in question, unless it is static. // if (this -> IsSubclass(type)) return this -> ACC_STATIC(); // "this" class is accessible only if it is static. if (this -> IsInner()) { if (this -> ContainingType() -> IsSubclass(type)) return true; env = env -> previous; // skip "this" type. } } for (; env != NULL; env = env -> previous) { if (env -> StaticRegion()) // are we in a static environment? break; else if (env -> Type() -> IsSubclass(type)) // then, check if we reached the type in question or one of its superclasses; return true; else if (env -> Type() -> ACC_STATIC()) // next, check whether or not the current type is static... break; } return false; } // // Given two types T and T2 in different packages, the type T has protected // access to T2 iff T or any class in which T is lexically enclosed is a subclass // of T2 or of some other type T3 that lexically encloses T2. // // Of course, T2 and all its enclosing classes, if any, must have been declared // either public or protected, otherwise they could not be eligible as a superclass // candidate. We do not (and need not) check for that condition here. // bool TypeSymbol::HasProtectedAccessTo(TypeSymbol *target_type) { assert(semantic_environment); for (SemanticEnvironment *env = this -> semantic_environment; env != NULL; env = env -> previous) { TypeSymbol *main_type = env -> Type(); for (TypeSymbol *type = target_type; type; type = type -> owner -> TypeCast()) { if (main_type -> IsSubclass(type)) // then, check if we reached the type in question or one of its superclasses; return true; } } return false; } inline NameSymbol *TypeSymbol::GetThisName(Control &control, int n) { wchar_t info[12], *str = &info[11]; *str = U_NULL; int num = n; do { *--str = (U_0 + num % 10); num /= 10; } while (num != 0); int length = wcslen(StringConstant::US__this_DOLLAR) + (&info[11] - str); wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__this_DOLLAR); wcscat(name, str); NameSymbol *name_symbol = control.FindOrInsertName(name, length); delete [] name; return name_symbol; } VariableSymbol *TypeSymbol::InsertThis(int n) { assert(IsInner()); Control &control = semantic_environment -> sem -> control; VariableSymbol *variable_symbol = NULL; if (n == 0) { assert(NumConstructorParameters() == 0); // no local shadows and no this$0 !!! assert(NumEnclosingInstances() == 0); // // Create a this0 pointer for an inner class. // variable_symbol = InsertVariableSymbol(control.this0_name_symbol); variable_symbol -> MarkSynthetic(); variable_symbol -> SetType(ContainingType()); variable_symbol -> SetACC_PRIVATE(); // variable_symbol -> SetACC_FINAL(); variable_symbol -> SetOwner((TypeSymbol *) this); variable_symbol -> MarkComplete(); AddConstructorParameter(variable_symbol); AddEnclosingInstance(variable_symbol); // must at least have this$0 } else { assert(NumEnclosingInstances() == n); // // Create a this$n pointer. // variable_symbol = InsertVariableSymbol(GetThisName(control, n)); variable_symbol -> MarkSynthetic(); variable_symbol -> SetType(EnclosingInstance(n - 1) -> Type() -> ContainingType()); variable_symbol -> SetACC_PRIVATE(); // variable_symbol -> SetACC_FINAL(); variable_symbol -> SetOwner((TypeSymbol *) this); variable_symbol -> MarkComplete(); AddEnclosingInstance(variable_symbol); } return variable_symbol; } TypeSymbol *TypeSymbol::FindOrInsertClassLiteralClass(LexStream::TokenIndex tok) { Semantic *sem = semantic_environment -> sem; AstCompilationUnit *compilation_unit = sem -> compilation_unit; Control &control = sem -> control; assert(this == outermost_type); if (! this -> class_literal_class) { AstClassInstanceCreationExpression *class_creation = compilation_unit -> ast_pool -> GenClassInstanceCreationExpression(); class_creation -> base_opt = NULL; class_creation -> dot_token_opt = 0; class_creation -> new_token = tok; AstSimpleName *ast_type= compilation_unit -> ast_pool -> GenSimpleName(tok); class_creation -> class_type = compilation_unit -> ast_pool -> GenTypeExpression(ast_type); class_creation -> left_parenthesis_token = tok; class_creation -> right_parenthesis_token = tok; AstClassBody *class_body = compilation_unit -> ast_pool -> GenClassBody(); class_body -> left_brace_token = tok; class_body -> right_brace_token = tok; class_creation -> class_body_opt = class_body; TypeSymbol *class_literal_type = sem -> GetAnonymousType(class_creation, control.Object()); (void) class_literal_type -> FindOrInsertClassLiteralMethod(control); sem -> AddDependence(class_literal_type, control.Class(), tok); this -> class_literal_class = class_literal_type; } return this -> class_literal_class; } MethodSymbol *TypeSymbol::FindOrInsertClassLiteralMethod(Control &control) { if (! class_literal_method) { BlockSymbol *block_symbol = new BlockSymbol(1); // the associated symbol table will contain 1 element block_symbol -> max_variable_index = 0; NameSymbol *name_symbol = control.FindOrInsertName(StringConstant::US__class_DOLLAR, wcslen(StringConstant::US__class_DOLLAR)); class_literal_method = InsertMethodSymbol(name_symbol); class_literal_method -> SetType(control.Class()); class_literal_method -> SetACC_STATIC(); class_literal_method -> SetContainingType((TypeSymbol *) this); class_literal_method -> SetBlockSymbol(block_symbol); VariableSymbol *variable_symbol = block_symbol -> InsertVariableSymbol(control.MakeParameter(1)); variable_symbol -> MarkSynthetic(); variable_symbol -> SetType(control.String()); variable_symbol -> SetOwner(class_literal_method); variable_symbol -> SetLocalVariableIndex(block_symbol -> max_variable_index++); class_literal_method -> AddFormalParameter(variable_symbol); class_literal_method -> SetSignature(control); } return class_literal_method; } Utf8LiteralValue *TypeSymbol::FindOrInsertClassLiteralName(Control &control) { if (! class_literal_name) { int length = fully_qualified_name -> length; char *slashed_name = fully_qualified_name -> value; char *name = new char[length + 1]; for (int i = 0; i < length; i++) name[i] = (slashed_name[i] == U_SLASH ? (wchar_t) U_DOT : slashed_name[i]); name[length] = U_NULL; class_literal_name = control.Utf8_pool.FindOrInsert(name, length); delete [] name; } return class_literal_name; } VariableSymbol *TypeSymbol::FindOrInsertClassLiteral(TypeSymbol *type) { assert(IsTopLevel() && (! type -> Primitive())); Semantic *sem = semantic_environment -> sem; Control &control = sem -> control; (void) this -> FindOrInsertClassLiteralMethod(control); (void) type -> FindOrInsertClassLiteralName(control); NameSymbol *name_symbol = NULL; char *signature = type -> SignatureString(); if (signature[0] == U_LEFT_BRACKET) // an array? { int array_length = wcslen(StringConstant::US__array), length = strlen(signature) + array_length; wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__array); int i, k; for (i = 0, k = array_length; signature[i] == U_LEFT_BRACKET; i++, k++) name[k] = U_DOLLAR; for (wchar_t ch = signature[i++]; ch && ch != U_SEMICOLON; ch = signature[i++]) name[k++] = (ch == U_SLASH ? (wchar_t) U_DOLLAR : ch); name[k] = U_NULL; name_symbol = control.FindOrInsertName(name, k); delete [] name; } else if (signature[0] == U_L) // a reference type ? { int class_length = wcslen(StringConstant::US__class_DOLLAR), length = strlen(signature) + class_length; wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__class_DOLLAR); int i = 0, k = class_length; for (wchar_t ch = signature[i++]; ch && ch != U_SEMICOLON; ch = signature[i++]) name[k++] = (ch == U_SLASH ? (wchar_t) U_DOLLAR : ch); name[k] = U_NULL; name_symbol = control.FindOrInsertName(name, k); delete [] name; } VariableSymbol *variable_symbol = FindVariableSymbol(name_symbol); if (! variable_symbol) { variable_symbol = InsertVariableSymbol(name_symbol); variable_symbol -> MarkSynthetic(); variable_symbol -> SetType(control.Class()); variable_symbol -> SetACC_PRIVATE(); variable_symbol -> SetACC_STATIC(); variable_symbol -> SetOwner((TypeSymbol *) this); variable_symbol -> MarkComplete(); AddClassLiteral(variable_symbol); } return variable_symbol; } VariableSymbol *TypeSymbol::FindOrInsertLocalShadow(VariableSymbol *local) { assert(this -> IsLocal()); Control &control = semantic_environment -> sem -> control; VariableSymbol *variable = FindVariableSymbol(local -> Identity()); // // For a local class, if it does not yet have a shadow for a local variable // that it needs access to, create one. // // Note that since this function is always invoked after the symbol // table for the type in question has been extended, the local shadow will // not appear in the expanded_field_table. Creating a shadow in the // expanded_field_table as well would cut down on the number of calls to // this function. However, the reason why we don't create such a shadow is // that since the new symbol is assigned a new name on the fly, its // name_symbol will fall outside the range of the expanded field table in // question. // if (! variable) { variable = InsertVariableSymbol(local -> Identity()); variable -> MarkSynthetic(); variable -> accessed_local = local; variable -> SetType(local -> Type()); variable -> SetACC_PRIVATE(); // variable -> SetACC_FINAL(); variable -> SetOwner((TypeSymbol *) this); variable -> MarkComplete(); int length = 4 + local -> NameLength(); // +4 for val$ wchar_t *external_name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(external_name, StringConstant::US__val_DOLLAR); wcscat(external_name, local -> Name()); variable -> SetExternalIdentity(control.FindOrInsertName(external_name, length)); AddConstructorParameter(variable); delete [] external_name; for (int i = 0; i < NumGeneratedConstructors(); i++) { MethodSymbol *constructor = GeneratedConstructor(i); VariableSymbol *symbol = constructor -> block_symbol -> FindVariableSymbol(local -> Identity()); if (! symbol) { symbol = constructor -> block_symbol -> InsertVariableSymbol(local -> Identity()); symbol -> MarkSynthetic(); symbol -> SetType(variable -> Type()); symbol -> SetOwner(constructor); symbol -> SetExternalIdentity(external_name_symbol); symbol -> SetLocalVariableIndex(constructor -> block_symbol -> max_variable_index++); if (symbol -> Type() == control.long_type || symbol -> Type() == control.double_type) constructor -> block_symbol -> max_variable_index++; constructor -> AddFormalParameter(symbol); } } } return variable; } MethodSymbol *TypeSymbol::GetReadAccessMethod(MethodSymbol *member) { if (! member -> read_method) { TypeSymbol *type = member -> containing_type; Semantic *sem = type -> semantic_environment -> sem; Control &control = sem -> control; StoragePool *ast_pool = sem -> compilation_unit -> ast_pool; wchar_t info[12], *str = &info[11]; int n = (member -> Identity() == control.init_name_symbol ? type -> NumPrivateAccessConstructors() : type -> NumPrivateAccessMethods()); *str = U_NULL; do { *--str = (U_0 + n % 10); n /= 10; } while (n != 0); int length = 7 + (&info[11] - str); // +7 for access$ wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__access_DOLLAR); wcscat(name, str); BlockSymbol *block_symbol = new BlockSymbol(member -> NumFormalParameters() + 3); MethodSymbol *method = type -> InsertMethodSymbol(control.FindOrInsertName(name, length)); method -> MarkSynthetic(); method -> SetType(member -> Type()); if (member -> ACC_STATIC()) { method -> SetACC_STATIC(); block_symbol -> max_variable_index = 0; } else block_symbol -> max_variable_index = 1; method -> SetContainingType(type); method -> SetBlockSymbol(block_symbol); for (int i = 0; i < member -> NumThrows(); i++) method -> AddThrows(member -> Throws(i)); // // // if (member -> Identity() != control.init_name_symbol) // not a constructor { for (int i = 0; i < member -> NumFormalParameters(); i++) { VariableSymbol *parm = method -> block_symbol -> InsertVariableSymbol(member -> FormalParameter(i) -> Identity()); parm -> MarkSynthetic(); parm -> SetType(member -> FormalParameter(i) -> Type()); parm -> SetOwner(method); parm -> SetLocalVariableIndex(block_symbol -> max_variable_index++); if (parm -> Type() == control.long_type || parm -> Type() == control.double_type) block_symbol -> max_variable_index++; method -> AddFormalParameter(parm); } method -> SetSignature(control); // A read access method has no throws clause ! type -> AddPrivateAccessMethod(method); } else { method -> SetExternalIdentity(member -> Identity()); Ast *declaration = member -> method_or_constructor_declaration; AstMethodDeclaration *method_declaration = declaration -> MethodDeclarationCast(); AstMethodDeclarator *declarator = (method_declaration ? method_declaration -> method_declarator : ((AstConstructorDeclaration *) declaration) -> constructor_declarator); LexStream::TokenIndex loc = declarator -> identifier_token; AstMethodDeclarator *method_declarator = ast_pool -> GenMethodDeclarator(); method_declarator -> identifier_token = loc; method_declarator -> left_parenthesis_token = declarator -> LeftToken(); method_declarator -> right_parenthesis_token = declarator -> RightToken(); AstThisCall *this_call = ast_pool -> GenThisCall(); this_call -> base_opt = NULL; this_call -> this_token = loc; this_call -> left_parenthesis_token = loc; this_call -> right_parenthesis_token = loc; this_call -> semicolon_token = loc; this_call -> symbol = member; VariableSymbol *this0_variable = NULL; if (type -> IsInner()) { this0_variable = block_symbol -> InsertVariableSymbol(control.this0_name_symbol); this0_variable -> MarkSynthetic(); this0_variable -> SetType(type -> ContainingType()); this0_variable -> SetOwner(method); this0_variable -> SetLocalVariableIndex(block_symbol -> max_variable_index++); } for (int i = 0; i < member -> NumFormalParameters(); i++) { VariableSymbol *parm = method -> block_symbol -> InsertVariableSymbol(member -> FormalParameter(i) -> Identity()); parm -> MarkSynthetic(); parm -> SetType(member -> FormalParameter(i) -> Type()); parm -> SetOwner(method); parm -> SetLocalVariableIndex(block_symbol -> max_variable_index++); if (parm -> Type() == control.long_type || parm -> Type() == control.double_type) block_symbol -> max_variable_index++; method -> AddFormalParameter(parm); // // Since private_access_constructors will compiled (see body.cpp), we must create // valid ast_simple_names for its parameters. // AstVariableDeclaratorId *variable_declarator_name = declarator -> FormalParameter(i) -> variable_declarator_name; AstSimpleName *simple_name = ast_pool -> GenSimpleName(variable_declarator_name -> identifier_token); simple_name -> symbol = parm; this_call -> AddArgument(simple_name); } method -> SetSignature(control, this0_variable); // A read access method has no throws clause ! AstReturnStatement *return_statement = ast_pool -> GenReturnStatement(); return_statement -> return_token = loc; return_statement -> expression_opt = NULL; return_statement -> semicolon_token = loc; return_statement -> is_reachable = true; AstBlock *block = ast_pool -> GenBlock(); block -> AllocateBlockStatements(1); // this block contains one statement block -> left_brace_token = loc; block -> right_brace_token = loc; block -> is_reachable = true; block -> can_complete_normally = false; block -> AddStatement(return_statement); AstConstructorBlock *constructor_block = ast_pool -> GenConstructorBlock(); constructor_block -> left_brace_token = loc; constructor_block -> explicit_constructor_invocation_opt = this_call; constructor_block -> block = block; constructor_block -> right_brace_token = loc; AstConstructorDeclaration *constructor_declaration = ast_pool -> GenConstructorDeclaration(); constructor_declaration -> constructor_declarator = method_declarator; constructor_declaration -> constructor_body = constructor_block; constructor_declaration -> constructor_symbol = method; method -> method_or_constructor_declaration = constructor_declaration; if (type -> IsLocal()) sem -> GenerateLocalConstructor(method); type -> AddPrivateAccessConstructor(method); } method -> accessed_member = member; member -> read_method = method; delete [] name; } return member -> read_method; } MethodSymbol *TypeSymbol::GetReadAccessMethod(VariableSymbol *member) { if (! member -> read_method) { TypeSymbol *type = member -> owner -> TypeCast(); Semantic *sem = type -> semantic_environment -> sem; Control &control = sem -> control; wchar_t info[12], *str = &info[11]; int n = type -> NumPrivateAccessMethods(); *str = U_NULL; do { *--str = (U_0 + n % 10); n /= 10; } while (n != 0); int length = 7 + (&info[11] - str); // +7 for access$ wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__access_DOLLAR); wcscat(name, str); MethodSymbol *method = type -> InsertMethodSymbol(control.FindOrInsertName(name, length)); method -> MarkSynthetic(); method -> SetType(member -> Type()); if (member -> ACC_STATIC()) method -> SetACC_STATIC(); method -> SetContainingType(type); // No block_symbol is associated with an access method ! // A read access method for a field has no formal parameters ! method -> SetSignature(control); // A read access method has no throws clause ! method -> accessed_member = member; member -> read_method = method; type -> AddPrivateAccessMethod(method); delete [] name; } return member -> read_method; } MethodSymbol *TypeSymbol::GetWriteAccessMethod(VariableSymbol *member) { if (! member -> write_method) { TypeSymbol *type = member -> owner -> TypeCast(); Semantic *sem = type -> semantic_environment -> sem; Control &control = sem -> control; wchar_t info[12], *str = &info[11]; int n = type -> NumPrivateAccessMethods(); *str = U_NULL; do { *--str = (U_0 + n % 10); n /= 10; } while (n != 0); int length = 7 + (&info[11] - str); // +7 for access$ wchar_t *name = new wchar_t[length + 1]; // +1 for '\0'; wcscpy(name, StringConstant::US__access_DOLLAR); wcscat(name, str); MethodSymbol *method = type -> InsertMethodSymbol(control.FindOrInsertName(name, length)); method -> MarkSynthetic(); method -> SetType(sem -> control.void_type); if (member -> ACC_STATIC()) method -> SetACC_STATIC(); method -> SetContainingType(type); method -> SetBlockSymbol(new BlockSymbol(3)); // the associated symbol table will contain 1 element // // A write access method takes exactly one argument of the same type // as the variable. For a member named "m", its body will consist of // the single statement: // // this.m = m; // VariableSymbol *symbol = method -> block_symbol -> InsertVariableSymbol(member -> Identity()); symbol -> MarkSynthetic(); symbol -> SetType(member -> Type()); method -> AddFormalParameter(symbol); method -> SetSignature(control); // A write access method has no throws clause ! method -> accessed_member = member; member -> write_method = method; type -> AddPrivateAccessMethod(method); delete [] name; } return member -> write_method; }