public function loadConfiguration(): array
	{
		$this->detectConfiguration();

		$machine_type_table = [];

		// Find all machine types
		foreach ($this->file_list as $file) {
			// Load all JSON files
			if (preg_match('/^(.*)\.json(\.php)?$/i', $file, $m)) {
				$machine_type = $m[1];
				$machine_def = [];

				$include_queue = [$file];
				$included_files = [];

				$postprocess_list = []; /** @var IMachineDefinitionReader[] $postprocess_list*/
				$errors = [];

				// Load files using readers
				while (($include = array_shift($include_queue)) !== null) {
					// String is filename
					if (!is_array($include)) {
						$include_file = $include;
						$include_opts = [];
					} else {
						$include_file = $include['file'];
						$include_opts = $include;
					}

					// Check for cycles
					if (!empty($included_files[$include_file])) {
						throw new RuntimeException("Cyclic dependency found when including \"$include_file\".");
					} else {
						$included_files[$include_file] = true;
					}

					// Relative path is relative to base directory
					if ($include_file[0] != '/') {
						$include_file = $this->base_dir.$include_file;
					}

					// Load & parse content of the file
					$reader = null;
					$parsed_content = $this->parseFile($machine_type, $include_file, $include_opts, $reader);

					// Enqueue includes
					if (!empty($parsed_content['include'])) {
						foreach ($parsed_content['include'] as $new_include) {
							$include_queue[] =  $new_include;
						}
					}

					// Update machine definition
					$machine_def = array_replace_recursive($parsed_content, $machine_def);

					if ($reader) {
						$postprocess_list[spl_object_hash($reader)] = $reader;
					}
				}

				// Postprocess the definition by the readers (each reader gets called only once)
				foreach ($postprocess_list as $postprocessor) {
					$postprocessor->postprocessDefinition($machine_type, $machine_def, $errors);
				}

				// Store errors in machine definition so we can show them nicely
				if (!empty($errors)) {
					// TODO: Replace simple array with a ErrorListener which preserves context of the error.
					$machine_def['errors'] = $errors;
				}

				// Store the final machine definition
				$machine_type_table[$machine_type] = $machine_def;
			}
		}

		// Sort machines by name
		ksort($machine_type_table);

		return $machine_type_table;
	}