1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-26 04:00:43 +03:00

Refactored the "current virtual machine" via inbuild

This commit is contained in:
Graham Nelson 2020-02-20 22:20:04 +00:00
parent 44fffd7bb8
commit 325d541880
36 changed files with 387 additions and 532 deletions

View file

@ -16,13 +16,14 @@ typedef struct target_vm {
struct text_stream *VM_image; /* filename of image for icon denoting VM */
int max_locals; /* upper limit on local variables per stack frame */
struct text_stream *default_browser_interpreter; /* e.g., "Parchment" */
struct text_stream *iFiction_format_name; /* e.g., "zcode": see the Treaty of Babel */
int supports_floating_point;
MEMORY_MANAGEMENT
} target_vm;
target_vm *TargetVMs::new(text_stream *code, text_stream *nick, semantic_version_number V,
text_stream *image, text_stream *interpreter, text_stream *blorbed, text_stream *arch,
int debug, int max_locals) {
int debug, int max_locals, text_stream *iFiction) {
target_vm *VM = CREATE(target_vm);
VM->family_name = Str::duplicate(code);
VM->version = V;
@ -37,6 +38,7 @@ target_vm *TargetVMs::new(text_stream *code, text_stream *nick, semantic_version
VM->with_debugging_enabled = debug;
VM->supports_floating_point = TRUE;
if (Architectures::is_16_bit(VM->architecture)) VM->supports_floating_point = FALSE;
VM->iFiction_format_name = Str::duplicate(iFiction);
return VM;
}
@ -53,20 +55,20 @@ void TargetVMs::write(OUTPUT_STREAM, target_vm *VM) {
void TargetVMs::create(void) {
/* hat tip: Joel Berez and Marc Blank, 1979, and later hands */
TargetVMs::new(I"Z-Machine", I"z5", VersionNumbers::from_text(I"5"),
I"vm_z5.png", I"Parchment", I"zblorb", I"16", FALSE, 15);
I"vm_z5.png", I"Parchment", I"zblorb", I"16", FALSE, 15, I"zcode");
TargetVMs::new(I"Z-Machine", I"z5", VersionNumbers::from_text(I"5"),
I"vm_z5.png", I"Parchment", I"zblorb", I"16d", TRUE, 15);
I"vm_z5.png", I"Parchment", I"zblorb", I"16d", TRUE, 15, I"zcode");
TargetVMs::new(I"Z-Machine", I"z8", VersionNumbers::from_text(I"8"),
I"vm_z8.png", I"Parchment", I"zblorb", I"16", FALSE, 15);
I"vm_z8.png", I"Parchment", I"zblorb", I"16", FALSE, 15, I"zcode");
TargetVMs::new(I"Z-Machine", I"z8", VersionNumbers::from_text(I"8"),
I"vm_z8.png", I"Parchment", I"zblorb", I"16d", TRUE, 15);
I"vm_z8.png", I"Parchment", I"zblorb", I"16d", TRUE, 15, I"zcode");
/* hat tip: Andrew Plotkin, 2000 */
TargetVMs::new(I"Glulx", I"ulx", VersionNumbers::from_text(I"3.1.2"),
I"vm_glulx.png", I"Quixe", I"gblorb", I"32", FALSE, 256);
I"vm_glulx.png", I"Quixe", I"gblorb", I"32", FALSE, 256, I"glulx");
TargetVMs::new(I"Glulx", I"ulx", VersionNumbers::from_text(I"3.1.2"),
I"vm_glulx.png", I"Quixe", I"gblorb", I"32d", TRUE, 256);
I"vm_glulx.png", I"Quixe", I"gblorb", I"32d", TRUE, 256, I"glulx");
}
target_vm *TargetVMs::find(text_stream *ext, int debug) {
@ -108,3 +110,54 @@ int TargetVMs::supports_floating_point(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->supports_floating_point;
}
@ The limits are different on each platform. On Z, the maximum is fixed
at 15, but Glulx allows it to be set with an I6 memory setting.
=
int TargetVMs::allow_this_many_locals(target_vm *VM, int N) {
if (VM == NULL) internal_error("no VM");
if ((VM->max_locals >= 0) && (VM->max_locals < N)) return FALSE;
return TRUE;
}
int TargetVMs::allow_MAX_LOCAL_VARIABLES(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
if (VM->max_locals > 15) return TRUE;
return FALSE;
}
@ When releasing a blorbed story file, the file extension depends on the
story file wrapped inside. (This is a dubious idea, in the opinion of
the author of Inform -- should not blorb be one unified wrapper? -- but
interpreter writers disagree.)
=
text_stream *TargetVMs::get_unblorbed_extension(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->VM_unblorbed_extension;
}
text_stream *TargetVMs::get_blorbed_extension(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->VM_blorbed_extension;
}
text_stream *TargetVMs::get_iFiction_format(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->iFiction_format_name;
}
inter_architecture *TargetVMs::get_architecture(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->architecture;
}
@ Different VMs have different in-browser interpreters, which means that
Inblorb needs to be given different release instructions for them. If the
user doesn't specify any particular interpreter, he gets:
=
text_stream *TargetVMs::get_default_interpreter(target_vm *VM) {
if (VM == NULL) internal_error("no VM");
return VM->default_browser_interpreter;
}

View file

@ -43,6 +43,9 @@ to add and process command line switches handled by inbuild:
@e KIT_CLSW
@e PROJECT_CLSW
@e SOURCE_CLSW
@e DEBUG_CLSW
@e FORMAT_CLSW
@e RELEASE_CLSW
=
void Inbuild::declare_options(void) {
@ -60,16 +63,28 @@ void Inbuild::declare_options(void) {
L"load the Inform kit called X");
CommandLine::declare_switch(PROJECT_CLSW, L"project", 2,
L"work within the Inform project X");
CommandLine::declare_boolean_switch(DEBUG_CLSW, L"debug", 1,
L"compile with debugging features even on a Release");
CommandLine::declare_boolean_switch(RELEASE_CLSW, L"release", 1,
L"compile a version suitable for a Release build");
CommandLine::declare_textual_switch(FORMAT_CLSW, L"format", 1,
L"compile I6 code suitable for the virtual machine X");
CommandLine::declare_switch(SOURCE_CLSW, L"source", 2,
L"use file X as the Inform source text");
CommandLine::end_group();
}
pathname *shared_transient_resources = NULL;
int this_is_a_debug_compile = FALSE; /* Destined to be compiled with debug features */
int this_is_a_release_compile = FALSE; /* Omit sections of source text marked not for release */
text_stream *story_filename_extension = NULL; /* What story file we will eventually have */
void Inbuild::option(int id, int val, text_stream *arg, void *state) {
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
switch (id) {
case DEBUG_CLSW: this_is_a_debug_compile = val; break;
case FORMAT_CLSW: story_filename_extension = Str::duplicate(arg); break;
case RELEASE_CLSW: this_is_a_release_compile = val; break;
case NEST_CLSW: Inbuild::add_nest(Pathnames::from_text(arg), GENERIC_NEST_TAG); break;
case INTERNAL_CLSW: Inbuild::add_nest(Pathnames::from_text(arg), INTERNAL_NEST_TAG); break;
case EXTERNAL_CLSW: Inbuild::add_nest(Pathnames::from_text(arg), EXTERNAL_NEST_TAG); break;
@ -87,7 +102,7 @@ void Inbuild::option(int id, int val, text_stream *arg, void *state) {
}
@ Once the tool has finished with the command line, it should call this
function.Inbuild rapidly runs through the next few phases as it does so.
function. Inbuild rapidly runs through the next few phases as it does so.
From the "nested" phase, the final list of nests in the search path for
finding kits, extensions and so on exists; from the "projected" phase,
the main Inform project exists. As we shall see, Inbuild deals with only
@ -95,6 +110,7 @@ one Inform project at a time, though it may be handling many kits and
extensions, and so on, which are needed by that project.
=
target_vm *current_target_VM = NULL;
inbuild_copy *Inbuild::optioneering_complete(inbuild_copy *C) {
RUN_ONLY_IN_PHASE(CONFIGURATION_INBUILD_PHASE)
inbuild_phase = PRETINKERING_INBUILD_PHASE;
@ -105,9 +121,21 @@ inbuild_copy *Inbuild::optioneering_complete(inbuild_copy *C) {
Inbuild::pass_kit_requests();
inbuild_phase = PROJECTED_INBUILD_PHASE;
inform_project *project = Inbuild::project();
if (Str::len(story_filename_extension) == 0) story_filename_extension = I"ulx";
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile))
current_target_VM = TargetVMs::find(story_filename_extension, TRUE);
else
current_target_VM = TargetVMs::find(story_filename_extension, FALSE);
return (project)?(project->as_copy):NULL;
}
target_vm *Inbuild::current_vm(void) {
return current_target_VM;
}
int Inbuild::currently_releasing(void) {
return this_is_a_release_compile;
}
@ Inbuild is now in the "projected" phase, then. The idea is that this
is a short interval during which the tool can if it wishes add further
kit dependencies to the main project. Once that sort of thing is done,

View file

@ -193,5 +193,5 @@ void Graphs::build_r(int gb, build_vertex *V, build_methodology *meth) {
if (since < 0) { needs_building = TRUE; break; }
}
}
if (needs_building) BuildSteps::execute(V->script, meth);
if (needs_building) BuildSteps::execute(V, V->script, meth);
}

