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:
parent
44fffd7bb8
commit
325d541880
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(" %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(" ");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
133
inform7/core-module/Chapter 26/Fundamental Constants.w
Normal file
133
inform7/core-module/Chapter 26/Fundamental Constants.w
Normal 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;
|
||||
}
|
|
@ -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(" %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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(" ");
|
||||
}
|
||||
}
|
||||
|
||||
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(" %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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ different template:
|
|||
compatibility_specification *C = E->as_copy->edition->compatibility;
|
||||
if (Str::len(C->parsed_from) > 0) {
|
||||
WRITE("%S ", C->parsed_from);
|
||||
VirtualMachines::write_icons(OUT, C);
|
||||
Extensions::Census::write_icons(OUT, C);
|
||||
}
|
||||
|
||||
@<Write up the version number, if any, and location@> =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue