1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/docs/core-module/26-vm.html
2019-09-09 08:12:15 +01:00

1005 lines
106 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>25/cp</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '26/vm' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">core</a></li><li><a href="index.html#26">Chapter 26: Compilation Utilities</a></li><li><b>Virtual Machines</b></li></ul><p class="purpose">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.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP5">&#167;5. Table of supported VMs</a></li><li><a href="#SP14">&#167;14. Parsing VM restrictions</a></li><li><a href="#SP17">&#167;17. Icons for virtual machines</a></li><li><a href="#SP18">&#167;18. Describing the current VM</a></li><li><a href="#SP20">&#167;20. Displaying VM restrictions</a></li><li><a href="#SP24">&#167;24. Resource ID numbers</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>We use the term "major VM" to mean one of the families we deal with:
the Z-machine, for instance, is a major VM. A "minor VM" is a specific
revision of this, such as version 5 of the Z-machine. The following table
describes both major and minor VMs: records with version set to -1 are
major, and the rest minor.
</p>
<p class="inwebparagraph">It is assumed that major VM names are single words: happily Z-machine has
always traditionally been hyphenated. We also assume their names use only
the plainest ASCII characters.
</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>We store data on both major and minor VMs in the following simple structure.
</p>
<p class="inwebparagraph">The point of multiplying version numbers by 10,000 is to allow room for
sub-versions in future: Glulx in particular has version numbers like 3.4.2,
which we might want to represent as 30402. (At present we don't distinguish
versions of Glulx because Glulx's gestalt mechanism means that it's much
easier to construct story files which can cope nicely on different Glulx
interpreter versions than would be the case for the Z-machine.) Given that
the multiplier is larger than 1, it is impossible for -1 to be a valid
version number of any VM, so this is used as a "not a version number" value.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">VMULT</span><span class="plain"> 10000</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">VM_identifier</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">VM_code</span><span class="plain">; </span> <span class="comment">one of the values above</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">VM_version</span><span class="plain">; </span> <span class="comment">times the <code class="display"><span class="extract">VMULT</span></code>, or -1 to mean generic versionless VM</span>
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">VM_major_name</span><span class="plain">; </span> <span class="comment">or NULL if not a major VM name</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">VM_extension</span><span class="plain">; </span> <span class="comment">canonical filename extension</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">VM_blorbed_extension</span><span class="plain">; </span> <span class="comment">when blorbed up</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">VM_name</span><span class="plain">; </span> <span class="comment">text to use with author</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">VM_image</span><span class="plain">; </span> <span class="comment">filename of image for icon denoting VM</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">VM_is_32_bit</span><span class="plain">; </span> <span class="comment">true or false: false means 16-bit</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">max_locals</span><span class="plain">; </span> <span class="comment">upper limit on local variables per stack frame</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">VM_matches</span><span class="plain">; </span> <span class="comment">true or false: computed</span>
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">default_browser_interpreter</span><span class="plain">; </span> <span class="comment">e.g., "Parchment"</span>
<span class="plain">} </span><span class="reserved">VM_identifier</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure VM_identifier is private to this section.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>We keep track of how array space is used in the VM, since this is in very
short supply in the Z-machine. This is done purely so that we can index
helpfully on the Contents index page.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_USAGE_COLUMN_WIDTH</span><span class="plain"> 200</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">VM_usage_note</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">structure_name</span><span class="plain">; </span> <span class="comment">name of the structure using this array space...</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">usage_explained</span><span class="plain">; </span> <span class="comment">...or an explanation instead</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">usage_category</span><span class="plain">; </span> <span class="comment">e.g., "relation"</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">bytes_used</span><span class="plain">; </span> <span class="comment">number of bytes (not words) given over to this</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">each_flag</span><span class="plain">; </span> <span class="comment">is this a count of how many bytes per usage of something?</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">VM_usage_note</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure VM_usage_note is private to this section.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Table of supported VMs. </b>The following data determines what VMs we know about, and how they can
be inferred from the present information passed by the GUI to us at the
command line - viz., the eventual file extension. The application passes
this by including among the command-line switches a pair like so:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">-extension ulx</span>
</pre>
<p class="inwebparagraph">The second word must be one of the file extensions listed in the fourth
column of the table of VM data below: the comparison is made case
insensitively, and any initial full stop is skipped, so ".Z6" is
equivalent to "z6".
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">Z_VM</span><span class="plain"> 1 </span> <span class="comment">Joel Berez and Marc Blank, 1979, and later hands</span>
<span class="definitionkeyword">define</span> <span class="constant">GLULX_VM</span><span class="plain"> 2 </span> <span class="comment">Andrew Plotkin, 2000</span>
<span class="definitionkeyword">define</span> <span class="constant">DEFAULT_TARGET_VM</span><span class="plain"> 3 </span> <span class="comment">if no -extension is supplied, target row 3: Z-machine v8</span>
</pre>
<pre class="display">
<span class="reserved">VM_identifier</span><span class="plain"> </span><span class="identifier">table_of_VM_data</span><span class="plain">[] = {</span>
<span class="plain">{ </span><span class="constant">Z_VM</span><span class="plain">, -1, </span><span class="identifier">L</span><span class="string">"z-machine"</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="string">"zblorb"</span><span class="plain">, </span><span class="string">"Z-Machine"</span><span class="plain">, </span><span class="string">"vm_z.png"</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 15, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Parchment"</span><span class="plain"> },</span>
<span class="plain">{ </span><span class="constant">Z_VM</span><span class="plain">, 5*</span><span class="constant">VMULT</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="string">"z5"</span><span class="plain">, </span><span class="string">"zblorb"</span><span class="plain">, </span><span class="string">"Z-Machine version 5"</span><span class="plain">, </span><span class="string">"vm_z5.png"</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 15, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Parchment"</span><span class="plain"> },</span>
<span class="plain">{ </span><span class="constant">Z_VM</span><span class="plain">, 6*</span><span class="constant">VMULT</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="string">"z6"</span><span class="plain">, </span><span class="string">"zblorb"</span><span class="plain">, </span><span class="string">"Z-Machine version 6"</span><span class="plain">, </span><span class="string">"vm_z6.png"</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 15, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Parchment"</span><span class="plain"> },</span>
<span class="plain">{ </span><span class="constant">Z_VM</span><span class="plain">, 8*</span><span class="constant">VMULT</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="string">"z8"</span><span class="plain">, </span><span class="string">"zblorb"</span><span class="plain">, </span><span class="string">"Z-Machine version 8"</span><span class="plain">, </span><span class="string">"vm_z8.png"</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 15, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Parchment"</span><span class="plain"> },</span>
<span class="plain">{ </span><span class="constant">GLULX_VM</span><span class="plain">, -1, </span><span class="identifier">L</span><span class="string">"glulx"</span><span class="plain">, </span><span class="string">"ulx"</span><span class="plain">, </span><span class="string">"gblorb"</span><span class="plain">, </span><span class="string">"Glulx"</span><span class="plain">, </span><span class="string">"vm_glulx.png"</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">, 256, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Quixe"</span><span class="plain"> },</span>
<span class="plain">{ -1, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 15, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Parchment"</span><span class="plain"> }</span>
<span class="plain">};</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>At present, we infer the target virtual machine by looking at the file
extension requested at the command line.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">target_VM</span><span class="plain">; </span> <span class="comment">an index in the above table, or -1 if unknown</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::set_identifier</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">text</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">target_VM</span><span class="plain"> = </span><span class="constant">DEFAULT_TARGET_VM</span><span class="plain">; </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">);</span>
<span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">, </span><span class="identifier">text</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::get_first_char</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">) == </span><span class="character">'.'</span><span class="plain">) </span><span class="identifier">Str::delete_first_character</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">);</span>
<span class="identifier">LOOP_THROUGH_TEXT</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">file_extension</span><span class="plain">)</span>
<span class="identifier">Str::put</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">Characters::tolower</span><span class="plain">(</span><span class="identifier">Str::get</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">)));</span>
<span class="identifier">target_VM</span><span class="plain"> = -1;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_extension</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Str::eq_narrow_string</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">, </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_extension</span><span class="plain">)))</span>
<span class="identifier">target_VM</span><span class="plain"> = </span><span class="identifier">i</span><span class="plain">;</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">file_extension</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::set_identifier is used in 1/mr (<a href="1-mr.html#SP4_5">&#167;4.5</a>).</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>To help Inform detect overflows, it needs to know whether integers in the
target VM are 16 or 32 bits wide:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::is_16_bit</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_is_32_bit</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::is_16_bit is used in <a href="#SP9">&#167;9</a>, <a href="#SP19">&#167;19</a>, <a href="#SP21">&#167;21</a>, 1/mr (<a href="1-mr.html#SP4_15">&#167;4.15</a>), 5/lp (<a href="5-lp.html#SP12_2">&#167;12.2</a>, <a href="5-lp.html#SP18_3">&#167;18.3</a>), 6/rlt (<a href="6-rlt.html#SP14">&#167;14</a>), 13/rsfk (<a href="13-rsfk.html#SP18_1">&#167;18.1</a>, <a href="13-rsfk.html#SP20">&#167;20</a>), 25/cii (<a href="25-cii.html#SP3_5_8_3">&#167;3.5.8.3</a>).</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>Fundamental constants are emitted about our choice of virtual machine.
</p>
<p class="inwebparagraph">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 <code class="display"><span class="extract">WORDSIZE</span></code>
constant is the word size in bytes, so is the multiplier between <code class="display"><span class="extract">-&gt;</span></code> and
<code class="display"><span class="extract">--&gt;</span></code> offsets in I6 pointer syntax.
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(1) <code class="display"><span class="extract">NULL</span></code> 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.
</li></ul>
<ul class="items"><li>(2) <code class="display"><span class="extract">WORD_HIGHBIT</span></code> is the most significant bit in the VM's data word.
</li></ul>
<ul class="items"><li>(3) <code class="display"><span class="extract">IMPROBABLE_VALUE</span></code> 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.
</li></ul>
<ul class="items"><li>(4) <code class="display"><span class="extract">MAX_POSITIVE_NUMBER</span></code> is the largest representable positive (signed)
integer, in twos-complement form.
</li></ul>
<ul class="items"><li>(5) <code class="display"><span class="extract">REPARSE_CODE</span></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 <code class="display"><span class="extract">REPARSE_CODE</span></code> for
some purposes. And expects the result to be greater than <code class="display"><span class="extract">REPARSE_CODE</span></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.
</li></ul>
<pre class="display">
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">id</span><span class="plain">, </span><span class="identifier">inter_t</span><span class="plain"> </span><span class="identifier">val</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">);</span>
<span class="functiontext">Hierarchy::make_available</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="functiontext">Emit::named_numeric_constant</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">iname</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::emit_signed_fundamental_constant</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">id</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">val</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">);</span>
<span class="functiontext">Hierarchy::make_available</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="functiontext">Emit::named_numeric_constant_signed</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">iname</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">id</span><span class="plain">, </span><span class="identifier">inter_t</span><span class="plain"> </span><span class="identifier">val</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">);</span>
<span class="functiontext">Hierarchy::make_available</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="functiontext">Emit::named_numeric_constant_hex</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">iname</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::emit_unchecked_hex_fundamental_constant</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">id</span><span class="plain">, </span><span class="identifier">inter_t</span><span class="plain"> </span><span class="identifier">val</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">);</span>
<span class="functiontext">Hierarchy::make_available</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="functiontext">Emit::named_unchecked_constant_hex</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">val</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">iname</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::emit_fundamental_constants</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">this_is_a_release_compile</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) || (</span><span class="identifier">this_is_a_debug_compile</span><span class="plain">))</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">DEBUG_HL</span><span class="plain">, 1);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="constant">Z_VM</span><span class="plain">) {</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">TARGET_ZCODE_HL</span><span class="plain">, 1);</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">DICT_WORD_SIZE_HL</span><span class="plain">, 6);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="constant">GLULX_VM</span><span class="plain">) {</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">TARGET_GLULX_HL</span><span class="plain">, 1);</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">DICT_WORD_SIZE_HL</span><span class="plain">, 9);</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">INDIV_PROP_START_HL</span><span class="plain">, 0);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_is_32_bit</span><span class="plain">) {</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">WORDSIZE_HL</span><span class="plain">, 4);</span>
<span class="functiontext">VirtualMachines::emit_unchecked_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">NULL_HL</span><span class="plain">, 0</span><span class="identifier">xffffffff</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">WORD_HIGHBIT_HL</span><span class="plain">, 0</span><span class="identifier">x80000000</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">WORD_NEXTTOHIGHBIT_HL</span><span class="plain">, 0</span><span class="identifier">x40000000</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">IMPROBABLE_VALUE_HL</span><span class="plain">, 0</span><span class="identifier">xdeadce11</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">REPARSE_CODE_HL</span><span class="plain">, 0</span><span class="identifier">x40000000</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">MAX_POSITIVE_NUMBER_HL</span><span class="plain">, 2147483647);</span>
<span class="functiontext">VirtualMachines::emit_signed_fundamental_constant</span><span class="plain">(</span><span class="constant">MIN_NEGATIVE_NUMBER_HL</span><span class="plain">, -2147483648);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">WORDSIZE_HL</span><span class="plain">, 2);</span>
<span class="functiontext">VirtualMachines::emit_unchecked_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">NULL_HL</span><span class="plain">, 0</span><span class="identifier">xffff</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">WORD_HIGHBIT_HL</span><span class="plain">, 0</span><span class="identifier">x8000</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">WORD_NEXTTOHIGHBIT_HL</span><span class="plain">, 0</span><span class="identifier">x4000</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">IMPROBABLE_VALUE_HL</span><span class="plain">, 0</span><span class="identifier">x7fe3</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::emit_hex_fundamental_constant</span><span class="plain">(</span><span class="constant">REPARSE_CODE_HL</span><span class="plain">, 10000);</span>
<span class="functiontext">VirtualMachines::emit_fundamental_constant</span><span class="plain">(</span><span class="constant">MAX_POSITIVE_NUMBER_HL</span><span class="plain">, 32767);</span>
<span class="functiontext">VirtualMachines::emit_signed_fundamental_constant</span><span class="plain">(</span><span class="constant">MIN_NEGATIVE_NUMBER_HL</span><span class="plain">, -32768);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::emit_fundamental_constant appears nowhere else.</p>
<p class="endnote">The function VirtualMachines::emit_signed_fundamental_constant appears nowhere else.</p>
<p class="endnote">The function VirtualMachines::emit_hex_fundamental_constant appears nowhere else.</p>
<p class="endnote">The function VirtualMachines::emit_unchecked_hex_fundamental_constant appears nowhere else.</p>
<p class="endnote">The function VirtualMachines::emit_fundamental_constants is used in 27/ei (<a href="27-ei.html#SP2">&#167;2</a>).</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>Using which:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::veto_number</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">X</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (((</span><span class="identifier">X</span><span class="plain"> &gt; 32767) || (</span><span class="identifier">X</span><span class="plain"> &lt; -32768)) &amp;&amp; (</span><span class="functiontext">VirtualMachines::is_16_bit</span><span class="plain">())) {</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_LiteralOverflow</span><span class="plain">),</span>
<span class="string">"you use a number which is too large"</span><span class="plain">,</span>
<span class="string">"at least with the Settings for this project as they currently "</span>
<span class="string">"are. (Change to Glulx to be allowed to use much larger numbers.)"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::veto_number appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>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.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::allow_this_many_locals</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.max_locals</span><span class="plain"> &gt;= 0) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.max_locals</span><span class="plain"> &lt; </span><span class="identifier">N</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::allow_MAX_LOCAL_VARIABLES</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.max_locals</span><span class="plain"> &gt; 15) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::allow_this_many_locals is used in 26/rt (<a href="26-rt.html#SP4">&#167;4</a>).</p>
<p class="endnote">The function VirtualMachines::allow_MAX_LOCAL_VARIABLES is used in 26/uo (<a href="26-uo.html#SP18">&#167;18</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>Real numbers are also a concern:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::supports</span><span class="plain">(</span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Kinds::FloatingPoint::uses_floating_point</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_is_32_bit</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::supports is used in 13/rsfk (<a href="13-rsfk.html#SP26">&#167;26</a>), 20/eq (<a href="20-eq.html#SP41">&#167;41</a>).</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>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 &mdash; should not blorb be one unified wrapper? &mdash; but
interpreter writers disagree.)
</p>
<pre class="display">
<span class="reserved">char</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::get_blorbed_extension</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_blorbed_extension</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::get_blorbed_extension appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>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:
</p>
<pre class="display">
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="functiontext">VirtualMachines::get_default_interpreter</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.default_browser_interpreter</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::get_default_interpreter appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. Parsing VM restrictions. </b>Given a word range, we see what set of virtual machines it specifies. For example,
the result of calling
</p>
<blockquote>
<p>for Z-machine version 5 or 8 only</p>
</blockquote>
<p class="inwebparagraph">is that the <code class="display"><span class="extract">VM_matches</span></code> field in the table above is set for the two minor VMs
cited, and cleared for all of the others, while the <code class="display"><span class="extract">VM_matching_error_thrown</span></code>
is false (since the text was valid). The same result is produced by
</p>
<blockquote>
<p>for Z-machine versions 5 and 8 only</p>
</blockquote>
<p class="inwebparagraph">English being quirky that way.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">THROW_VM_MATCHING_ERROR_AND_RETURN</span><span class="plain"> { </span><span class="identifier">VM_matching_error_thrown</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; }</span>
</pre>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">VM_matching_error_thrown</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span> <span class="comment">an error occurred during parsing</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">most_recent_major_VM</span><span class="plain">; </span> <span class="comment">most recent major VM which matched, or -1</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">version_can_be_inferred</span><span class="plain">; </span> <span class="comment">from earlier in the word range parsed</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::match_against</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Clean the slate ready for a fresh VM parse</span> <span class="cwebmacronumber">14.1</span>&gt;<span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::match_against is used in <a href="#SP16">&#167;16</a>, <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP14_1"></a><b>&#167;14.1. </b>It is slightly lazy of this code to use global variables to preserve state
through a sequence of function calls to <code class="display"><span class="extract">match_VM_from</span></code>, but sometimes a
little laziness is what we deserve.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Clean the slate ready for a fresh VM parse</span> <span class="cwebmacronumber">14.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="identifier">VM_matching_error_thrown</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">most_recent_major_VM</span><span class="plain"> = -1;</span>
<span class="identifier">version_can_be_inferred</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP14">&#167;14</a>.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b>Not much grammar is used to parse virtual machine identifications like:
</p>
<blockquote>
<p>Z-machine versions 5 and 8</p>
</blockquote>
<p class="inwebparagraph">The words "Z-machine" and "Glulx" are hard-wired so that they can't be
altered using Preform. (The Spanish for "Glulx", say, is "Glulx".) Preform
grammar is used first to split the list:
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; 0; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">preform_lookahead_mode</span><span class="plain">; </span> <span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">&gt; &lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; 0</span>
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">&gt; ==&gt; 0</span>
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="plain">, </span><span class="identifier">_and</span><span class="plain">/</span><span class="identifier">or</span><span class="plain"> &lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; |</span>
<span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain">/</span><span class="identifier">or</span><span class="plain"> &lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt;</span>
<span class="plain">&lt;</span><span class="identifier">vm</span><span class="plain">-</span><span class="identifier">description</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">&gt; ::=</span>
<span class="plain">... ==&gt; </span>&lt;<span class="cwebmacro">Parse latest term in word range list</span> <span class="cwebmacronumber">15.2</span>&gt;
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP15_1"></a><b>&#167;15.1. </b>Preform doesn't parse the VM names themselves, but it does pick up the
optional part about version numbering:
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">version</span><span class="plain">-</span><span class="identifier">identification</span><span class="plain">&gt; ::=</span>
<span class="identifier">version</span><span class="plain">/</span><span class="identifier">versions</span><span class="plain"> &lt;</span><span class="identifier">cardinal</span><span class="plain">-</span><span class="identifier">number</span><span class="plain">&gt; ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP15_2"></a><b>&#167;15.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Parse latest term in word range list</span> <span class="cwebmacronumber">15.2</span>&gt; =
</code></p>
<pre class="displaydefn">
&lt;<span class="cwebmacro">Detect major VM name, if given, and advance one word</span> <span class="cwebmacronumber">15.2.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Give up if no major VM name found in any term of the list so far</span> <span class="cwebmacronumber">15.2.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">version_specified</span><span class="plain"> = -1;</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">version</span><span class="plain">-</span><span class="identifier">identification</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="identifier">version_specified</span><span class="plain"> = </span><span class="constant">VMULT</span><span class="plain"> * &lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;;</span>
<span class="identifier">version_can_be_inferred</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">version_can_be_inferred</span><span class="plain">) &amp;&amp; (&lt;</span><span class="identifier">cardinal</span><span class="plain">-</span><span class="identifier">number</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">))) {</span>
<span class="identifier">version_specified</span><span class="plain"> = </span><span class="constant">VMULT</span><span class="plain"> * &lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="constant">THROW_VM_MATCHING_ERROR_AND_RETURN</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Score a match for this specific version of the major VM, if we know about it</span> <span class="cwebmacronumber">15.2.4</span>&gt;<span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
&lt;<span class="cwebmacro">Score a match for every known version of the major VM</span> <span class="cwebmacronumber">15.2.3</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP15_2_1"></a><b>&#167;15.2.1. </b>The word "version" is sometimes implicit, but not after a major VM name.
Thus "Glulx 3" is not allowed: it has to be "Glulx version 3".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Detect major VM name, if given, and advance one word</span> <span class="cwebmacronumber">15.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_major_name</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Word::compare_by_strcmp</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">), </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_major_name</span><span class="plain">))) {</span>
<span class="identifier">most_recent_major_VM</span><span class="plain"> = </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain">;</span>
<span class="identifier">version_can_be_inferred</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Wordings::trim_first_word</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_2">&#167;15.2</a>.</p>
<p class="inwebparagraph"><a id="SP15_2_2"></a><b>&#167;15.2.2. </b>The variable <code class="display"><span class="extract">VM_matching_error_thrown</span></code> may have been set either on
this term or a previous one: for instance, if we are reading "Squirrel
versions 4 and 7" then at the second term, "7", no major VM is named
but the variable remains set from "Squirrel" having been parsed at the
first term.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Give up if no major VM name found in any term of the list so far</span> <span class="cwebmacronumber">15.2.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">most_recent_major_VM</span><span class="plain"> == -1) </span><span class="constant">THROW_VM_MATCHING_ERROR_AND_RETURN</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_2">&#167;15.2</a>.</p>
<p class="inwebparagraph"><a id="SP15_2_3"></a><b>&#167;15.2.3. </b>We either make a run of matches:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Score a match for every known version of the major VM</span> <span class="cwebmacronumber">15.2.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="identifier">most_recent_major_VM</span><span class="plain">)</span>
<span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_2">&#167;15.2</a>.</p>
<p class="inwebparagraph"><a id="SP15_2_4"></a><b>&#167;15.2.4. </b>...or else we make a single match, or even none at all. This would not be
an error: if the request was for "version 71 of Chipmunk", and we were
unable to compile to this VM (so that no such minor VM record appeared in
the table) then the situation might be that we are reading the requirements
of some extension used by other people, who have a later version of Inform
than us, and which does compile to that VM.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Score a match for this specific version of the major VM, if we know about it</span> <span class="cwebmacronumber">15.2.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="identifier">most_recent_major_VM</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">version_specified</span><span class="plain"> == </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_version</span><span class="plain">))</span>
<span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP15_2">&#167;15.2</a>.</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>The following nonterminal matches any valid description of a virtual machine,
with result <code class="display"><span class="extract">TRUE</span></code> if the current target VM matches that description and
<code class="display"><span class="extract">FALSE</span></code> if not.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">virtual</span><span class="plain">-</span><span class="identifier">machine</span><span class="plain">&gt; </span><span class="identifier">internal</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::match_against</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VM_matching_error_thrown</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain">) *</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> *</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. Icons for virtual machines. </b>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:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::plot_icon</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">minor</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">minor</span><span class="plain">]</span><span class="element">.VM_image</span><span class="plain">) {</span>
<span class="identifier">HTML_TAG_WITH</span><span class="plain">(</span><span class="string">"img"</span><span class="plain">,</span>
<span class="string">"border=0 src=inform:/doc_images/%s"</span><span class="plain">,</span>
<span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">minor</span><span class="plain">]</span><span class="element">.VM_image</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&amp;nbsp;"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::write_key</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Extensions compatible with specific story file formats only: "</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">&gt;0) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", "</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::plot_icon</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%s"</span><span class="plain">, </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_name</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::plot_icon is used in <a href="#SP19">&#167;19</a>, <a href="#SP20">&#167;20</a>.</p>
<p class="endnote">The function VirtualMachines::write_key is used in 8/ec (<a href="8-ec.html#SP10_5">&#167;10.5</a>).</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. Describing the current VM. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::index_innards</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="functiontext">VirtualMachines::write_current</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="functiontext">UseOptions::index</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">Index::extra_link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 3);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"See some technicalities for Inform maintainers only"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">Index::extra_div_open</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 3, 2, </span><span class="string">"e0e0e0"</span><span class="plain">);</span>
<span class="functiontext">Plugins::Manage::show_configuration</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Add some paste buttons for the debugging log</span> <span class="cwebmacronumber">18.1</span>&gt;<span class="plain">;</span>
<span class="identifier">Index::extra_div_close</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"e0e0e0"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::index_innards appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP18_1"></a><b>&#167;18.1. </b>The index provides some hidden paste icons for these:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Add some paste buttons for the debugging log</span> <span class="cwebmacronumber">18.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Debugging log:"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">NO_DEFINED_DA_VALUES</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">debugging_aspect</span><span class="plain"> *</span><span class="identifier">da</span><span class="plain"> = &amp;(</span><span class="identifier">the_debugging_aspects</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">da</span><span class="plain">-&gt;</span><span class="identifier">unhyphenated_name</span><span class="plain">) &gt; 0) {</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">is</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">is</span><span class="plain">, </span><span class="string">"Include %S in the debugging log."</span><span class="plain">, </span><span class="identifier">da</span><span class="plain">-&gt;</span><span class="identifier">unhyphenated_name</span><span class="plain">);</span>
<span class="identifier">HTML::Javascript::paste_stream</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">is</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&amp;nbsp;%S"</span><span class="plain">, </span><span class="identifier">is</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">is</span><span class="plain">);</span>
<span class="identifier">HTML_TAG</span><span class="plain">(</span><span class="string">"br"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::write_current</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">target_VM</span><span class="plain"> == -1) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"target VM not set yet"</span><span class="plain">);</span>
<span class="identifier">Index::anchor</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"STORYFILE"</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Story file format: "</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::plot_icon</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">target_VM</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_name</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">target_VM</span><span class="plain">]</span><span class="element">.VM_name</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"No name available\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VirtualMachines::is_16_bit</span><span class="plain">()) {</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); </span><span class="identifier">Index::extra_link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 1);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"See estimates of memory usage"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">Index::extra_div_open</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 1, 1, </span><span class="string">"e0e0e0"</span><span class="plain">);</span>
<span class="functiontext">VirtualMachines::index_memory_usage</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="identifier">Index::extra_div_close</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"e0e0e0"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::write_current is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP20"></a><b>&#167;20. Displaying VM restrictions. </b>Given a word range, we parse it to set the match flags, then describe the
result as concisely as we can with a row of icons.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::write_icons</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">) {</span>
<span class="functiontext">VirtualMachines::match_against</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Display nothing if every VM matches</span> <span class="cwebmacronumber">20.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Display only the generic Z icon if every Z-machine VM version matches</span> <span class="cwebmacronumber">20.2</span>&gt;<span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain">)</span>
<span class="functiontext">VirtualMachines::plot_icon</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::write_icons is used in 8/ec (<a href="8-ec.html#SP10_7_4_1_1">&#167;10.7.4.1.1</a>), 8/ed2 (<a href="8-ed2.html#SP3_2_1_2">&#167;3.2.1.2</a>).</p>
<p class="inwebparagraph"><a id="SP20_1"></a><b>&#167;20.1. </b>To avoid the extensions directory page being plastered with gaudy but
uncommunicative icons, we leave blank space if the requirements are always
met. The icons are to signal exceptions.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Display nothing if every VM matches</span> <span class="cwebmacronumber">20.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">everything_matches</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">everything_matches</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">everything_matches</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP20_2"></a><b>&#167;20.2. </b>This might happen if the user typed "for Z-machine only", but could also
come about if he typed a specification naming in turn each minor version we
know about, so the only way to check is to look at the match flag for each
one.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Display only the generic Z icon if every Z-machine VM version matches</span> <span class="cwebmacronumber">20.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">every_Z_matches</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="constant">Z_VM</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">))</span>
<span class="identifier">every_Z_matches</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">every_Z_matches</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Replace minor Z VMs in the match set with the single major one</span> <span class="cwebmacronumber">20.2.1</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP20_2_1"></a><b>&#167;20.2.1. </b>The following operation leaves the match set in a state which does not
correspond to what parsing would tell us (indeed, that's the point): so
we must not use the match set again without reparsing it. But in fact,
the match set is always recalculated before being used, so this is fine.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Replace minor Z VMs in the match set with the single major one</span> <span class="cwebmacronumber">20.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> &gt;= 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_code</span><span class="plain"> == </span><span class="constant">Z_VM</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_major_name</span><span class="plain">) </span> <span class="comment">the major VM line for Z</span>
<span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">else</span>
<span class="identifier">table_of_VM_data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.VM_matches</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span> <span class="comment">one of the minor ones</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20_2">&#167;20.2</a>.</p>
<p class="inwebparagraph"><a id="SP21"></a><b>&#167;21. </b>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.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">NOTEWORTHY_USAGE_THRESHOLD</span><span class="plain"> 50 </span> <span class="comment">don't mention arrays smaller than this, in bytes</span>
</pre>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::note_usage</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">cat</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">words</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">bytes</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">each</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">b</span><span class="plain"> = </span><span class="identifier">bytes</span><span class="plain"> + </span><span class="identifier">words</span><span class="plain">*((</span><span class="functiontext">VirtualMachines::is_16_bit</span><span class="plain">())?2:4);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">each</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp; (</span><span class="identifier">b</span><span class="plain"> &lt; </span><span class="constant">NOTEWORTHY_USAGE_THRESHOLD</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">b</span><span class="plain"> == 0) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">VM_usage_note</span><span class="plain"> *</span><span class="identifier">VMun</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">VM_usage_note</span><span class="plain">);</span>
<span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
<span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;usage_explained</span><span class="plain"> = </span><span class="identifier">Str::duplicate</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">);</span>
<span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;usage_category</span><span class="plain"> = </span><span class="identifier">cat</span><span class="plain">;</span>
<span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain"> = </span><span class="identifier">b</span><span class="plain">;</span>
<span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;each_flag</span><span class="plain"> = </span><span class="identifier">each</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::note_usage is used in 6/rlt (<a href="6-rlt.html#SP20">&#167;20</a>), 15/epv (<a href="15-epv.html#SP1">&#167;1</a>), 19/rsft (<a href="19-rsft.html#SP1_4">&#167;1.4</a>).</p>
<p class="inwebparagraph"><a id="SP22"></a><b>&#167;22. </b>The explanatory note here probably ought to use the words "approximately",
"incomplete" and so forth. It's really no better than a guide.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VirtualMachines::index_memory_usage</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">nr</span><span class="plain"> = </span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="reserved">VM_usage_note</span><span class="plain">);</span>
<span class="reserved">VM_usage_note</span><span class="plain"> **</span><span class="identifier">sorted</span><span class="plain"> = </span><span class="identifier">Memory::I7_calloc</span><span class="plain">(</span><span class="identifier">nr</span><span class="plain">, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">VM_usage_note</span><span class="plain"> *), </span><span class="constant">INDEX_SORTING_MREASON</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"In a Z-machine story file, array memory can be very limited. "</span>
<span class="string">"Switching to the Glulx setting removes all difficulty, but some authors "</span>
<span class="string">"like to squeeze the very most out of the Z-machine instead. This "</span>
<span class="string">"list shows about how much array space is used by some larger items "</span>
<span class="string">"the source text has chosen to create."</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Sort the array usages</span> <span class="cwebmacronumber">22.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Tabulate the array usages</span> <span class="cwebmacronumber">22.1</span>&gt;<span class="plain">;</span>
<span class="identifier">Memory::I7_array_free</span><span class="plain">(</span><span class="identifier">sorted</span><span class="plain">, </span><span class="constant">INDEX_SORTING_MREASON</span><span class="plain">, </span><span class="identifier">nr</span><span class="plain">, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">VM_usage_note</span><span class="plain"> *));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::index_memory_usage is used in <a href="#SP19">&#167;19</a>.</p>
<p class="inwebparagraph"><a id="SP22_1"></a><b>&#167;22.1. </b>The rows in the table mention pathetically small numbers of bytes, of course,
by any rational measure.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Tabulate the array usages</span> <span class="cwebmacronumber">22.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">HTML::begin_plain_html_table</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">VM_usage_note</span><span class="plain"> *</span><span class="identifier">VMun</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">nr</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="identifier">VMun</span><span class="plain"> = </span><span class="identifier">sorted</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">];</span>
<span class="identifier">HTML::first_html_column</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 0);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%s"</span><span class="plain">, </span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;usage_category</span><span class="plain">);</span>
<span class="identifier">HTML::next_html_column</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 0);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;each_flag</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"each "</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;usage_explained</span><span class="plain">) &gt; 0)</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%S"</span><span class="plain">, </span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;usage_explained</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">) &gt;= 0)</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%W"</span><span class="plain">, </span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">) &gt;= 0)</span>
<span class="identifier">Index::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">));</span>
<span class="identifier">HTML::next_html_column</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, 0);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d bytes"</span><span class="plain">, </span><span class="identifier">VMun</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain">);</span>
<span class="identifier">HTML::end_html_row</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">HTML::end_html_table</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP22_2"></a><b>&#167;22.2. </b>As usual, we sort with the C library's <code class="display"><span class="extract">qsort</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Sort the array usages</span> <span class="cwebmacronumber">22.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = 0;</span>
<span class="reserved">VM_usage_note</span><span class="plain"> *</span><span class="identifier">VMun</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">VMun</span><span class="plain">, </span><span class="reserved">VM_usage_note</span><span class="plain">) </span><span class="identifier">sorted</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++] = </span><span class="identifier">VMun</span><span class="plain">;</span>
<span class="identifier">qsort</span><span class="plain">(</span><span class="identifier">sorted</span><span class="plain">, (</span><span class="identifier">size_t</span><span class="plain">) </span><span class="identifier">nr</span><span class="plain">, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">VM_usage_note</span><span class="plain"> *), </span><span class="functiontext">VirtualMachines::compare_usage</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP23"></a><b>&#167;23. </b>The following means the table is sorted in decreasing order of bytes used,
with ties resolved by listing the first-declared item first.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::compare_usage</span><span class="plain">(</span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">ent1</span><span class="plain">, </span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">ent2</span><span class="plain">) {</span>
<span class="reserved">const</span><span class="plain"> </span><span class="reserved">VM_usage_note</span><span class="plain"> *</span><span class="identifier">v1</span><span class="plain"> = *((</span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">VM_usage_note</span><span class="plain"> **) </span><span class="identifier">ent1</span><span class="plain">);</span>
<span class="reserved">const</span><span class="plain"> </span><span class="reserved">VM_usage_note</span><span class="plain"> *</span><span class="identifier">v2</span><span class="plain"> = *((</span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">VM_usage_note</span><span class="plain"> **) </span><span class="identifier">ent2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">v2</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain"> != </span><span class="identifier">v1</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">v2</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain"> - </span><span class="identifier">v1</span><span class="plain">-</span><span class="element">&gt;bytes_used</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">v1</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">) - </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">v2</span><span class="plain">-</span><span class="element">&gt;structure_name</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::compare_usage is used in <a href="#SP22_2">&#167;22.2</a>.</p>
<p class="inwebparagraph"><a id="SP24"></a><b>&#167;24. Resource ID numbers. </b>Resources in a Blorb file have unique ID numbers which are positive integers,
but these are not required to start from 1, nor to be contiguous. For Inform,
ID number 1 is reserved for the cover image (whether or not any cover image
is provided: it is legal for there to be figures but no cover, and vice versa).
Other figures, and sound effects, then mix freely as needed from ID number 3
on upwards. We skip 2 so that it can be guaranteed that no sound resource
has ID 1 or 2: this is to help people trying to play sounds in the Z-machine,
where operand 1 or 2 in the <code class="display"><span class="extract">@sound</span></code> opcode signifies not a sound resource
number but a long or short beep. If a genuine sound effect had resource ID
1 or 2, therefore, it would be unplayable on the Z-machine.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">next_free_resource_ID</span><span class="plain"> = 3;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VirtualMachines::get_next_free_blorb_resource_ID</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">next_free_resource_ID</span><span class="plain">++;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VirtualMachines::get_next_free_blorb_resource_ID appears nowhere else.</p>
<hr class="tocbar">
<ul class="toc"><li><i>(This section begins Chapter 26: Compilation Utilities.)</i></li><li><a href="26-i6i.html">Continue with 'Inform 6 Inclusions'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>