View file

@ -22,12 +22,14 @@ typedef struct build_step {
int what_to_do;
struct pathname *arg_p1;
struct text_stream *arg_t1;
struct target_vm *arg_vm;
MEMORY_MANAGEMENT
} build_step;
@
@e ASSIMILATE_BSTEP from 1
@e COMPILE_I7_TO_INTER_BSTEP
=
build_script *BuildSteps::new_script(void) {
@ -41,6 +43,7 @@ build_step *BuildSteps::new_step(int to_do, pathname *P, text_stream *T) {
S->what_to_do = to_do;
S->arg_p1 = P;
S->arg_t1 = T;
S->arg_vm = NULL;
return S;
}
@ -100,7 +103,7 @@ build_methodology *BuildSteps::methodology(pathname *tools_path, int dev) {
return meth;
}
void BuildSteps::execute(build_script *BS, build_methodology *meth) {
void BuildSteps::execute(build_vertex *V, build_script *BS, build_methodology *meth) {
build_step *S;
LOOP_OVER_LINKED_LIST(S, build_step, BS->steps) {
TEMPORARY_TEXT(command);

View file

@ -365,7 +365,7 @@ just a blank image used for horizontal spacing to keep margins straight.
if (key_vms) {
#ifdef CORE_MODULE
HTML_TAG("br");
VirtualMachines::write_key(OUT);
Extensions::Census::write_key(OUT);
#endif
}
HTML_CLOSE("p");
@ -578,7 +578,7 @@ the first and last word and just look at what is in between:
@<Append icons which signify the VM requirements of the extension@> =
WRITE("&nbsp;%S", C->parsed_from);
#ifdef CORE_MODULE
VirtualMachines::write_icons(OUT, C);
Extensions::Census::write_icons(OUT, C);
#endif
@<Print column 2 of the census line@> =
@ -682,3 +682,49 @@ int Extensions::Census::compare_ecd_by_length(const void *ecd1, const void *ecd2
extension_census_datum *e2 = *((extension_census_datum **) ecd2);
return Works::compare_by_length(e1->found_as->copy->edition->work, e2->found_as->copy->edition->work);
}
@h Icons for virtual machines.
And everything else is cosmetic: printing, or showing icons to signify,
the current VM or some set of permitted VMs. The following plots the
icon associated with a given minor VM, and explicates what the icons mean:
=
void Extensions::Census::plot_icon(OUTPUT_STREAM, target_vm *VM) {
if (Str::len(VM->VM_image) > 0) {
HTML_TAG_WITH("img", "border=0 src=inform:/doc_images/%S", VM->VM_image);
WRITE("&nbsp;");
}
}
void Extensions::Census::write_key(OUTPUT_STREAM) {
WRITE("Extensions compatible with specific story file formats only: ");
int i = 0;
target_vm *VM;
LOOP_OVER(VM, target_vm) {
if (VM->with_debugging_enabled) continue; /* avoids listing twice */
if (i++ > 0) WRITE(", ");
Extensions::Census::plot_icon(OUT, VM);
TargetVMs::write(OUT, VM);
}
}
@h Displaying VM restrictions.
Given a word range, we describe the result as concisely as we can with a
row of icons (but do not bother for the common case where some extension
has no restriction on its use).
=
void Extensions::Census::write_icons(OUTPUT_STREAM, compatibility_specification *C) {
int something = FALSE, everything = TRUE;
target_vm *VM;
LOOP_OVER(VM, target_vm)
if (Compatibility::with(C, VM))
something = TRUE;
else
everything = FALSE;
if (something == FALSE) WRITE("none");
if (everything == FALSE)
LOOP_OVER(VM, target_vm)
if (Compatibility::with(C, VM))
Extensions::Census::plot_icon(OUT, VM);
}

View file

@ -251,6 +251,9 @@ void Projects::construct_graph(inform_project *project) {
if (project == NULL) return;
Projects::finalise_kit_dependencies(project);
build_vertex *V = project->as_copy->vertex;
build_step *BS = BuildSteps::new_step(
COMPILE_I7_TO_INTER_BSTEP, NULL, NULL);
BuildSteps::add_step(V->script, BS);
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, project->kits_to_include) {
Graphs::need_this_to_build(V, K->as_copy->vertex);

View file

@ -61,7 +61,6 @@ We need to itemise the structures we'll want to allocate:
@e equation_node_MT
@e placement_affecting_array_MT
@e activity_crossref_array_MT
@e VM_usage_note_MT
@e invocation_options_array_MT
@e inv_token_problem_token_MT
@e application_array_MT
@ -160,7 +159,6 @@ ALLOCATE_INDIVIDUALLY(text_substitution)
ALLOCATE_INDIVIDUALLY(to_phrase_request)
ALLOCATE_INDIVIDUALLY(use_as_event)
ALLOCATE_INDIVIDUALLY(use_option)
ALLOCATE_INDIVIDUALLY(VM_usage_note)
ALLOCATE_INDIVIDUALLY(runtime_kind_structure)
ALLOCATE_INDIVIDUALLY(adjective_iname_holder)
ALLOCATE_INDIVIDUALLY(label_namespace)

View file

@ -4,30 +4,13 @@ As with all C programs, Inform begins execution in a |main| routine,
reading command-line arguments to modify its behaviour.
@h Flags.
These flags are set by command-line parameters. |for_release| will be set
when Inform is used in a run started by clicking on the Release button in the
application. |rng_seed_at_start_of_play| is not used by the application,
but the |intest| program makes use of this feature to make repeated
tests of the Z-machine story file produce identical sequences of random
numbers: without this, we would have difficulty comparing a transcript of
text produced by the story file on one compilation from another.
|story_filename_extension| is also set as a result of information passed
from the application via the command line to Inform. In order for Inform to
write good releasing instructions, it needs to know the story file format
(".z5", ".z8", etc.) of the finally produced story file. But since Inform 7
compiles only to Inter and thence to Inform 6 code, and does not run I6
itself, it has no way of telling what the application intends to do on this.
So the application is required to give Inform advance notice of this via a
command-line option.
These are not all of the options, because Inform shares a whole range of
options with inbuild: see that module for more.
=
int this_is_a_debug_compile = FALSE; /* Destined to be compiled with debug features */
int this_is_a_release_compile = FALSE; /* Omit sections of source text marked not for release */
int existing_story_file = FALSE; /* Ignore source text to blorb existing story file? */
int rng_seed_at_start_of_play = 0; /* The seed value, or 0 if not seeded */
int census_mode = FALSE; /* Inform running only to update extension documentation */
text_stream *story_filename_extension = NULL; /* What story file we will eventually have */
int show_progress_indicator = TRUE; /* Produce percentage of progress messages */
int scoring_option_set = NOT_APPLICABLE; /* Whether in this case a score is kept at run time */
int disable_import = FALSE;
@ -100,7 +83,6 @@ int CoreMain::main(int argc, char *argv[]) {
@<Banner and startup@> =
Errors::set_internal_handler(&Problems::Issue::internal_error_fn);
story_filename_extension = I"ulx";
inter_processing_pipeline = Str::new();
inter_processing_file = I"compile";
@ -114,12 +96,9 @@ list is not exhaustive.
@e CASE_CLSW
@e CENSUS_CLSW
@e CLOCK_CLSW
@e DEBUG_CLSW
@e FORMAT_CLSW
@e CRASHALL_CLSW
@e NOINDEX_CLSW
@e NOPROGRESS_CLSW
@e RELEASE_CLSW
@e REQUIRE_PROBLEM_CLSW
@e RNG_CLSW
@e SIGILS_CLSW
@ -132,22 +111,16 @@ list is not exhaustive.
L"inform7: a compiler from source text to Inform 6 code\n\n"
L"Usage: inform7 [OPTIONS] [SOURCETEXT]\n");
CommandLine::declare_textual_switch(FORMAT_CLSW, L"format", 1,
L"compile I6 code suitable for the virtual machine X");
CommandLine::declare_boolean_switch(CENSUS_CLSW, L"census", 1,
L"perform an extensions census (rather than compile)");
CommandLine::declare_boolean_switch(CLOCK_CLSW, L"clock", 1,
L"time how long inform7 takes to run");
CommandLine::declare_boolean_switch(DEBUG_CLSW, L"debug", 1,
L"compile with debugging features even on a Release");
CommandLine::declare_boolean_switch(CRASHALL_CLSW, L"crash-all", 1,
L"crash intentionally on Problem messages (for debugger backtraces)");
CommandLine::declare_boolean_switch(NOINDEX_CLSW, L"noindex", 1,
L"don't produce an Index");
CommandLine::declare_boolean_switch(NOPROGRESS_CLSW, L"noprogress", 1,
L"don't display progress percentages");
CommandLine::declare_boolean_switch(RELEASE_CLSW, L"release", 1,
L"compile a version suitable for a Release build");
CommandLine::declare_boolean_switch(RNG_CLSW, L"rng", 1,
L"fix the random number generator of the story file (for testing)");
CommandLine::declare_boolean_switch(SIGILS_CLSW, L"sigils", 1,
@ -169,10 +142,6 @@ list is not exhaustive.
@<With that done, configure all other settings@> =
Inbuild::optioneering_complete(NULL);
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile))
VirtualMachines::set_identifier(story_filename_extension, TRUE);
else
VirtualMachines::set_identifier(story_filename_extension, FALSE );
if (Locations::set_defaults(census_mode) == FALSE)
Problems::Fatal::issue("Unable to create folders in local file system");
Log::set_debug_log_filename(filename_of_debugging_log);
@ -313,7 +282,7 @@ with "Output.i6t".
ProgressBar::update_progress_bar(4, 0);
if (problem_count == 0) CoreMain::go_to_log_phase(I"Generating inter");
COMPILATION_STEP(UseOptions::compile_icl_commands, I"UseOptions::compile_icl_commands")
COMPILATION_STEP(VirtualMachines::compile_build_number, I"VirtualMachines::compile_build_number")
COMPILATION_STEP(FundamentalConstants::emit_build_number, I"FundamentalConstants::emit_build_number")
COMPILATION_STEP(PL::Bibliographic::compile_constants, I"PL::Bibliographic::compile_constants")
COMPILATION_STEP(Extensions::Files::ShowExtensionVersions_routine, I"Extensions::Files::ShowExtensionVersions_routine")
COMPILATION_STEP(Kinds::Constructors::compile_I6_constants, I"Kinds::Constructors::compile_I6_constants")
@ -361,7 +330,7 @@ with "Output.i6t".
COMPILATION_STEP_IF(parsing_plugin, PL::Parsing::Tokens::Values::compile_type_gprs, I"PL::Parsing::Tokens::Values::compile_type_gprs")
COMPILATION_STEP(NewVerbs::ConjugateVerb, I"NewVerbs::ConjugateVerb")
COMPILATION_STEP(Adjectives::Meanings::agreements, I"Adjectives::Meanings::agreements")
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile)) {
if (TargetVMs::debug_enabled(Inbuild::current_vm())) {
COMPILATION_STEP_IF(parsing_plugin, PL::Parsing::TestScripts::write_text, I"PL::Parsing::TestScripts::write_text")
COMPILATION_STEP_IF(parsing_plugin, PL::Parsing::TestScripts::TestScriptSub_routine, I"PL::Parsing::TestScripts::TestScriptSub_routine")
COMPILATION_STEP_IF(parsing_plugin, PL::Parsing::TestScripts::InternalTestCases_routine, I"PL::Parsing::TestScripts::InternalTestCases_routine")
@ -411,17 +380,7 @@ with "Output.i6t".
LOG("Front end elapsed time: %dcs\n", ((int) (front_end - start)) / (CLOCKS_PER_SEC/100));
CoreMain::go_to_log_phase(I"Converting inter to Inform 6");
if (existing_story_file == FALSE) {
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile)) {
if (VirtualMachines::is_16_bit())
CodeGen::Architecture::set(I"16d");
else
CodeGen::Architecture::set(I"32d");
} else {
if (VirtualMachines::is_16_bit())
CodeGen::Architecture::set(I"16");
else
CodeGen::Architecture::set(I"32");
}
CodeGen::Architecture::set(Architectures::to_codename(TargetVMs::get_architecture(Inbuild::current_vm())));
@<Ensure inter pipeline variables dictionary@>;
Str::copy(Dictionaries::create_text(pipeline_vars, I"*in"), I"*memory");
Str::copy(Dictionaries::create_text(pipeline_vars, I"*out"), Filenames::get_leafname(filename_of_compiled_i6_code));
@ -517,10 +476,8 @@ void CoreMain::switch(int id, int val, text_stream *arg, void *state) {
case CENSUS_CLSW: census_mode = val; break;
case CLOCK_CLSW: report_clock_time = val; break;
case CRASHALL_CLSW: debugger_mode = val; crash_on_all_errors = val; break;
case DEBUG_CLSW: this_is_a_debug_compile = val; break;
case NOINDEX_CLSW: do_not_generate_index = val; break;
case NOPROGRESS_CLSW: show_progress_indicator = val?FALSE:TRUE; break;
case RELEASE_CLSW: this_is_a_release_compile = val; break;
case RNG_CLSW:
if (val) rng_seed_at_start_of_play = -16339;
else rng_seed_at_start_of_play = 0;
@ -528,7 +485,6 @@ void CoreMain::switch(int id, int val, text_stream *arg, void *state) {
case SIGILS_CLSW: echo_problem_message_sigils = val; break;
/* Other settings */
case FORMAT_CLSW: story_filename_extension = Str::duplicate(arg); break;
case CASE_CLSW: HTMLFiles::set_source_link_case(arg); break;
case REQUIRE_PROBLEM_CLSW: Problems::Fatal::require(arg); break;
case PIPELINE_CLSW: inter_processing_pipeline = Str::duplicate(arg); break;

View file

@ -280,7 +280,7 @@ will produce if this is a Release run.
filename_of_compiled_i6_code = Filenames::in_folder(build_folder, I"auto.inf");
TEMPORARY_TEXT(story_file_leafname);
WRITE_TO(story_file_leafname, "output.%S", story_filename_extension);
WRITE_TO(story_file_leafname, "output.%S", TargetVMs::get_unblorbed_extension(Inbuild::current_vm()));
filename_of_story_file = Filenames::in_folder(build_folder, story_file_leafname);
DISCARD_TEXT(story_file_leafname);
@ -359,7 +359,7 @@ have by default, if so.
@<Existing story file@> =
TEMPORARY_TEXT(leaf);
WRITE_TO(leaf, "story.%S", story_filename_extension);
WRITE_TO(leaf, "story.%S", TargetVMs::get_unblorbed_extension(Inbuild::current_vm()));
filename_of_existing_story_file =
Filenames::in_folder(Inbuild::materials(), leaf);
DISCARD_TEXT(leaf);

View file

@ -805,7 +805,7 @@ has essentially no memory constraints compared with the Z-machine.
if (total_heap_allocation < UseOptions::get_dynamic_memory_allocation())
total_heap_allocation = UseOptions::get_dynamic_memory_allocation();
while (max_heap < total_heap_allocation) max_heap = max_heap*2;
if (VirtualMachines::is_16_bit())
if (TargetVMs::is_16_bit(Inbuild::current_vm()))
Kinds::RunTime::compile_nnci(Hierarchy::find(MEMORY_HEAP_SIZE_HL), max_heap);
else
Kinds::RunTime::compile_nnci(Hierarchy::find(MEMORY_HEAP_SIZE_HL), 4*max_heap);
@ -874,12 +874,12 @@ void Kinds::RunTime::emit_heap_allocation(heap_allocation ha) {
void Kinds::RunTime::emit_block_value_header(kind *K, int individual, int size) {
if (individual == FALSE) Emit::array_numeric_entry(0);
int n = 0, c = 1, w = 4;
if (VirtualMachines::is_16_bit()) w = 2;
if (TargetVMs::is_16_bit(Inbuild::current_vm())) w = 2;
while (c < (size + 3)*w) { n++; c = c*2; }
int flags = BLK_FLAG_RESIDENT + BLK_FLAG_WORD;
if (Kinds::get_construct(K) == CON_list_of) flags += BLK_FLAG_TRUNCMULT;
if (Kinds::get_construct(K) == CON_relation) flags += BLK_FLAG_MULTIPLE;
if (VirtualMachines::is_16_bit())
if (TargetVMs::is_16_bit(Inbuild::current_vm()))
Emit::array_numeric_entry((inter_t) (0x100*n + flags));
else
Emit::array_numeric_entry((inter_t) (0x1000000*n + 0x10000*flags));
@ -1815,7 +1815,7 @@ void Kinds::RunTime::I7_Kind_Name_routine(void) {
@ =
int VM_non_support_problem_issued = FALSE;
void Kinds::RunTime::notify_of_use(kind *K) {
if (VirtualMachines::supports(K) == FALSE) {
if (Kinds::RunTime::target_VM_supports(K) == FALSE) {
if (VM_non_support_problem_issued == FALSE) {
VM_non_support_problem_issued = TRUE;
Problems::Issue::handmade_problem(_p_(PM_KindRequiresGlulx));
@ -1830,3 +1830,11 @@ void Kinds::RunTime::notify_of_use(kind *K) {
}
}
}
int Kinds::RunTime::target_VM_supports(kind *K) {
target_vm *VM = Inbuild::current_vm();
if (VM == NULL) internal_error("target VM not set yet");
if ((Kinds::FloatingPoint::uses_floating_point(K)) &&
(TargetVMs::supports_floating_point(VM) == FALSE)) return FALSE;
return TRUE;
}

View file

@ -35,8 +35,6 @@ void Properties::Emit::emit_subject(inference_subject *subj) {
if (K2) nw += World::Compile::get_rough_memory_usage(K2);
}
nw += 16;
wording KW = Kinds::Behaviour::get_name(K, FALSE);
VirtualMachines::note_usage("object", KW, NULL, nw, 0, TRUE);
LOGIF(OBJECT_COMPILATION, "Rough size estimate: %d words\n", nw);
}
LOGIF(OBJECT_COMPILATION, "Compilation of $j complete\n", subj);

View file

@ -288,7 +288,7 @@ a request for a new text substitution to be compiled later...
BEGIN_COMPILATION_MODE;
COMPILATION_MODE_EXIT(IMPLY_NEWLINES_IN_SAY_CMODE);
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile)) {
if (TargetVMs::debug_enabled(Inbuild::current_vm())) {
Produce::inv_primitive(Emit::tree(), IFDEBUG_BIP);
Produce::down(Emit::tree());
Produce::code(Emit::tree());

View file

@ -10,7 +10,6 @@ void Tables::Support::compile(void) {
@<Compile the blanks bitmap table@>;
@<Compile the Table of Tables@>;
Tables::Columns::compile_run_time_support();
@<Note the usage of run-time memory for tables@>;
}
@<Compile the data structures for entry storage@> =
@ -253,14 +252,6 @@ against the rules. (The Template file "Tables.i6t" defines it.)
Emit::array_numeric_entry(0);
Emit::array_end(save);
@<Note the usage of run-time memory for tables@> =
table *t;
LOOP_OVER(t, table)
if (t->amendment_of == FALSE)
VirtualMachines::note_usage("table",
ParseTree::get_text(t->headline_fragment),
NULL, t->approximate_array_space_needed, 0, FALSE);
@ The following allows tables to be said: it's a routine which switches on
table values and prints the (title-cased) name of the one which matches.

View file

@ -1270,7 +1270,7 @@ int Equations::enode_typecheck(equation *eqn, equation_node *tok) {
tok->gK_before =
Kinds::FloatingPoint::new_gk(
ParseTree::get_kind_of_value(tok->leaf_constant));
if ((tok->enode_promotion) && (VirtualMachines::supports(K_real_number)))
if ((tok->enode_promotion) && (Kinds::RunTime::target_VM_supports(K_real_number)))
tok->gK_before =
Kinds::FloatingPoint::to_real(tok->gK_before);
break;

View file

@ -1354,7 +1354,7 @@ because neither syntax will compile when I6 is compiling for the other VM.
Produce::ref_iname(Emit::tree(), K_number, Hierarchy::find(UNICODE_TEMP_HL));
Specifications::Compiler::emit_to_kind(to_say, K);
Produce::up(Emit::tree());
if (VirtualMachines::is_16_bit()) {
if (TargetVMs::is_16_bit(Inbuild::current_vm())) {
Produce::inv_assembly(Emit::tree(), I"@print_unicode");
Produce::down(Emit::tree());
Produce::val_iname(Emit::tree(), K_number, Hierarchy::find(UNICODE_TEMP_HL));

View file

@ -0,0 +1,133 @@
[FundamentalConstants::] Fundamental Constants.
Inter constants for, say, extremal number values, which depend on the
target we are compiling to, and are generally low-level in nature.
@ Fundamental constants are emitted about our choice of virtual machine.
The old I6 library used to confuse Z-vs-G with 16-vs-32-bit, but we try
to separate these distinctions here, even though at present the Z-machine
is our only 16-bit target and Glulx our only 32-bit one. The |WORDSIZE|
constant is the word size in bytes, so is the multiplier between |->| and
|-->| offsets in I6 pointer syntax.
(1) |NULL| is used, as in C, to represent a null value or pointer. In C,
this is conventionally 0, but here it is the maximum unsigned value which
can be stored, pointing to the topmost byte in the directly addressable
memory map; this means it is also $-1$ when regarded as a signed
twos-complement integer, but we write it as an unsigned hexadecimal
address for clarity's sake.
(2) |WORD_HIGHBIT| is the most significant bit in the VM's data word.
(3) |IMPROBABLE_VALUE| is one which is unlikely but still possible
to be a genuine I7 value. The efficiency of some algorithms depends on
how well chosen this is: they would ran badly if we chose 1, for instance.
(4) |MAX_POSITIVE_NUMBER| is the largest representable positive (signed)
integer, in twos-complement form.
(5) |REPARSE_CODE| is a magic value used in the I6 library's parser to
signal that some code which ought to have been parsing a command has in
fact rewritten it, so that the whole command must be re-parsed afresh.
(Returning this value is like throwing an exception in a language like
Java, though we don't implement it that way.) A comment in the 6/11 library
reads: "The parser rather gunkily adds addresses to |REPARSE_CODE| for
some purposes. And expects the result to be greater than |REPARSE_CODE|
(signed comparison). So Glulx Inform is limited to a single gigabyte of
storage, for the moment." Guilty as charged, but the gigabyte story file
is a remote prospect for now. Anyway, it's this comparison issue which
means we need a different value for each possible word size.
=
inter_name *FundamentalConstants::emit_one(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant(iname, val);
return iname;
}
inter_name *FundamentalConstants::emit_signed(int id, int val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant_signed(iname, val);
return iname;
}
inter_name *FundamentalConstants::emit_hex(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant_hex(iname, val);
return iname;
}
inter_name *FundamentalConstants::emit_unchecked_hex(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_unchecked_constant_hex(iname, val);
return iname;
}
void FundamentalConstants::emit(target_vm *VM) {
if (VM == NULL) internal_error("target VM not set yet");
if (TargetVMs::debug_enabled(VM))
FundamentalConstants::emit_one(DEBUG_HL, 1);
if (Str::eq(VM->family_name, I"Z-Machine")) {
FundamentalConstants::emit_one(TARGET_ZCODE_HL, 1);
FundamentalConstants::emit_one(DICT_WORD_SIZE_HL, 6);
} else if (Str::eq(VM->family_name, I"Glulx")) {
FundamentalConstants::emit_one(TARGET_GLULX_HL, 1);
FundamentalConstants::emit_one(DICT_WORD_SIZE_HL, 9);
FundamentalConstants::emit_one(INDIV_PROP_START_HL, 0);
}
if (TargetVMs::is_16_bit(VM)) {
FundamentalConstants::emit_one(WORDSIZE_HL, 2);
FundamentalConstants::emit_unchecked_hex(NULL_HL, 0xffff);
FundamentalConstants::emit_hex(WORD_HIGHBIT_HL, 0x8000);
FundamentalConstants::emit_hex(WORD_NEXTTOHIGHBIT_HL, 0x4000);
FundamentalConstants::emit_hex(IMPROBABLE_VALUE_HL, 0x7fe3);
FundamentalConstants::emit_hex(REPARSE_CODE_HL, 10000);
FundamentalConstants::emit_one(MAX_POSITIVE_NUMBER_HL, 32767);
FundamentalConstants::emit_signed(MIN_NEGATIVE_NUMBER_HL, -32768);
} else {
FundamentalConstants::emit_one(WORDSIZE_HL, 4);
FundamentalConstants::emit_unchecked_hex(NULL_HL, 0xffffffff);
FundamentalConstants::emit_hex(WORD_HIGHBIT_HL, 0x80000000);
FundamentalConstants::emit_hex(WORD_NEXTTOHIGHBIT_HL, 0x40000000);
FundamentalConstants::emit_hex(IMPROBABLE_VALUE_HL, 0xdeadce11);
FundamentalConstants::emit_hex(REPARSE_CODE_HL, 0x40000000);
FundamentalConstants::emit_one(MAX_POSITIVE_NUMBER_HL, 2147483647);
FundamentalConstants::emit_signed(MIN_NEGATIVE_NUMBER_HL, -2147483648);
}
}
@ This version-numbering constant is not really to do with the VM (it is
Inform's own version number), but it belongs nowhere else either, so:
=
void FundamentalConstants::emit_build_number(void) {
TEMPORARY_TEXT(build);
WRITE_TO(build, "%B", TRUE);
inter_name *iname = Hierarchy::find(NI_BUILD_COUNT_HL);
Emit::named_string_constant(iname, build);
Hierarchy::make_available(Emit::tree(), iname);
DISCARD_TEXT(build);
}
@ This also doesn't really belong here, but...
=
int FundamentalConstants::veto_number(int X) {
if (((X > 32767) || (X < -32768)) &&
(TargetVMs::is_16_bit(Inbuild::current_vm()))) {
Problems::Issue::sentence_problem(_p_(PM_LiteralOverflow),
"you use a number which is too large",
"at least with the Settings for this project as they currently "
"are. (Change to Glulx to be allowed to use much larger numbers.)");
return TRUE;
}
return FALSE;
}

View file

@ -280,6 +280,53 @@ void Plugins::Manage::start_plugins(void) {
}
}
@h Describing the current VM.
=
void Plugins::Manage::index_innards(OUTPUT_STREAM, target_vm *VM) {
Plugins::Manage::index_VM(OUT, VM);
UseOptions::index(OUT);
HTML_OPEN("p");
Index::extra_link(OUT, 3);
WRITE("See some technicalities for Inform maintainers only");
HTML_CLOSE("p");
Index::extra_div_open(OUT, 3, 2, "e0e0e0");
Plugins::Manage::show_configuration(OUT);
@<Add some paste buttons for the debugging log@>;
Index::extra_div_close(OUT, "e0e0e0");
}
@ The index provides some hidden paste icons for these:
@<Add some paste buttons for the debugging log@> =
HTML_OPEN("p");
WRITE("Debugging log:");
HTML_CLOSE("p");
HTML_OPEN("p");
for (int i=0; i<NO_DEFINED_DA_VALUES; i++) {
debugging_aspect *da = &(the_debugging_aspects[i]);
if (Str::len(da->unhyphenated_name) > 0) {
TEMPORARY_TEXT(is);
WRITE_TO(is, "Include %S in the debugging log.", da->unhyphenated_name);
HTML::Javascript::paste_stream(OUT, is);
WRITE("&nbsp;%S", is);
DISCARD_TEXT(is);
HTML_TAG("br");
}
}
HTML_CLOSE("p");
@ =
void Plugins::Manage::index_VM(OUTPUT_STREAM, target_vm *VM) {
if (VM == NULL) internal_error("target VM not set yet");
Index::anchor(OUT, I"STORYFILE");
HTML_OPEN("p"); WRITE("Story file format: ");
Extensions::Census::plot_icon(OUT, VM);
TargetVMs::write(OUT, VM);
HTML_CLOSE("p");
}
@ =
void Plugins::Manage::show_configuration(OUTPUT_STREAM) {
HTML_OPEN("p");
Index::anchor(OUT, I"CONFIG");

View file

@ -70,7 +70,7 @@ void Routines::end(packaging_state save) {
int needed = LocalVariables::count(currently_compiling_in_frame);
if (kernel_name) needed++;
if (VirtualMachines::allow_this_many_locals(needed) == FALSE)
if (TargetVMs::allow_this_many_locals(Inbuild::current_vm(), needed) == FALSE)
@<Issue a problem for too many locals@>;
LocalVariables::declare(currently_compiling_in_frame, FALSE);

View file

@ -428,7 +428,7 @@ void UseOptions::compile_icl_commands(void) {
i6_memory_setting *ms;
LOOP_OVER(ms, i6_memory_setting) {
if ((Str::eq_wide_string(ms->ICL_identifier, L"MAX_LOCAL_VARIABLES")) &&
(VirtualMachines::allow_MAX_LOCAL_VARIABLES() == FALSE))
(TargetVMs::allow_MAX_LOCAL_VARIABLES(Inbuild::current_vm()) == FALSE))
continue;
TEMPORARY_TEXT(prag);
WRITE_TO(prag, "$%S=%d", ms->ICL_identifier, ms->number);

View file

@ -1,410 +0,0 @@
[VirtualMachines::] Virtual Machines.
I7 supports a variety of virtual machines as targets. Most source
text should be independent of the target VM, but sometimes numbering is
needed, and this is where any VM dependencies are decided.
@h Definitions.
@
@d MAX_USAGE_COLUMN_WIDTH 200
=
typedef struct VM_usage_note {
struct wording structure_name; /* name of the structure using this array space... */
struct text_stream *usage_explained; /* ...or an explanation instead */
char *usage_category; /* e.g., "relation" */
int bytes_used; /* number of bytes (not words) given over to this */
int each_flag; /* is this a count of how many bytes per usage of something? */
MEMORY_MANAGEMENT
} VM_usage_note;
@ At present, we infer the target virtual machine by looking at the file
extension requested at the command line.
=
target_vm *current_target_VM = NULL;
void VirtualMachines::set_identifier(text_stream *text, int debugging) {
current_target_VM = TargetVMs::find(text, debugging);
}
int VirtualMachines::compatible_with(compatibility_specification *C) {
return Compatibility::with(C, current_target_VM);
}
<current-virtual-machine> internal {
if (<virtual-machine>(W)) {
*X = VirtualMachines::compatible_with((compatibility_specification *) <<rp>>);
return TRUE;
} else {
*X = FALSE;
return FALSE;
}
}
@ To help Inform detect overflows, it needs to know whether integers in the
target VM are 16 or 32 bits wide:
=
int VirtualMachines::is_16_bit(void) {
return TargetVMs::is_16_bit(current_target_VM);
}
@ Using which:
=
int VirtualMachines::veto_number(int X) {
if (((X > 32767) || (X < -32768)) && (TargetVMs::is_16_bit(current_target_VM))) {
Problems::Issue::sentence_problem(_p_(PM_LiteralOverflow),
"you use a number which is too large",
"at least with the Settings for this project as they currently "
"are. (Change to Glulx to be allowed to use much larger numbers.)");
return TRUE;
}
return FALSE;
}
@ Fundamental constants are emitted about our choice of virtual machine.
The old I6 library used to confuse Z-vs-G with 16-vs-32-bit, but we try
to separate these distinctions here, even though at present the Z-machine
is our only 16-bit target and Glulx our only 32-bit one. The |WORDSIZE|
constant is the word size in bytes, so is the multiplier between |->| and
|-->| offsets in I6 pointer syntax.
(1) |NULL| is used, as in C, to represent a null value or pointer. In C,
this is conventionally 0, but here it is the maximum unsigned value which
can be stored, pointing to the topmost byte in the directly addressable
memory map; this means it is also $-1$ when regarded as a signed
twos-complement integer, but we write it as an unsigned hexadecimal
address for clarity's sake.
(2) |WORD_HIGHBIT| is the most significant bit in the VM's data word.
(3) |IMPROBABLE_VALUE| is one which is unlikely but still possible
to be a genuine I7 value. The efficiency of some algorithms depends on
how well chosen this is: they would ran badly if we chose 1, for instance.
(4) |MAX_POSITIVE_NUMBER| is the largest representable positive (signed)
integer, in twos-complement form.
(5) |REPARSE_CODE| is a magic value used in the I6 library's parser to
signal that some code which ought to have been parsing a command has in
fact rewritten it, so that the whole command must be re-parsed afresh.
(Returning this value is like throwing an exception in a language like
Java, though we don't implement it that way.) A comment in the 6/11 library
reads: "The parser rather gunkily adds addresses to |REPARSE_CODE| for
some purposes. And expects the result to be greater than |REPARSE_CODE|
(signed comparison). So Glulx Inform is limited to a single gigabyte of
storage, for the moment." Guilty as charged, but the gigabyte story file
is a remote prospect for now: even megabyte story files are off the
horizon. Anyway, it's this comparison issue which means we need a different
value for each possible word size.
=
inter_name *VirtualMachines::emit_fundamental_constant(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant(iname, val);
return iname;
}
inter_name *VirtualMachines::emit_signed_fundamental_constant(int id, int val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant_signed(iname, val);
return iname;
}
inter_name *VirtualMachines::emit_hex_fundamental_constant(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_numeric_constant_hex(iname, val);
return iname;
}
inter_name *VirtualMachines::emit_unchecked_hex_fundamental_constant(int id, inter_t val) {
inter_name *iname = Hierarchy::find(id);
Hierarchy::make_available(Emit::tree(), iname);
Emit::named_unchecked_constant_hex(iname, val);
return iname;
}
void VirtualMachines::emit_fundamental_constants(void) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile))
VirtualMachines::emit_fundamental_constant(DEBUG_HL, 1);
if (Str::eq(current_target_VM->family_name, I"Z-Machine")) {
VirtualMachines::emit_fundamental_constant(TARGET_ZCODE_HL, 1);
VirtualMachines::emit_fundamental_constant(DICT_WORD_SIZE_HL, 6);
} else if (Str::eq(current_target_VM->family_name, I"Glulx")) {
VirtualMachines::emit_fundamental_constant(TARGET_GLULX_HL, 1);
VirtualMachines::emit_fundamental_constant(DICT_WORD_SIZE_HL, 9);
VirtualMachines::emit_fundamental_constant(INDIV_PROP_START_HL, 0);
}
if (TargetVMs::is_16_bit(current_target_VM)) {
VirtualMachines::emit_fundamental_constant(WORDSIZE_HL, 2);
VirtualMachines::emit_unchecked_hex_fundamental_constant(NULL_HL, 0xffff);
VirtualMachines::emit_hex_fundamental_constant(WORD_HIGHBIT_HL, 0x8000);
VirtualMachines::emit_hex_fundamental_constant(WORD_NEXTTOHIGHBIT_HL, 0x4000);
VirtualMachines::emit_hex_fundamental_constant(IMPROBABLE_VALUE_HL, 0x7fe3);
VirtualMachines::emit_hex_fundamental_constant(REPARSE_CODE_HL, 10000);
VirtualMachines::emit_fundamental_constant(MAX_POSITIVE_NUMBER_HL, 32767);
VirtualMachines::emit_signed_fundamental_constant(MIN_NEGATIVE_NUMBER_HL, -32768);
} else {
VirtualMachines::emit_fundamental_constant(WORDSIZE_HL, 4);
VirtualMachines::emit_unchecked_hex_fundamental_constant(NULL_HL, 0xffffffff);
VirtualMachines::emit_hex_fundamental_constant(WORD_HIGHBIT_HL, 0x80000000);
VirtualMachines::emit_hex_fundamental_constant(WORD_NEXTTOHIGHBIT_HL, 0x40000000);
VirtualMachines::emit_hex_fundamental_constant(IMPROBABLE_VALUE_HL, 0xdeadce11);
VirtualMachines::emit_hex_fundamental_constant(REPARSE_CODE_HL, 0x40000000);
VirtualMachines::emit_fundamental_constant(MAX_POSITIVE_NUMBER_HL, 2147483647);
VirtualMachines::emit_signed_fundamental_constant(MIN_NEGATIVE_NUMBER_HL, -2147483648);
}
}
@ This version-numbering constant is not really to do with the VM (it is
Inform's own version number), but it belongs nowhere else either, so:
=
void VirtualMachines::compile_build_number(void) {
TEMPORARY_TEXT(build);
WRITE_TO(build, "%B", TRUE);
inter_name *iname = Hierarchy::find(NI_BUILD_COUNT_HL);
Emit::named_string_constant(iname, build);
Hierarchy::make_available(Emit::tree(), iname);
DISCARD_TEXT(build);
}
@ The limits are different on each platform. On Z, the maximum is fixed
at 15, but Glulx allows it to be set with an I6 memory setting.
=
int VirtualMachines::allow_this_many_locals(int N) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
if ((current_target_VM->max_locals >= 0) &&
(current_target_VM->max_locals < N)) return FALSE;
return TRUE;
}
int VirtualMachines::allow_MAX_LOCAL_VARIABLES(void) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
if (current_target_VM->max_locals > 15) return TRUE;
return FALSE;
}
@ Real numbers are also a concern:
=
int VirtualMachines::supports(kind *K) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
if ((Kinds::FloatingPoint::uses_floating_point(K)) &&
(TargetVMs::supports_floating_point(current_target_VM) == FALSE)) return FALSE;
return TRUE;
}
@ When releasing a blorbed story file, the file extension depends on the
story file wrapped inside. (This is a dubious idea, in the opinion of
the author of Inform -- should not blorb be one unified wrapper? -- but
interpreter writers disagree.)
=
text_stream *VirtualMachines::get_blorbed_extension(void) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
return current_target_VM->VM_blorbed_extension;
}
@ Different VMs have different in-browser interpreters, which means that
Inblorb needs to be given different release instructions for them. If the
user doesn't specify any particular interpreter, he gets:
=
text_stream *VirtualMachines::get_default_interpreter(void) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
return current_target_VM->default_browser_interpreter;
}
@h Icons for virtual machines.
And everything else is cosmetic: printing, or showing icons to signify,
the current VM or some set of permitted VMs. The following plots the
icon associated with a given minor VM, and explicates what the icons mean:
=
void VirtualMachines::plot_icon(OUTPUT_STREAM, target_vm *VM) {
if (Str::len(VM->VM_image) > 0) {
HTML_TAG_WITH("img", "border=0 src=inform:/doc_images/%S", VM->VM_image);
WRITE("&nbsp;");
}
}
void VirtualMachines::write_key(OUTPUT_STREAM) {
WRITE("Extensions compatible with specific story file formats only: ");
int i = 0;
target_vm *VM;
LOOP_OVER(VM, target_vm) {
if (VM->with_debugging_enabled) continue; /* avoids listing twice */
if (i++ > 0) WRITE(", ");
VirtualMachines::plot_icon(OUT, VM);
TargetVMs::write(OUT, VM);
}
}
@h Describing the current VM.
=
void VirtualMachines::index_innards(OUTPUT_STREAM) {
VirtualMachines::write_current(OUT);
UseOptions::index(OUT);
HTML_OPEN("p");
Index::extra_link(OUT, 3);
WRITE("See some technicalities for Inform maintainers only");
HTML_CLOSE("p");
Index::extra_div_open(OUT, 3, 2, "e0e0e0");
Plugins::Manage::show_configuration(OUT);
@<Add some paste buttons for the debugging log@>;
Index::extra_div_close(OUT, "e0e0e0");
}
@ The index provides some hidden paste icons for these:
@<Add some paste buttons for the debugging log@> =
HTML_OPEN("p");
WRITE("Debugging log:");
HTML_CLOSE("p");
HTML_OPEN("p");
for (int i=0; i<NO_DEFINED_DA_VALUES; i++) {
debugging_aspect *da = &(the_debugging_aspects[i]);
if (Str::len(da->unhyphenated_name) > 0) {
TEMPORARY_TEXT(is);
WRITE_TO(is, "Include %S in the debugging log.", da->unhyphenated_name);
HTML::Javascript::paste_stream(OUT, is);
WRITE("&nbsp;%S", is);
DISCARD_TEXT(is);
HTML_TAG("br");
}
}
HTML_CLOSE("p");
@ =
void VirtualMachines::write_current(OUTPUT_STREAM) {
if (current_target_VM == NULL) internal_error("target VM not set yet");
Index::anchor(OUT, I"STORYFILE");
HTML_OPEN("p"); WRITE("Story file format: ");
VirtualMachines::plot_icon(OUT, current_target_VM);
TargetVMs::write(OUT, current_target_VM);
HTML_CLOSE("p");
if (TargetVMs::is_16_bit(current_target_VM)) {
HTML_OPEN("p"); Index::extra_link(OUT, 1);
WRITE("See estimates of memory usage");
HTML_CLOSE("p");
Index::extra_div_open(OUT, 1, 1, "e0e0e0");
VirtualMachines::index_memory_usage(OUT);
Index::extra_div_close(OUT, "e0e0e0");
}
}
@h Displaying VM restrictions.
Given a word range, we describe the result as concisely as we can with a
row of icons (but do not bother for the common case where some extension
has no restriction on its use).
=
void VirtualMachines::write_icons(OUTPUT_STREAM, compatibility_specification *C) {
int something = FALSE, everything = TRUE;
target_vm *VM;
LOOP_OVER(VM, target_vm)
if (Compatibility::with(C, VM))
something = TRUE;
else
everything = FALSE;
if (something == FALSE) WRITE("none");
if (everything == FALSE)
LOOP_OVER(VM, target_vm)
if (Compatibility::with(C, VM))
VirtualMachines::plot_icon(OUT, VM);
}
@ The following table in the index (on the Contents page) may be useful to a
few diehard Z-machine hackers, determined to squeeze the maximum out of the
tiny array space available.
@d NOTEWORTHY_USAGE_THRESHOLD 50 /* don't mention arrays smaller than this, in bytes */
=
void VirtualMachines::note_usage(char *cat, wording W, text_stream *name, int words, int bytes, int each) {
int b = bytes + words*((VirtualMachines::is_16_bit())?2:4);
if ((each == FALSE) && (b < NOTEWORTHY_USAGE_THRESHOLD)) return;
if (b == 0) return;
VM_usage_note *VMun = CREATE(VM_usage_note);
VMun->structure_name = W;
VMun->usage_explained = Str::duplicate(name);
VMun->usage_category = cat;
VMun->bytes_used = b;
VMun->each_flag = each;
}
@ The explanatory note here probably ought to use the words "approximately",
"incomplete" and so forth. It's really no better than a guide.
=
void VirtualMachines::index_memory_usage(OUTPUT_STREAM) {
int nr = NUMBER_CREATED(VM_usage_note);
VM_usage_note **sorted = Memory::I7_calloc(nr, sizeof(VM_usage_note *), INDEX_SORTING_MREASON);
HTML_OPEN("p"); WRITE("In a Z-machine story file, array memory can be very limited. "
"Switching to the Glulx setting removes all difficulty, but some authors "
"like to squeeze the very most out of the Z-machine instead. This "
"list shows about how much array space is used by some larger items "
"the source text has chosen to create.");
HTML_CLOSE("p");
@<Sort the array usages@>;
@<Tabulate the array usages@>;
Memory::I7_array_free(sorted, INDEX_SORTING_MREASON, nr, sizeof(VM_usage_note *));
}
@ The rows in the table mention pathetically small numbers of bytes, of course,
by any rational measure.
@<Tabulate the array usages@> =
HTML::begin_plain_html_table(OUT);
int i;
VM_usage_note *VMun;
for (i=0; i<nr; i++) {
VMun = sorted[i];
HTML::first_html_column(OUT, 0);
WRITE("%s", VMun->usage_category);
HTML::next_html_column(OUT, 0);
if (VMun->each_flag) WRITE("each ");
if (Str::len(VMun->usage_explained) > 0)
WRITE("%S", VMun->usage_explained);
else if (Wordings::first_wn(VMun->structure_name) >= 0)
WRITE("%W", VMun->structure_name);
if (Wordings::first_wn(VMun->structure_name) >= 0)
Index::link(OUT, Wordings::first_wn(VMun->structure_name));
HTML::next_html_column(OUT, 0);
WRITE("%d bytes", VMun->bytes_used);
HTML::end_html_row(OUT);
}
HTML::end_html_table(OUT);
@ As usual, we sort with the C library's |qsort|.
@<Sort the array usages@> =
int i = 0;
VM_usage_note *VMun;
LOOP_OVER(VMun, VM_usage_note) sorted[i++] = VMun;
qsort(sorted, (size_t) nr, sizeof(VM_usage_note *), VirtualMachines::compare_usage);
@ The following means the table is sorted in decreasing order of bytes used,
with ties resolved by listing the first-declared item first.
=
int VirtualMachines::compare_usage(const void *ent1, const void *ent2) {
const VM_usage_note *v1 = *((const VM_usage_note **) ent1);
const VM_usage_note *v2 = *((const VM_usage_note **) ent2);
if (v2->bytes_used != v1->bytes_used) return v2->bytes_used - v1->bytes_used;
return Wordings::first_wn(v1->structure_name) - Wordings::first_wn(v2->structure_name);
}

View file

@ -56,7 +56,7 @@ void Emit::begin(void) {
Emit::kind_inner(Inter::SymbolsTables::id_from_IRS_and_symbol(Packaging::at(Emit::tree()), string_interk), TEXT_IDT, 0, BASE_ICON, 0, NULL);
Packaging::exit(Emit::tree(), save);
VirtualMachines::emit_fundamental_constants();
FundamentalConstants::emit(Inbuild::current_vm());
NewVerbs::ConjugateVerbDefinitions();
Hierarchy::find(INFORMLIBRARY_HL);

View file

@ -258,7 +258,7 @@ equivalent to an exact value.
list_head = LiteralPatterns::lp_list_add_inner(list_head, new_lp);
if ((VirtualMachines::is_16_bit()) && (PM_ZMachineOverflow2_issued == FALSE))
if ((TargetVMs::is_16_bit(Inbuild::current_vm())) && (PM_ZMachineOverflow2_issued == FALSE))
for (lp = list_head; lp; lp = lp->next_for_this_kind)
if (Kinds::Scalings::quantum(lp->scaling) > 32767) {
Problems::Issue::sentence_problem(_p_(PM_ZMachineOverflow2),
@ -600,7 +600,7 @@ which is annoying. So we have a mechanism to suppress duplicates:
"page of the Index.)");
return NULL;
}
if ((overflow_16_bit_flag) && (VirtualMachines::is_16_bit())) {
if ((overflow_16_bit_flag) && (TargetVMs::is_16_bit(Inbuild::current_vm()))) {
ISSUING_LP_PROBLEM;
Problems::Issue::sentence_problem(_p_(PM_ZMachineOverflow),
"you use a literal specification to make a value which is too large",

View file

@ -871,7 +871,7 @@ void Relations::compile_defined_relation_constants(void) {
RELS_LOOKUP_ALL_X_iname = Relations::compile_defined_relation_constant(RELS_LOOKUP_ALL_X_HL, 0x0004);
RELS_LOOKUP_ALL_Y_iname = Relations::compile_defined_relation_constant(RELS_LOOKUP_ALL_Y_HL, 0x0002);
RELS_LIST_iname = Relations::compile_defined_relation_constant(RELS_LIST_HL, 0x0001);
if (VirtualMachines::is_16_bit()) {
if (TargetVMs::is_16_bit(Inbuild::current_vm())) {
REL_BLOCK_HEADER_symbol = Relations::compile_defined_relation_constant(REL_BLOCK_HEADER_HL, 0x100*5 + 13); /* $2^5 = 32$ bytes block */
} else {
REL_BLOCK_HEADER_symbol = Relations::compile_defined_relation_constant(REL_BLOCK_HEADER_HL, (0x100*6 + 13)*0x10000);
@ -1817,11 +1817,6 @@ void Relations::compile_vtov_storage(binary_predicate *bp) {
Emit::array_end(save);
TEMPORARY_TEXT(rname);
WRITE_TO(rname, "%A", &(bp->relation_name));
VirtualMachines::note_usage("relation",
ParseTree::get_text(bp->bp_created_at), rname, words_used, bytes_used, FALSE);
DISCARD_TEXT(rname);
Relations::free_index_storage();
}

View file

@ -339,6 +339,17 @@ allowed; they should probably be withdrawn.
DISCARD_TEXT(exft);
DISCARD_TEXT(exfa);
@ =
<current-virtual-machine> internal {
if (<virtual-machine>(W)) {
*X = Compatibility::with((compatibility_specification *) <<rp>>, Inbuild::current_vm());
return TRUE;
} else {
*X = FALSE;
return FALSE;
}
}
@h The heading tree.
The headings were constructed above as freestanding nodes (except that the
pseudo-heading already existed): here, we assemble them into a tree
@ -487,8 +498,9 @@ if the target virtual machine on this run of Inform is the Z-machine.)
=
int Sentences::Headings::include_material(heading *h) {
if ((h->for_release == TRUE) && (this_is_a_release_compile == FALSE)) return FALSE;
if ((h->for_release == FALSE) && (this_is_a_release_compile == TRUE)) return FALSE;
int releasing = Inbuild::currently_releasing();
if ((h->for_release == TRUE) && (releasing == FALSE)) return FALSE;
if ((h->for_release == FALSE) && (releasing == TRUE)) return FALSE;
if (h->omit_material) return FALSE;
return TRUE;
}

View file

@ -185,7 +185,7 @@ different template:
compatibility_specification *C = E->as_copy->edition->compatibility;
if (Str::len(C->parsed_from) > 0) {
WRITE("%S&nbsp;", C->parsed_from);
VirtualMachines::write_icons(OUT, C);
Extensions::Census::write_icons(OUT, C);
}
@<Write up the version number, if any, and location@> =

View file

@ -337,7 +337,7 @@ with our VM de jour.
@<Check that the extension's stipulation about the virtual machine can be met@> =
compatibility_specification *C = E->as_copy->edition->compatibility;
if (VirtualMachines::compatible_with(C) == FALSE)
if (Compatibility::with(C, Inbuild::current_vm()) == FALSE)
@<Issue a problem message saying that the VM does not meet requirements@>;
@ Here the problem is not that the extension is broken in some way: it's

View file

@ -258,7 +258,7 @@ Chapter 25: Compilation
Chapter 26: Compilation Utilities
"Mainly low-level utilities for compiling code."
Virtual Machines
Fundamental Constants
Inform 6 Inclusions
Use Options
List Together

View file

@ -197,7 +197,7 @@ void PL::Bibliographic::Release::handle_release_declaration_inner(parse_node *p)
break;
case EXISTING_STORY_FILE_PAYLOAD:
case NAMED_EXISTING_STORY_FILE_PAYLOAD:
if (VirtualMachines::is_16_bit() == FALSE) {
if (TargetVMs::is_16_bit(Inbuild::current_vm()) == FALSE) {
Problems::Issue::sentence_problem(_p_(BelievedImpossible), /* not usefully testable */
"existing story files can only be used with the Z-machine",
"not with the Glulx setting.");
@ -463,7 +463,7 @@ art and see that its dimensions conform to Treaty of Babel requirements.
}
@<Read header of existing story file if present@> =
if (this_is_a_release_compile == FALSE)
if (Inbuild::currently_releasing() == FALSE)
@<Issue a problem if this isn't a Release run@>;
FILE *STORYF = Filenames::fopen(filename_of_existing_story_file, "rb");
if (STORYF == NULL) {
@ -544,8 +544,7 @@ void PL::Bibliographic::Release::write_ifiction_record(OUTPUT_STREAM, zbyte *hea
}
@<Write the body of the iFiction record@> =
char *story_format = "zcode";
if (Str::eq_wide_string(story_filename_extension, L"ulx")) story_format = "glulx";
text_stream *story_format = TargetVMs::get_iFiction_format(Inbuild::current_vm());
@<Write the identification tag of the iFiction record@>;
@<Write the bibliographic tag of the iFiction record@>;
@ -555,9 +554,9 @@ void PL::Bibliographic::Release::write_ifiction_record(OUTPUT_STREAM, zbyte *hea
@<Write the cover tag of the iFiction record@>;
@<Write the releases tag of the iFiction record@>;
@<Write the colophon tag of the iFiction record@>;
WRITE("<%s>\n", story_format); INDENT;
WRITE("<%S>\n", story_format); INDENT;
@<Write the format-specific tag of the iFiction record@>;
OUTDENT; WRITE("</%s>\n", story_format);
OUTDENT; WRITE("</%S>\n", story_format);
@<Write the identification tag of the iFiction record@> =
WRITE("<identification>\n"); INDENT;
@ -571,7 +570,7 @@ void PL::Bibliographic::Release::write_ifiction_record(OUTPUT_STREAM, zbyte *hea
WRITE("-%04x", header[0x1c]*256 + header[0x1d]);
WRITE("</ifid>\n");
}
WRITE("<format>%s</format>\n", story_format);
WRITE("<format>%S</format>\n", story_format);
OUTDENT; WRITE("</identification>\n");
@<Write the bibliographic tag of the iFiction record@> =
@ -842,7 +841,7 @@ the Blorb-file's filename won't be too long for the file system.
PL::Bibliographic::Release::write_var_to_text(TEMP, story_title_VAR);
END_COMPILATION_MODE;
} else WRITE_TO(TEMP, "story");
WRITE_TO(TEMP, ".%S", VirtualMachines::get_blorbed_extension());
WRITE_TO(TEMP, ".%S", TargetVMs::get_blorbed_extension(Inbuild::current_vm()));
@<Write the body of the Blurb file@> =
@<Tell Inblorb where to write its report to@>;
@ -995,8 +994,8 @@ file online.
@<Tell Inblorb where to find the website templates@>;
if (Str::len(interpreter_template_leafname) == 0)
interpreter_template_leafname = VirtualMachines::get_default_interpreter();
text_stream *ext = VirtualMachines::get_blorbed_extension();
interpreter_template_leafname = TargetVMs::get_default_interpreter(Inbuild::current_vm());
text_stream *ext = TargetVMs::get_blorbed_extension(Inbuild::current_vm());
WRITE("placeholder [INTERPRETERSCRIPTS] = \" ");
auxiliary_file *af;
LOOP_OVER(af, auxiliary_file)

View file

@ -196,7 +196,7 @@ int PL::Scenes::parse_scene_end_name(scene *sc, wording EW, int create) {
if (create) {
int end = sc->no_ends++;
int max = 31;
if (VirtualMachines::is_16_bit()) max = 15;
if (TargetVMs::is_16_bit(Inbuild::current_vm())) max = 15;
if (end >= max) @<Issue a too-many-ends problem message@>
else {
sc->end_names[end] = EW;

View file

@ -276,7 +276,7 @@ turn by turn.
Produce::down(Emit::tree());
Produce::inv_primitive(Emit::tree(), AND_BIP);
Produce::down(Emit::tree());
if ((this_is_a_release_compile == FALSE) || (this_is_a_debug_compile)) {
if (TargetVMs::debug_enabled(Inbuild::current_vm())) {
Produce::inv_call_iname(Emit::tree(), Hierarchy::find(ALLOWINSHOWME_HL));
Produce::down(Emit::tree());
Produce::val_iname(Emit::tree(), K_value, Properties::iname(prn));

View file

@ -429,9 +429,6 @@ at run-time, so we can't know now how many we will need.
}
Emit::array_end(save);
Hierarchy::make_available(Emit::tree(), iname);
VirtualMachines::note_usage("map", EMPTY_WORDING, I"map of rooms and doors",
words_used, 0, FALSE);
@h Door connectivity.
We've seen how most of the map is represented, in the |exits| arrays. The

View file

@ -1203,8 +1203,6 @@ void PL::Actions::ActionData(void) {
Emit::named_numeric_constant(ad_iname, (inter_t) record_count);
Hierarchy::make_available(Emit::tree(), ad_iname);
VirtualMachines::note_usage("action", EMPTY_WORDING, NULL, 12, 0, TRUE);
inter_name *DB_Action_Details_iname = Hierarchy::find(DB_ACTION_DETAILS_HL);
save = Routines::begin(DB_Action_Details_iname);
inter_symbol *act_s = LocalVariables::add_named_call_as_symbol(I"act");

View file

@ -597,7 +597,7 @@ void Index::index_actual_element(OUTPUT_STREAM, text_stream *elt) {
return;
}
if (Str::eq_wide_string(elt, L"In")) {
VirtualMachines::index_innards(OUT);
Plugins::Manage::index_innards(OUT, Inbuild::current_vm());
return;
}

View file

@ -885,13 +885,13 @@ scaling this can appear to be much lower.
@<Index the maximum positive value for a quasinumerical kind@> =
if (Kinds::Compare::eq(R, K_number)) {
if (VirtualMachines::is_16_bit()) WRITE("32767");
if (TargetVMs::is_16_bit(Inbuild::current_vm())) WRITE("32767");
else WRITE("2147483647");
} else {
text_stream *p = Kinds::Behaviour::get_index_maximum_value(R);
if (Str::len(p) > 0) WRITE("%S", p);
else {
if (VirtualMachines::is_16_bit())
if (TargetVMs::is_16_bit(Inbuild::current_vm()))
LiteralPatterns::index_value(OUT,
LiteralPatterns::list_of_literal_forms(R), 32767);
else

View file

@ -433,7 +433,7 @@ void Kinds::Scalings::compile_scale_and_add(inter_symbol *var, inter_symbol *sgn
int scale_factor, int to_add, inter_symbol *var_to_add, inter_symbol *label) {
if (scale_factor > 1) {
long long int max = 2147483647LL;
if (VirtualMachines::is_16_bit()) max = 32767LL;
if (TargetVMs::is_16_bit(Inbuild::current_vm())) max = 32767LL;
Produce::inv_primitive(Emit::tree(), IFELSE_BIP);
Produce::down(Emit::tree());
Produce::inv_primitive(Emit::tree(), EQ_BIP);
@ -515,7 +515,7 @@ void Kinds::Scalings::compile_scale_and_add_oldschool(OUTPUT_STREAM, char *var,
if (scale_factor > 1) {
long long int max = 2147483647LL;
#ifdef CORE_MODULE
if (VirtualMachines::is_16_bit()) max = 32767LL;
if (TargetVMs::is_16_bit(Inbuild::current_vm())) max = 32767LL;
#endif
WRITE("if (sgn == 1) {\n"); INDENT;
WRITE("if ((%s > %d) || ((%s == %d) && (%S > %d)))\n",

View file

@ -114,7 +114,7 @@ project, with the user not realising the consequences.
@<In Inform 7 only, check that the number is representable in the VM@> =
#ifdef CORE_MODULE
if (VirtualMachines::veto_number(*X)) {
if (FundamentalConstants::veto_number(*X)) {
/* to prevent repetitions: */
Vocabulary::set_literal_number_value(Lexer::word(Wordings::first_wn(W)), 1);
return FALSE;