// $Id: control.cpp,v 1.4 1999/03/10 19:59:21 shields Exp $ copyright notice #include "config.h" #include <sys/stat.h> #include "control.h" #include "scanner.h" #include "parser.h" #include "semantic.h" #include "unicode.h" #include "error.h" #include "bytecode.h" Control::Control(ArgumentExpander &arguments, Option &option_) : return_code(0), option(option_), dot_classpath_index(0), system_semantic(NULL), semantic(1024), needs_body_work(1024), type_trash_bin(1024), input_java_file_set(1021), input_class_file_set(1021), expired_file_set(), recompilation_file_set(1021), Object_type(NULL), Cloneable_type(NULL), Serializable_type(NULL), String_type(NULL), Void_type(NULL), Boolean_type(NULL), Byte_type(NULL), Short_type(NULL), Character_type(NULL), Integer_type(NULL), Long_type(NULL), Float_type(NULL), Double_type(NULL), Class_type(NULL), StringBuffer_type(NULL), Throwable_type(NULL), RuntimeException_type(NULL), Error_type(NULL), int_pool(&bad_value), long_pool(&bad_value), float_pool(&bad_value), double_pool(&bad_value), Utf8_pool(&bad_value) #ifdef TEST , line_count(0), class_files_read(0), class_files_written(0), class_file_id(0), input_files_processed(0) #endif {Initialize top level variables in the Control class, adding a set of names to the global NameLookupTable ProcessGlobalNameSymbols(); Create the unnamed package and set up global names. ProcessUnnamedPackage(); ProcessPath(); ProcessSystemInformation(); // // Instantiate a scanner and a parser and initialize the static members for the semantic processors. // scanner = new Scanner(*this); parser = new Parser(); SemanticError::StaticInitializer(); // // Process all file names specified in command line // ProcessNewInputFiles(input_java_file_set, arguments, option.first_file_index); // // For each input file, copy it into the input_files array and process its package declaration. // StoragePool *ast_pool = new StoragePool(64); // how much space do we need? estimate 64 tokens. FileSymbol **input_files = new FileSymbol*[input_java_file_set.Size() + 1]; int num_files = 0; for (FileSymbol *file_symbol = (FileSymbol *) input_java_file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol *) input_java_file_set.NextElement()) { input_files[num_files++] = file_symbol; scanner -> Scan(file_symbol); if (file_symbol -> lex_stream) // did we have a successful scan! { AstPackageDeclaration *package_declaration = parser -> PackageHeaderParse(file_symbol -> lex_stream, ast_pool); ProcessPackageDeclaration(file_symbol, package_declaration); ast_pool -> Reset(); } } // // // FileSymbol *main_file_clone; if (num_files > 0) main_file_clone = input_files[0] -> Clone(); else { // // Some name, any name !!! We use dot_name_symbol as a bad file name because // no file can be named ".". // FileSymbol *file_symbol = classpath[dot_classpath_index] -> RootDirectory() -> InsertFileSymbol(dot_name_symbol); file_symbol -> directory_symbol = classpath[dot_classpath_index] -> RootDirectory(); file_symbol -> SetJava(); main_file_clone = file_symbol -> Clone(); } main_file_clone -> semantic = new Semantic(*this, main_file_clone); system_semantic = main_file_clone -> semantic; scanner -> SetUp(main_file_clone); #ifdef WIN32_FILE_SYSTEM // // // if (option.BadMainDisk()) { system_semantic -> ReportSemError(SemanticError::NO_CURRENT_DIRECTORY, 0, 0); } #endif // // // for (int o = 0; o < option.bad_options.Length(); o++) { system_semantic -> ReportSemError((SemanticError::SemanticErrorKind) option.bad_options[o] -> kind, 0, 0, option.bad_options[o] -> name); } // // // for (int l = 0; l < bad_zip_filenames.Length(); l++) { system_semantic -> ReportSemError(SemanticError::CANNOT_OPEN_ZIP_FILE, 0, 0, bad_zip_filenames[l]); } // // // if (system_package -> directory.Length() == 0) { system_semantic -> ReportSemError(SemanticError::PACKAGE_NOT_FOUND, 0, 0, StringConstant::US_java_SL_lang); } // // When the -d option is specified, create the relevant // directories if they don't already exist. // if (option.directory) { if (! ::SystemIsDirectory(option.directory)) { for (char *ptr = option.directory; *ptr; ptr++) { char delimiter = *ptr; if (delimiter == U_SLASH) { *ptr = U_NULL; if (! ::SystemIsDirectory(option.directory)) ::SystemMkdir(option.directory); *ptr = delimiter; } } ::SystemMkdir(option.directory); if (! ::SystemIsDirectory(option.directory)) { int length = strlen(option.directory); wchar_t *name = new wchar_t[length + 1]; for (int i = 0; i < length; i++) name[i] = option.directory[i]; name[length] = U_NULL; system_semantic -> ReportSemError(SemanticError::CANNOT_OPEN_DIRECTORY, 0, 0, name); delete [] name; } } } // // // for (int m = 0; m < bad_input_filenames.Length(); m++) { system_semantic -> ReportSemError(SemanticError::BAD_INPUT_FILE, 0, 0, bad_input_filenames[m]); } // // // for (int n = 0; n < unreadable_input_filenames.Length(); n++) { system_semantic -> ReportSemError(SemanticError::UNREADABLE_INPUT_FILE, 0, 0, unreadable_input_filenames[n]); } // // // if (system_semantic -> NumErrors() > 0) system_semantic -> PrintMessages(); else { system_semantic -> PrintMessages(); // there might be some warnings we want to print... // // // input_java_file_set.SetEmpty(); for (int i = 0; i < num_files; i++) { FileSymbol *file_symbol = input_files[i]; if (! input_java_file_set.IsElement(file_symbol)) ProcessFile(file_symbol); } // // Clean up all the file that have just been compiled i this new batch. // for (FileSymbol *file_symbol = (FileSymbol *) input_java_file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol *) input_java_file_set.NextElement()) { CleanUp(file_symbol); } // // If more messages were added to system_semantic, print them... // system_semantic -> PrintMessages(); if (system_semantic -> return_code > 0) return_code = 1; // // If the incremental flag is on, check to see if the user wants us to recompile. // if (option.incremental) { option.depend = false; // The depend flag should only be in effect in the first pass for (bool recompile = IncrementalRecompilation(); recompile; recompile = IncrementalRecompilation()) { return_code = 0; // reset the return code as we may compile clean in this pass system_semantic -> return_code = 0; // // // for (int m = 0; m < bad_input_filenames.Length(); m++) { system_semantic -> ReportSemError(SemanticError::BAD_INPUT_FILE, 0, 0, bad_input_filenames[m]); } // // // for (int n = 0; n < unreadable_input_filenames.Length(); n++) { system_semantic -> ReportSemError(SemanticError::UNREADABLE_INPUT_FILE, 0, 0, unreadable_input_filenames[n]); } FileSymbol *file_symbol; num_files = 0; delete [] input_files; // delete previous copy input_files = new FileSymbol*[recompilation_file_set.Size()]; for (file_symbol = (FileSymbol *) recompilation_file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol *) recompilation_file_set.NextElement()) { input_java_file_set.RemoveElement(file_symbol); input_files[num_files++] = file_symbol; LexStream *lex_stream = file_symbol -> lex_stream; if (lex_stream) { AstPackageDeclaration *package_declaration = parser -> PackageHeaderParse(lex_stream, ast_pool); ProcessPackageDeclaration(file_symbol, package_declaration); ast_pool -> Reset(); } } // // If a file has been erased, remove it from the input file set. // for (file_symbol = (FileSymbol *) expired_file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol *) expired_file_set.NextElement()) { input_java_file_set.RemoveElement(file_symbol); } // // Reset the global objects before recompiling this new batch. // expired_file_set.SetEmpty(); recompilation_file_set.SetEmpty(); type_trash_bin.Reset(); // // For each file that should be recompiled, process it if it has not // already been dragged in by dependence. // for (int k = 0; k < num_files; k++) { FileSymbol *file_symbol = input_files[k]; if (! input_java_file_set.IsElement(file_symbol)) ProcessFile(file_symbol); } // // Clean up all the file that have just been compiled i this new batch. // for (file_symbol = (FileSymbol *) input_java_file_set.FirstElement(); file_symbol; file_symbol = (FileSymbol *) input_java_file_set.NextElement()) { CleanUp(file_symbol); } // // If any system error or warning was detected, print it... // system_semantic -> PrintMessages(); if (system_semantic -> return_code > 0) return_code = 1; } } // // Are we supposed to generate Makefiles? // if (option.makefile) { SymbolSet *candidates = new SymbolSet(input_java_file_set.Size() + input_class_file_set.Size()); *candidates = input_java_file_set; candidates -> Union(input_class_file_set); TypeDependenceChecker *dependence_checker = new TypeDependenceChecker((Control *) this, *candidates, type_trash_bin); dependence_checker -> PartialOrder(); dependence_checker -> OutputDependences(); delete dependence_checker; delete candidates; } } delete ast_pool; delete main_file_clone; // delete the clone of the main source file... #ifdef NO_LEAKS delete [] input_files; #endif return; } Control::~Control() { #ifdef NO_LEAKS for (int i = 0; i < bad_zip_filenames.Length(); i++) delete [] bad_zip_filenames[i]; for (int j = 0; j < bad_input_filenames.Length(); j++) delete [] bad_input_filenames[j]; for (int k = 0; k < unreadable_input_filenames.Length(); k++) delete [] unreadable_input_filenames[k]; for (int l = 0; l < root_directories.Length(); l++) delete root_directories[l]; delete scanner; delete parser; delete system_semantic; #endif #ifdef TEST if (option.debug_dump_lex || option.debug_dump_ast) { cout << line_count << " source lines read\n\n" << class_files_read << " \".class\" files read\n" << class_files_written << " \".class\" files written\n" << input_files_processed << " \".java\" files processed\n"; } #endif } PackageSymbol *Control::ProcessPackage(wchar_t *name) { int name_length = wcslen(name); wchar_t *package_name = new wchar_t[name_length]; int length; for (length = 0; length < name_length && name[length] != U_SLASH; length++) package_name[length] = name[length]; NameSymbol *name_symbol = FindOrInsertName(package_name, length); PackageSymbol *package_symbol = external_table.FindPackageSymbol(name_symbol); if (! package_symbol) { package_symbol = external_table.InsertPackageSymbol(name_symbol, NULL); FindPathsToDirectory(package_symbol); } while(length < name_length) { int start = ++length; for (int i = 0; length < name_length && name[length] != U_SLASH; i++, length++) package_name[i] = name[length]; name_symbol = FindOrInsertName(package_name, length - start); PackageSymbol *subpackage_symbol = package_symbol -> FindPackageSymbol(name_symbol); if (! subpackage_symbol) { subpackage_symbol = package_symbol -> InsertPackageSymbol(name_symbol); FindPathsToDirectory(subpackage_symbol); } package_symbol = subpackage_symbol; } delete [] package_name; return package_symbol; } // // When searching for a subdirectory in a zipped file, it must already be present in the // hierarchy. // DirectorySymbol *Control::FindSubdirectory(PathSymbol *path_symbol, wchar_t *name, int name_length) { wchar_t *directory_name = new wchar_t[name_length + 1]; DirectorySymbol *directory_symbol = path_symbol -> RootDirectory(); for (int start = 0, end; directory_symbol && start < name_length; start = end + 1) { end = start; for (int i = 0; end < name_length && name[end] != U_SLASH; i++, end++) directory_name[i] = name[end]; NameSymbol *name_symbol = FindOrInsertName(directory_name, end - start); directory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); } delete [] directory_name; return directory_symbol; } // // When searching for a directory in the system, if it is not already present in the hierarchy // insert it and attempt to read it from the system... // #ifdef UNIX_FILE_SYSTEM DirectorySymbol *Control::ProcessSubdirectories(wchar_t *source_name, int source_name_length) { DirectorySymbol *directory_symbol = classpath[dot_classpath_index] -> RootDirectory(); int name_length = (source_name_length < 0 ? 0 : source_name_length); wchar_t *name = new wchar_t[name_length + 1]; for (int i = 0; i < name_length; i++) name[i] = source_name[i]; name[name_length] = U_NULL; int end; for (end = 0; end < name_length && name[end] == U_SLASH; end++) // keep all extra leading '/' ; // // // wchar_t *directory_name = new wchar_t[name_length]; int length; if (end > 0) { for (length = 0; length < end; length++) directory_name[length] = name[length]; NameSymbol *name_symbol = FindOrInsertName(directory_name, length); DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(name_symbol); directory_symbol = subdirectory_symbol; } // // // for (int start = end; start < name_length; start = end) { for (length = 0; end < name_length && name[end] != U_SLASH; length++, end++) directory_name[length] = name[end]; if (length != 1 || directory_name[0] != U_DOT) // Not the current directory { if (length == 2 && directory_name[0] == U_DOT && directory_name[1] == U_DOT) // keep the current directory { if (directory_symbol -> Identity() == dot_name_symbol || directory_symbol -> Identity() == dot_dot_name_symbol) { DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(dot_dot_name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(dot_dot_name_symbol); directory_symbol = subdirectory_symbol; } else directory_symbol = directory_symbol -> owner -> DirectoryCast(); } else { NameSymbol *name_symbol = FindOrInsertName(directory_name, length); DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(name_symbol); directory_symbol = subdirectory_symbol; } } for (end++; end < name_length && name[end] == U_SLASH; end++) // skip all extra '/' ; } delete [] directory_name; delete [] name; return directory_symbol; } #elif defined(WIN32_FILE_SYSTEM) DirectorySymbol *Control::ProcessSubdirectories(wchar_t *source_name, int source_name_length) { DirectorySymbol *directory_symbol = classpath[dot_classpath_index] -> RootDirectory(); int name_length = (source_name_length < 0 ? 0 : source_name_length); wchar_t *name = new wchar_t[name_length + 1]; char *input_name = new char[name_length + 1]; for (int i = 0; i < name_length; i++) input_name[i] = name[i] = source_name[i]; input_name[name_length] = name[name_length] = U_NULL; if (name_length >= 2 && Case::IsAsciiAlpha(input_name[0]) && input_name[1] == U_COLON) // a disk was specified { char disk = input_name[0]; option.SaveCurrentDirectoryOnDisk(disk); if (SetCurrentDirectory(input_name)) { DWORD directory_length = GetCurrentDirectory(0, input_name); // first, get the right size char *full_directory_name = new char[directory_length + 1]; // allocate the directory DWORD length = GetCurrentDirectory(directory_length, full_directory_name); if (length <= directory_length) { for (char *ptr = full_directory_name; *ptr; ptr++) *ptr = (*ptr != U_BACKSLASH ? *ptr : (char) U_SLASH); // turn '\' to '/'. char *current_directory = option.GetMainCurrentDirectory(); int prefix_length = strlen(current_directory); int start = (prefix_length <= length && Case::StringSegmentEqual(current_directory, full_directory_name, prefix_length) && (full_directory_name[prefix_length] == U_SLASH || full_directory_name[prefix_length] == U_NULL) ? prefix_length + 1 : 0); if (start > length) name_length = 0; else if (start <= length) // note that we can assert that (start != length) { delete [] name; name_length = length - start; name = new wchar_t[name_length + 1]; for (int k = 0, i = start; i < length; i++, k++) name[k] = full_directory_name[i]; name[name_length] = U_NULL; } } delete [] full_directory_name; } option.ResetCurrentDirectoryOnDisk(disk); // reset the current directory on this disk option.SetMainCurrentDirectory(); // reset the real current directory... } // // // int end; if (name_length > 2 && Case::IsAsciiAlpha(name[0]) && name[1] == U_COLON && name[2] == U_SLASH) end = 3; else { for (end = 0; end < name_length && name[end] == U_SLASH; end++) // keep all extra leading '/' ; } // // // wchar_t *directory_name = new wchar_t[name_length]; int length; if (end > 0) { for (length = 0; length < end; length++) directory_name[length] = name[length]; NameSymbol *name_symbol = FindOrInsertName(directory_name, length); DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(name_symbol); directory_symbol = subdirectory_symbol; } // // // for (int start = end; start < name_length; start = end) { for (length = 0; end < name_length && name[end] != U_SLASH; length++, end++) directory_name[length] = name[end]; if (length != 1 || directory_name[0] != U_DOT) // Not the current directory { if (length == 2 && directory_name[0] == U_DOT && directory_name[1] == U_DOT) // keep the current directory { if (directory_symbol -> Identity() == dot_name_symbol || directory_symbol -> Identity() == dot_dot_name_symbol) { DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(dot_dot_name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(dot_dot_name_symbol); directory_symbol = subdirectory_symbol; } else directory_symbol = directory_symbol -> owner -> DirectoryCast(); } else { char *entry_name = new char[length + 1]; for (int i = 0; i < length; i++) entry_name[i] = directory_name[i]; entry_name[length] = U_NULL; DirectoryEntry *entry = directory_symbol -> FindCaseInsensitiveEntry(entry_name, length); if (entry) { for (int k = 0; k < length; k++) directory_name[k] = entry -> name[k]; } delete [] entry_name; NameSymbol *name_symbol = FindOrInsertName(directory_name, length); DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertAndReadDirectorySymbol(name_symbol); directory_symbol = subdirectory_symbol; } } for (end++; end < name_length && name[end] == U_SLASH; end++) // skip all extra '/' ; } delete [] directory_name; delete [] name; delete [] input_name; return directory_symbol; } #endif void Control::ProcessNewInputFiles(SymbolSet &file_set, ArgumentExpander &arguments, int first_index) { for (int i = 0; i < bad_input_filenames.Length(); i++) delete [] bad_input_filenames[i]; bad_input_filenames.Reset(); for (int k = 0; k < unreadable_input_filenames.Length(); k++) delete [] unreadable_input_filenames[k]; unreadable_input_filenames.Reset(); // // Process all file names specified in command line // for (int j = first_index; j < arguments.argc; j++) { char *file_name = arguments.argv[j]; int file_name_length = strlen(file_name); wchar_t *name = new wchar_t[file_name_length + 1]; for (int i = 0; i < file_name_length; i++) name[i] = (file_name[i] != U_BACKSLASH ? file_name[i] : (wchar_t) U_SLASH); // change backslash to forward slash. name[file_name_length] = U_NULL; // // File must be of the form xxx.java where xxx is a // character string consisting of at least one character. // if (file_name_length < FileSymbol::java_suffix_length || (! FileSymbol::IsJavaSuffix(&file_name[file_name_length - FileSymbol::java_suffix_length]))) bad_input_filenames.Next() = name; else { FileSymbol *file_symbol = FindOrInsertJavaInputFile(name, file_name_length - FileSymbol::java_suffix_length); if (! file_symbol) unreadable_input_filenames.Next() = name; else { delete [] name; file_set.AddElement(file_symbol); } } } return; } FileSymbol *Control::FindOrInsertJavaInputFile(DirectorySymbol *directory_symbol, NameSymbol *file_name_symbol) { FileSymbol *file_symbol = NULL; int length = file_name_symbol -> Utf8NameLength() + FileSymbol::java_suffix_length; char *java_name = new char[length + 1]; // +1 for \0 strcpy(java_name, file_name_symbol -> Utf8Name()); strcat(java_name, FileSymbol::java_suffix); DirectoryEntry *entry = directory_symbol -> FindEntry(java_name, length); if (entry) { file_symbol = directory_symbol -> FindFileSymbol(file_name_symbol); if (! file_symbol) { file_symbol = directory_symbol -> InsertFileSymbol(file_name_symbol); file_symbol -> directory_symbol = directory_symbol; file_symbol -> SetJava(); } file_symbol -> mtime = entry -> Mtime(); } delete [] java_name; return file_symbol; } FileSymbol *Control::FindOrInsertJavaInputFile(wchar_t *name, int name_length) { FileSymbol *file_symbol = NULL; // // The name has been preprocessed so that if it contains any // slashes it is a forward slash. In the loop below we look // for the occurrence of the first slash (if any) that separates // the file name from its directory name. // DirectorySymbol *directory_symbol; NameSymbol *file_name_symbol; #ifdef UNIX_FILE_SYSTEM int len; for (len = name_length - 1; len >= 0 && name[len] != U_SLASH; len--) ; directory_symbol = ProcessSubdirectories(name, len); file_name_symbol = FindOrInsertName(&name[len + 1], name_length - (len + 1)); #elif defined(WIN32_FILE_SYSTEM) int len; for (len = name_length - 1; len >= 0 && name[len] != U_SLASH && name[len] != U_COLON; len--) ; directory_symbol = ProcessSubdirectories(name, (name[len] == U_COLON ? len + 1 : len)); file_name_symbol = FindOrInsertName(&name[len + 1], name_length - (len + 1)); #endif for (int i = 1; i < classpath.Length(); i++) { if (i == dot_classpath_index) // the current directory (.). { file_symbol = FindOrInsertJavaInputFile(directory_symbol, file_name_symbol); if (file_symbol) break; } else if (classpath[i] -> IsZip()) { DirectorySymbol *directory_symbol = FindSubdirectory(classpath[i], name, len); if (directory_symbol) { file_symbol = directory_symbol -> FindFileSymbol(file_name_symbol); if (file_symbol && file_symbol -> IsJava()) break; else file_symbol = NULL; } } } // // If the file was found, return it; otherwise, in case the (.) directory was not specified in the // classpath, search for the file in it... // return (file_symbol ? file_symbol : FindOrInsertJavaInputFile(directory_symbol, file_name_symbol)); } PackageSymbol *Control::FindOrInsertPackage(LexStream *lex_stream, AstExpression *name) { PackageSymbol *package; AstFieldAccess* field_access = name -> FieldAccessCast(); if (field_access) { package = FindOrInsertPackage(lex_stream, field_access -> base); NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(field_access -> identifier_token); PackageSymbol *subpackage = package -> FindPackageSymbol(name_symbol); if (! subpackage) subpackage = package -> InsertPackageSymbol(name_symbol); package = subpackage; } else { AstSimpleName *simple_name = (AstSimpleName *) name; NameSymbol *name_symbol = (NameSymbol *) lex_stream -> NameSymbol(simple_name -> identifier_token); package = external_table.FindPackageSymbol(name_symbol); if (! package) package = external_table.InsertPackageSymbol(name_symbol, NULL); } FindPathsToDirectory(package); return package; } void Control::ProcessFile(FileSymbol *file_symbol) { ProcessHeaders(file_symbol); // // As long as there are new bodies, ... // for (int i = 0; i < needs_body_work.Length(); i++) { assert(semantic.Length() == 0); ProcessBodies(needs_body_work[i]); } needs_body_work.Reset(); return; } void Control::ProcessHeaders(FileSymbol *file_symbol) { input_java_file_set.AddElement(file_symbol); bool initial_invocation = (semantic.Length() == 0); if (option.verbose) { cout << "[read "; Unicode::Cout(file_symbol -> FileName()); cout << "]\n"; } if (! file_symbol -> lex_stream) scanner -> Scan(file_symbol); else file_symbol -> lex_stream -> Reset(); if (file_symbol -> lex_stream) // do we have a successful scan! { if (! file_symbol -> compilation_unit) file_symbol -> compilation_unit = parser -> HeaderParse(file_symbol -> lex_stream); // // If we have a compilation unit, analyze it, process its types. // if (file_symbol -> compilation_unit) { assert(! file_symbol -> semantic); if (! file_symbol -> package) ProcessPackageDeclaration(file_symbol, file_symbol -> compilation_unit -> package_declaration_opt); file_symbol -> semantic = new Semantic(*this, file_symbol); semantic.Next() = file_symbol -> semantic; file_symbol -> semantic -> ProcessTypeNames(); } } if (initial_invocation) ProcessMembers(); return; } void Control::ProcessMembers() { Tuple<TypeSymbol *> partially_ordered_types(1024); SymbolSet needs_member_work(101); TypeCycleChecker cycle_checker(partially_ordered_types); TopologicalSort topological_sorter(needs_member_work, partially_ordered_types); int start = 0; while (start < semantic.Length()) { needs_member_work.SetEmpty(); do { // // Check whether or not there are cycles in this new batch of types. // Create a partial order of the types (cycles are ordered arbitrarily) // and place the result in partially_ordered_types. // cycle_checker.PartialOrder(semantic, start); start = semantic.Length(); // next starting point // // Process the extends and implements clauses. // for (int j = 0; j < partially_ordered_types.Length(); j++) { TypeSymbol *type = partially_ordered_types[j]; needs_member_work.AddElement(type); type -> ProcessTypeHeaders(); type -> semantic_environment -> sem -> types_to_be_processed.AddElement(type); } } while (start < semantic.Length()); // // Patially order the collection of types in needs_member_work and place the result // in partially_ordered_types. This reordering is based on the complete "supertype" // information computed in ProcessTypeHeaders. // topological_sorter.Sort(); for (int i = 0; i < partially_ordered_types.Length(); i++) { TypeSymbol *type = partially_ordered_types[i]; needs_body_work.Next() = type; type -> ProcessMembers(); } } semantic.Reset(); return; } void Control::ProcessBodies(TypeSymbol *type) { Semantic *sem = type -> semantic_environment -> sem; if (type -> declaration && (! sem -> compilation_unit -> BadCompilationUnitCast())) { AstInterfaceDeclaration *interface_declaration = type -> declaration -> InterfaceDeclarationCast(); AstClassDeclaration *class_declaration = type -> declaration -> ClassDeclarationCast(); #ifdef WIN32_FILE_SYSTEM if (! type -> file_symbol -> IsZip()) { int length = type -> Utf8NameLength() + FileSymbol::class_suffix_length; char *classfile_name = new char[length + 1]; // +1 for "\0" strcpy(classfile_name, type -> Utf8Name()); strcat(classfile_name, FileSymbol::class_suffix); DirectorySymbol *directory = type -> file_symbol -> OutputDirectory(); DirectoryEntry *entry = directory -> FindCaseInsensitiveEntry(classfile_name, length); // // If no entry exists for the classfile name, add it as we are about to create // such a file. If an entry is found and it is not identical (in a case-sensitive test) // to the name of the type, issue an appropriate message. // if (! entry) directory -> InsertEntry(classfile_name, length); else if (strcmp(classfile_name, entry -> name) != 0) { wchar_t *entry_name = new wchar_t[entry -> length + 1]; for (int i = 0; i < length; i++) entry_name[i] = entry -> name[i]; entry_name[entry -> length] = U_NULL; LexStream::TokenIndex identifier_token = (interface_declaration ? interface_declaration -> identifier_token : class_declaration -> identifier_token); sem -> ReportSemError(SemanticError::FILE_FILE_CONFLICT, identifier_token, identifier_token, type -> Name(), entry_name, directory -> Name()); delete [] entry_name; } delete [] classfile_name; } #endif if (interface_declaration) { if (! parser -> InitializerParse(sem -> lex_stream, interface_declaration)) sem -> compilation_unit -> kind = Ast::BAD_COMPILATION; // recall that syntax errors were detected else { type -> CompleteSymbolTable(); if (! parser -> BodyParse(sem -> lex_stream, interface_declaration)) sem -> compilation_unit -> kind = Ast::BAD_COMPILATION; // mark that syntax errors were detected else type -> ProcessExecutableBodies(); } } else { if (! parser -> InitializerParse(sem -> lex_stream, class_declaration -> class_body)) sem -> compilation_unit -> kind = Ast::BAD_COMPILATION; // recall that syntax errors were detected else { type -> CompleteSymbolTable(); if (! parser -> BodyParse(sem -> lex_stream, class_declaration -> class_body)) sem -> compilation_unit -> kind = Ast::BAD_COMPILATION; // mark that syntax errors were detected. else type -> ProcessExecutableBodies(); } } if ((sem -> NumErrors() == 0) && (! sem -> compilation_unit -> BadCompilationUnitCast())) { Tuple<TypeSymbol *> *types = new Tuple<TypeSymbol *>(1024); types -> Next() = type; for (int j = 0; j < type -> num_anonymous_types(); j++) { types -> Next() = type -> AnonymousType(j); } if (type -> local) { for (TypeSymbol *local_type = (TypeSymbol *) type -> local -> FirstElement(); local_type; local_type = (TypeSymbol *) type -> local -> NextElement()) { types -> Next() = local_type; } } if (type -> non_local) { for (TypeSymbol *non_local_type = (TypeSymbol *) type -> non_local -> FirstElement(); non_local_type; non_local_type = (TypeSymbol *) type -> non_local -> NextElement()) { types -> Next() = non_local_type; } } for (int k = 0; k < types -> Length(); k++) { TypeSymbol *type = (*types)[k]; if (option.bytecode) { ByteCode *code = new ByteCode(type); if (type -> ACC_INTERFACE()) code -> CompileInterface(type); else code -> CompileClass(type); delete code; } delete type -> semantic_environment; type -> semantic_environment = NULL; if (type -> ACC_INTERFACE()) { AstInterfaceDeclaration *interface_declaration = (AstInterfaceDeclaration *) type -> declaration; interface_declaration -> semantic_environment = NULL; } else { AstClassDeclaration *class_declaration = type -> declaration -> ClassDeclarationCast(); if (class_declaration) class_declaration -> semantic_environment = NULL; } } delete types; } } sem -> types_to_be_processed.RemoveElement(type); if (sem -> types_to_be_processed.Size() == 0) // all types belonging to this compilation unit have been processed. CleanUp(sem -> source_file_symbol); return; } // // Introduce the main package and the current package. // This procedure is invoked directly only while doing // an incremental compilation. // void Control::ProcessPackageDeclaration(FileSymbol *file_symbol, AstPackageDeclaration *package_declaration) { file_symbol -> package = (package_declaration ? FindOrInsertPackage(file_symbol -> lex_stream, package_declaration -> name) : unnamed_package); for (int i = 0; i < file_symbol -> lex_stream -> NumTypes(); i++) { LexStream::TokenIndex identifier_token = file_symbol -> lex_stream -> Next(file_symbol -> lex_stream -> Type(i)); if (file_symbol -> lex_stream -> Kind(identifier_token) == TK_Identifier) { NameSymbol *name_symbol = (NameSymbol *) file_symbol -> lex_stream -> NameSymbol(identifier_token); if (! file_symbol -> package -> FindTypeSymbol(name_symbol)) { TypeSymbol *type = file_symbol -> package -> InsertOuterTypeSymbol(name_symbol); type -> file_symbol = file_symbol; type -> outermost_type = type; type -> SetOwner(file_symbol -> package); type -> SetSignature(*this); type -> MarkSourcePending(); // // If this type is contained in the unnamed package add it to the set // unnamed_package_types if a type of similar name was not already there. // if ((! package_declaration) && (unnamed_package_types.Image(type -> Identity()) == NULL)) unnamed_package_types.AddElement(type); } } } return; } void Control::CleanUp(FileSymbol *file_symbol) { Semantic *sem = file_symbol -> semantic; if (sem) { #ifdef TEST if (option.debug_dump_lex) { sem -> lex_stream -> Reset(); // rewind input and ... sem -> lex_stream -> Dump(); // dump it! } if (option.debug_dump_ast) sem -> compilation_unit -> Print(*sem -> lex_stream); #endif sem -> PrintMessages(); if (sem -> return_code > 0) return_code = 1; file_symbol -> CleanUp(); } return; }