520 lines
73 KiB
HTML
520 lines
73 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
|
<html>
|
||
|
<head>
|
||
|
<title>2/pn</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 '3/ta' generated by inweb 6P91-->
|
||
|
<ul class="crumbs"><li><a href="../webs.html">★</a></li><li><a href="index.html">inweb 7</a></li><li><a href="index.html#3">Chapter 3: Outputs</a></li><li><b>The Analyser</b></li></ul><p class="purpose">Here we analyse the code in the web, enabling us to see how functions and data structures are used within the program.</p>
|
||
|
|
||
|
<ul class="toc"><li><a href="#SP1">§1. Scanning webs</a></li><li><a href="#SP2">§2. The section catalogue</a></li><li><a href="#SP3">§3. Analysing code</a></li><li><a href="#SP5">§5. Identifier searching</a></li><li><a href="#SP6">§6. The identifier hash table</a></li><li><a href="#SP13">§13. Open-source project support</a></li></ul><hr class="tocbar">
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Scanning webs. </b>This scanner is intended for debugging Inweb, and simply shows the main
|
||
|
result of reading in and parsing the web:
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::scan_line_categories</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">range</span><span class="plain">) {</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Scan of source lines for '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">range</span><span class="plain">);</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">count</span><span class="plain"> = 1;</span>
|
||
|
<span class="reserved">chapter</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain"> = </span><span class="functiontext">Reader::get_chapter_for_range</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">range</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">C</span><span class="plain">) {</span>
|
||
|
<span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">section</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>sections</span><span class="plain">)</span>
|
||
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>first_line</span><span class="plain">; </span><span class="identifier">L</span><span class="plain">; </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">)</span>
|
||
|
<<span class="cwebmacro">Trace the content and category of this source line</span> <span class="cwebmacronumber">1.1</span>><span class="plain">;</span>
|
||
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
||
|
<span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain"> = </span><span class="functiontext">Reader::get_section_for_range</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">range</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">S</span><span class="plain">) {</span>
|
||
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>first_line</span><span class="plain">; </span><span class="identifier">L</span><span class="plain">; </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">)</span>
|
||
|
<<span class="cwebmacro">Trace the content and category of this source line</span> <span class="cwebmacronumber">1.1</span>>
|
||
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">chapter</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">-</span><span class="element">>chapters</span><span class="plain">)</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">section</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>sections</span><span class="plain">)</span>
|
||
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>first_line</span><span class="plain">; </span><span class="identifier">L</span><span class="plain">; </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">)</span>
|
||
|
<<span class="cwebmacro">Trace the content and category of this source line</span> <span class="cwebmacronumber">1.1</span>><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::scan_line_categories is used in 1/pc (<a href="1-pc.html#SP7_2_1">§7.2.1</a>).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP1_1"></a><b>§1.1. </b><code class="display">
|
||
|
<<span class="cwebmacrodefn">Trace the content and category of this source line</span> <span class="cwebmacronumber">1.1</span>> =
|
||
|
</code></p>
|
||
|
|
||
|
|
||
|
<pre class="displaydefn">
|
||
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
|
||
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="string">"%s"</span><span class="plain">, </span><span class="functiontext">Lines::category_name</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>category</span><span class="plain">));</span>
|
||
|
<span class="reserved">while</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">) < 20) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="character">'.'</span><span class="plain">);</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"%07d %S %S\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">count</span><span class="plain">++, </span><span class="identifier">C</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text</span><span class="plain">);</span>
|
||
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">This code is used in <a href="#SP1">§1</a> (three times).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. The section catalogue. </b>This provides quite a useful overview of the sections. As we'll see frequently
|
||
|
in Chapter 4, we call out to a general routine in Chapter 5 to provide
|
||
|
annotations which are programming-language specific; the aim is to abstract
|
||
|
so that Chapter 4 contains no assumptions about the language.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="definitions">
|
||
|
<span class="definitionkeyword">enum</span> <span class="constant">BASIC_SECTIONCAT</span><span class="definitionkeyword"> from </span><span class="constant">1</span>
|
||
|
<span class="definitionkeyword">enum</span> <span class="constant">STRUCTURES_SECTIONCAT</span>
|
||
|
<span class="definitionkeyword">enum</span> <span class="constant">FUNCTIONS_SECTIONCAT</span>
|
||
|
</pre>
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::catalogue_the_sections</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">range</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">form</span><span class="plain">) {</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">max_width</span><span class="plain"> = 0, </span><span class="identifier">max_range_width</span><span class="plain"> = 0;</span>
|
||
|
<span class="reserved">chapter</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">;</span>
|
||
|
<span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">chapter</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">-</span><span class="element">>chapters</span><span class="plain">)</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">section</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>sections</span><span class="plain">) {</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">max_range_width</span><span class="plain"> < </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">-</span><span class="element">>range</span><span class="plain">)) </span><span class="identifier">max_range_width</span><span class="plain"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">-</span><span class="element">>range</span><span class="plain">);</span>
|
||
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">);</span>
|
||
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">, </span><span class="string">"Chapter %S/%S"</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>ch_range</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>sect_title</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">max_width</span><span class="plain"> < </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">)) </span><span class="identifier">max_width</span><span class="plain"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">);</span>
|
||
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="reserved">chapter</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">-</span><span class="element">>chapters</span><span class="plain">)</span>
|
||
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">range</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"0"</span><span class="plain">)) || (</span><span class="functiontext">Str::eq</span><span class="plain">(</span><span class="identifier">range</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>ch_range</span><span class="plain">))) {</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">" -----\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">section</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>sections</span><span class="plain">) {</span>
|
||
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">);</span>
|
||
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">, </span><span class="string">"Chapter %S/%S"</span><span class="plain">, </span><span class="identifier">C</span><span class="plain">-</span><span class="element">>ch_range</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>sect_title</span><span class="plain">);</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"%4d %S"</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>sect_extent</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-</span><span class="element">>range</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"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">-</span><span class="element">>range</span><span class="plain">); </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">max_range_width</span><span class="plain">+2; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"%S"</span><span class="plain">, </span><span class="identifier">main_title</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"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">); </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">max_width</span><span class="plain">+2; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> != </span><span class="constant">BASIC_SECTIONCAT</span><span class="plain">)</span>
|
||
|
<span class="functiontext">Languages::catalogue</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">-</span><span class="element">>sect_language</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">,</span>
|
||
|
<span class="plain">(</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FUNCTIONS_SECTIONCAT</span><span class="plain">)?</span><span class="constant">TRUE</span><span class="plain">:</span><span class="constant">FALSE</span><span class="plain">);</span>
|
||
|
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
||
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">main_title</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::catalogue_the_sections is used in 1/pc (<a href="1-pc.html#SP7_2_1">§7.2.1</a>).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. Analysing code. </b>We can't pretend to a full-scale static analysis of the code — for one thing,
|
||
|
that would mean knowing more about the syntax of the web's language than we
|
||
|
actually do. So the following provides only a toolkit which other code can
|
||
|
use when looking for certain syntactic patterns: something which looks like
|
||
|
a function call, or a C structure field reference, for example. These are
|
||
|
all essentially based on spotting identifiers in the code, but with
|
||
|
punctuation around them.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph">Usage codes are used to define a set of allowed contexts in which to spot
|
||
|
these identifiers.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="definitions">
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">ELEMENT_ACCESS_USAGE</span><span class="plain"> 0</span><span class="identifier">x00000001</span><span class="plain"> </span> <span class="comment">C-like languages: access via <code class="display"><span class="extract">-></span></code> or <code class="display"><span class="extract">.</span></code> operators to structure element</span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">FCALL_USAGE</span><span class="plain"> 0</span><span class="identifier">x00000002</span><span class="plain"> </span> <span class="comment">C-like languages: function call made using brackets, <code class="display"><span class="extract">name(args)</span></code></span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">PREFORM_IN_CODE_USAGE</span><span class="plain"> 0</span><span class="identifier">x00000004</span><span class="plain"> </span> <span class="comment">InC only: use of a Preform nonterminal as a C "constant"</span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">PREFORM_IN_GRAMMAR_USAGE</span><span class="plain"> 0</span><span class="identifier">x00000008</span><span class="plain"> </span> <span class="comment">InC only: ditto, but within Preform production rather than C code</span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">MISC_USAGE</span><span class="plain"> 0</span><span class="identifier">x00000010</span><span class="plain"> </span> <span class="comment">any other appearance as an identifier</span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">ANY_USAGE</span><span class="plain"> 0</span><span class="identifier">x7fffffff</span><span class="plain"> </span> <span class="comment">any of the above</span>
|
||
|
</pre>
|
||
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. </b>The main analysis routine goes through a web as follows. Note that we only
|
||
|
perform the search here, we don't comment on the results; any action to be
|
||
|
taken must be handled by <code class="display"><span class="extract">Languages::late_preweave_analysis</span></code> when we're done.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::analyse_code</span><span class="plain">(</span><span class="reserved">web</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">W</span><span class="plain">-</span><span class="element">>analysed</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
||
|
|
||
|
<<span class="cwebmacro">Ask language-specific code to identify search targets, and parse the Interfaces</span> <span class="cwebmacronumber">4.1</span>><span class="plain">;</span>
|
||
|
|
||
|
<span class="reserved">chapter</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">;</span>
|
||
|
<span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_WITHIN_TANGLE</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="functiontext">Tangler::primary_target</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">))</span>
|
||
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>category</span><span class="plain">) {</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">BEGIN_DEFINITION_LCAT</span><span class="plain">:</span>
|
||
|
<<span class="cwebmacro">Perform analysis on the body of the definition</span> <span class="cwebmacronumber">4.3</span>><span class="plain">;</span>
|
||
|
<span class="reserved">break</span><span class="plain">;</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CODE_BODY_LCAT</span><span class="plain">:</span>
|
||
|
<<span class="cwebmacro">Perform analysis on a typical line of code</span> <span class="cwebmacronumber">4.2</span>><span class="plain">;</span>
|
||
|
<span class="reserved">break</span><span class="plain">;</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PREFORM_GRAMMAR_LCAT</span><span class="plain">:</span>
|
||
|
<<span class="cwebmacro">Perform analysis on productions in a Preform grammar</span> <span class="cwebmacronumber">4.4</span>><span class="plain">;</span>
|
||
|
<span class="reserved">break</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
|
||
|
<span class="functiontext">Languages::late_preweave_analysis</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-</span><span class="element">>main_language</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
|
||
|
<span class="identifier">W</span><span class="plain">-</span><span class="element">>analysed</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::analyse_code is used in 3/ts (<a href="3-ts.html#SP2">§2</a>).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP4_1"></a><b>§4.1. </b>First, we call any language-specific code, whose task is to identify what we
|
||
|
should be looking for: for example, the C-like languages code tells us (see
|
||
|
below) to look for names of particular functions it knows about.
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph">In Version 1 webs, this code is also expected to parse any Interface lines in
|
||
|
a section which it recognises, marking those by setting their
|
||
|
<code class="display"><span class="extract">interface_line_identified</span></code> flags. Any that are left must be erroneous.
|
||
|
Version 2 removed Interface altogeter as being cumbersome for no real gain in
|
||
|
practice.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="macrodefinition"><code class="display">
|
||
|
<<span class="cwebmacrodefn">Ask language-specific code to identify search targets, and parse the Interfaces</span> <span class="cwebmacronumber">4.1</span>> =
|
||
|
</code></p>
|
||
|
|
||
|
|
||
|
<pre class="displaydefn">
|
||
|
<span class="functiontext">Languages::early_preweave_analysis</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-</span><span class="element">>main_language</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
|
||
|
|
||
|
<span class="reserved">chapter</span><span class="plain"> *</span><span class="identifier">C</span><span class="plain">;</span>
|
||
|
<span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_WITHIN_TANGLE</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="functiontext">Tangler::primary_target</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">L</span><span class="plain">-</span><span class="element">>category</span><span class="plain"> == </span><span class="constant">INTERFACE_BODY_LCAT</span><span class="plain">) &&</span>
|
||
|
<span class="plain">(</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>interface_line_identified</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) &&</span>
|
||
|
<span class="plain">(</span><span class="functiontext">Regexp::string_is_white_space</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">))</span>
|
||
|
<span class="functiontext">Main::error_in_web</span><span class="plain">(</span><span class="identifier">I</span><span class="string">"unrecognised interface line"</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">This code is used in <a href="#SP4">§4</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP4_2"></a><b>§4.2. </b><code class="display">
|
||
|
<<span class="cwebmacrodefn">Perform analysis on a typical line of code</span> <span class="cwebmacronumber">4.2</span>> =
|
||
|
</code></p>
|
||
|
|
||
|
|
||
|
<pre class="displaydefn">
|
||
|
<span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text</span><span class="plain">, </span><span class="constant">ANY_USAGE</span><span class="plain">, 0);</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">This code is used in <a href="#SP4">§4</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP4_3"></a><b>§4.3. </b><code class="display">
|
||
|
<<span class="cwebmacrodefn">Perform analysis on the body of the definition</span> <span class="cwebmacronumber">4.3</span>> =
|
||
|
</code></p>
|
||
|
|
||
|
|
||
|
<pre class="displaydefn">
|
||
|
<span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text_operand2</span><span class="plain">, </span><span class="constant">ANY_USAGE</span><span class="plain">, 0);</span>
|
||
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">) && (</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">-</span><span class="element">>category</span><span class="plain"> == </span><span class="constant">CONT_DEFINITION_LCAT</span><span class="plain">)) {</span>
|
||
|
<span class="identifier">L</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>next_line</span><span class="plain">;</span>
|
||
|
<span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text</span><span class="plain">, </span><span class="constant">ANY_USAGE</span><span class="plain">, 0);</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">This code is used in <a href="#SP4">§4</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP4_4"></a><b>§4.4. </b>Recall — or rather, see Chapter 5, where this all comes up — that lines
|
||
|
in a Preform grammar generally take the form of some BNF grammar, where we
|
||
|
want only to identify any nonterminals mentioned, then a <code class="display"><span class="extract">==></span></code> divider,
|
||
|
and then some C code to deal with a match. The code is subjected to analysis
|
||
|
just as any other code would be.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="macrodefinition"><code class="display">
|
||
|
<<span class="cwebmacrodefn">Perform analysis on productions in a Preform grammar</span> <span class="cwebmacronumber">4.4</span>> =
|
||
|
</code></p>
|
||
|
|
||
|
|
||
|
<pre class="displaydefn">
|
||
|
<span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text_operand2</span><span class="plain">, </span><span class="constant">ANY_USAGE</span><span class="plain">, 0);</span>
|
||
|
<span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>text_operand</span><span class="plain">, </span><span class="constant">PREFORM_IN_CODE_USAGE</span><span class="plain">, </span><span class="constant">PREFORM_IN_GRAMMAR_USAGE</span><span class="plain">);</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">This code is used in <a href="#SP4">§4</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. Identifier searching. </b>Here's what we actually do, then. We take the code fragment <code class="display"><span class="extract">text</span></code>, drawn
|
||
|
from part or all of source line <code class="display"><span class="extract">L</span></code> from web <code class="display"><span class="extract">W</span></code>, and look for any identifier
|
||
|
names used in one of the contexts in the bitmap <code class="display"><span class="extract">mask</span></code>. Any that we find are
|
||
|
passed to <code class="display"><span class="extract">Analyser::analyse_find</span></code>, along with the context they were found in (or, if
|
||
|
<code class="display"><span class="extract">transf</span></code> is nonzero, with <code class="display"><span class="extract">transf</span></code> as their context).
|
||
|
</p>
|
||
|
|
||
|
<p class="inwebparagraph">What we do is to look for instances of an identifier, defined as a maximal
|
||
|
string of <code class="display"><span class="extract">%i</span></code> characters or hyphens not followed by <code class="display"><span class="extract">></span></code> characters. (Thus
|
||
|
<code class="display"><span class="extract">fish-or-chips</span></code> counts, but <code class="display"><span class="extract">fish-</span></code> is not an identifier when it occurs in
|
||
|
<code class="display"><span class="extract">fish->bone</span></code>.)
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::analyse_as_code</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">mask</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">transf</span><span class="plain">) {</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">start_at</span><span class="plain"> = -1, </span><span class="identifier">element_follows</span><span class="plain"> = </span><span class="constant">FALSE</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"> < </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">text</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="functiontext">Regexp::identifier_char</span><span class="plain">(</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">))) ||</span>
|
||
|
<span class="plain">((</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'-'</span><span class="plain">) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+1) != </span><span class="character">'>'</span><span class="plain">))) {</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">start_at</span><span class="plain"> == -1) </span><span class="identifier">start_at</span><span class="plain"> = </span><span class="identifier">i</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">start_at</span><span class="plain"> != -1) {</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">u</span><span class="plain"> = </span><span class="constant">MISC_USAGE</span><span class="plain">;</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">element_follows</span><span class="plain">) </span><span class="identifier">u</span><span class="plain"> = </span><span class="constant">ELEMENT_ACCESS_USAGE</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="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'('</span><span class="plain">) </span><span class="identifier">u</span><span class="plain"> = </span><span class="constant">FCALL_USAGE</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="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'>'</span><span class="plain">) && (</span><span class="identifier">start_at</span><span class="plain"> > 0) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">start_at</span><span class="plain">-1) == </span><span class="character">'<'</span><span class="plain">))</span>
|
||
|
<span class="identifier">u</span><span class="plain"> = </span><span class="constant">PREFORM_IN_CODE_USAGE</span><span class="plain">;</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">u</span><span class="plain"> & </span><span class="identifier">mask</span><span class="plain">) {</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">transf</span><span class="plain">) </span><span class="identifier">u</span><span class="plain"> = </span><span class="identifier">transf</span><span class="plain">;</span>
|
||
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">identifier_found</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">j</span><span class="plain"> = 0; </span><span class="identifier">start_at</span><span class="plain"> + </span><span class="identifier">j</span><span class="plain"> < </span><span class="identifier">i</span><span class="plain">; </span><span class="identifier">j</span><span class="plain">++)</span>
|
||
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">identifier_found</span><span class="plain">, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">start_at</span><span class="plain"> + </span><span class="identifier">j</span><span class="plain">));</span>
|
||
|
<span class="functiontext">Analyser::analyse_find</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">identifier_found</span><span class="plain">, </span><span class="identifier">u</span><span class="plain">);</span>
|
||
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">identifier_found</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="identifier">start_at</span><span class="plain"> = -1; </span><span class="identifier">element_follows</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'.'</span><span class="plain">) </span><span class="identifier">element_follows</span><span class="plain"> = </span><span class="constant">TRUE</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="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">) == </span><span class="character">'-'</span><span class="plain">) && (</span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+1) == </span><span class="character">'>'</span><span class="plain">)) {</span>
|
||
|
<span class="identifier">element_follows</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++;</span>
|
||
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">element_follows</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::analyse_as_code is used in <a href="#SP4_2">§4.2</a>, <a href="#SP4_3">§4.3</a>, <a href="#SP4_4">§4.4</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP6"></a><b>§6. The identifier hash table. </b>We clearly need rapid access to a large symbols table, and we store this as
|
||
|
a hash. Identifiers are hash-coded with the following simple code, which is
|
||
|
simplified from one used by Inform; it's the algorithm called "X 30011"
|
||
|
in Aho, Sethi and Ullman, "Compilers: Principles, Techniques and Tools"
|
||
|
(1986), adapted slightly to separate out literal numbers.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="definitions">
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">HASH_TAB_SIZE</span><span class="plain"> 1000 </span> <span class="comment">the possible hash codes are 0 up to this minus 1</span>
|
||
|
<span class="definitionkeyword">define</span> <span class="constant">NUMBER_HASH</span><span class="plain"> 0 </span> <span class="comment">literal decimal integers, and no other words, have this hash code</span>
|
||
|
</pre>
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Analyser::hash_code_from_word</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">) {</span>
|
||
|
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">hash_code</span><span class="plain"> = 0;</span>
|
||
|
<span class="reserved">string_position</span><span class="plain"> </span><span class="identifier">p</span><span class="plain"> = </span><span class="functiontext">Str::start</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">);</span>
|
||
|
<span class="reserved">switch</span><span class="plain">(</span><span class="functiontext">Str::get</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)) {</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'-'</span><span class="plain">: </span><span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">) == 1) </span><span class="reserved">break</span><span class="plain">; </span> <span class="comment">an isolated minus sign is an ordinary word</span>
|
||
|
<span class="comment">and otherwise fall into...</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'0'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'1'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'2'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'3'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'4'</span><span class="plain">:</span>
|
||
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'5'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'6'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'7'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'8'</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="character">'9'</span><span class="plain">:</span>
|
||
|
<span class="comment">the first character may prove to be the start of a number: is this true?</span>
|
||
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain"> = </span><span class="functiontext">Str::forward</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">); </span><span class="functiontext">Str::in_range</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">); </span><span class="identifier">p</span><span class="plain"> = </span><span class="functiontext">Str::forward</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)) </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">isdigit</span><span class="plain">(</span><span class="functiontext">Str::get</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)) == </span><span class="constant">FALSE</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
|
||
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">NUMBER_HASH</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">=</span><span class="functiontext">Str::start</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">); </span><span class="functiontext">Str::in_range</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">); </span><span class="identifier">p</span><span class="plain"> = </span><span class="functiontext">Str::forward</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">))</span>
|
||
|
<span class="identifier">hash_code</span><span class="plain"> = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) ((</span><span class="reserved">int</span><span class="plain">) (</span><span class="identifier">hash_code</span><span class="plain">*30011) + (</span><span class="functiontext">Str::get</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)));</span>
|
||
|
<span class="reserved">return</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain">) (1+(</span><span class="identifier">hash_code</span><span class="plain"> % (</span><span class="constant">HASH_TAB_SIZE</span><span class="plain">-1))); </span> <span class="comment">result of X 30011, plus 1</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::hash_code_from_word is used in <a href="#SP9">§9</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. </b>The actual table is stored here:
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct hash_table</span><span class="plain"> {</span>
|
||
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">analysis_hash</span><span class="plain">[</span><span class="constant">HASH_TAB_SIZE</span><span class="plain">]; </span> <span class="comment">of <code class="display"><span class="extract">hash_table_entry</span></code></span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">analysis_hash_initialised</span><span class="plain">; </span> <span class="comment">when we start up, array's contents are undefined</span>
|
||
|
<span class="plain">}</span><span class="reserved"> hash_table</span><span class="plain">;</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The structure hash_table is private to this section.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP8"></a><b>§8. </b>Where we define:
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">hash_table_entry</span><span class="plain"> {</span>
|
||
|
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">hash_key</span><span class="plain">;</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">reserved_word</span><span class="plain">; </span> <span class="comment">in the language currently being woven, that is</span>
|
||
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">usages</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">hash_table_entry_usage</span></code></span>
|
||
|
<span class="constant">MEMORY_MANAGEMENT</span>
|
||
|
<span class="plain">} </span><span class="reserved">hash_table_entry</span><span class="plain">;</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The structure hash_table_entry is accessed in 3/tw, 4/cl, 4/is and here.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP9"></a><b>§9. </b>A single routine is used both to interrogate the hash and to lodge values
|
||
|
in it, as usual with symbols tables. For example, the code to handle C-like
|
||
|
languages prepares for code analysis by calling this routine on the name
|
||
|
of each C function.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="functiontext">Analyser::find_hash_entry</span><span class="plain">(</span><span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">create</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table</span><span class="plain"> *</span><span class="identifier">HT</span><span class="plain"> = &(</span><span class="identifier">S</span><span class="plain">-</span><span class="element">>sect_target</span><span class="plain">-</span><span class="element">>symbols</span><span class="plain">);</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">h</span><span class="plain"> = </span><span class="functiontext">Analyser::hash_code_from_word</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">h</span><span class="plain"> == </span><span class="constant">NUMBER_HASH</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash_initialised</span><span class="plain"> == </span><span class="constant">FALSE</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"><</span><span class="constant">HASH_TAB_SIZE</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
||
|
<span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash_initialised</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">] != </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="identifier">hte</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">hte</span><span class="plain">, </span><span class="reserved">hash_table_entry</span><span class="plain">, </span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">])</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::eq</span><span class="plain">(</span><span class="identifier">hte</span><span class="plain">-</span><span class="element">>hash_key</span><span class="plain">, </span><span class="identifier">text</span><span class="plain">))</span>
|
||
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">hte</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">create</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="identifier">hte</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">hash_table_entry</span><span class="plain">);</span>
|
||
|
<span class="identifier">hte</span><span class="plain">-</span><span class="element">>hash_key</span><span class="plain"> = </span><span class="functiontext">Str::duplicate</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">);</span>
|
||
|
<span class="identifier">hte</span><span class="plain">-</span><span class="element">>usages</span><span class="plain"> = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="reserved">hash_table_entry_usage</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">] == </span><span class="identifier">NULL</span><span class="plain">)</span>
|
||
|
<span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">] = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="reserved">hash_table_entry</span><span class="plain">);</span>
|
||
|
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">hte</span><span class="plain">, </span><span class="reserved">hash_table_entry</span><span class="plain">, </span><span class="identifier">HT</span><span class="plain">-</span><span class="element">>analysis_hash</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">]);</span>
|
||
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">hte</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::find_hash_entry is used in <a href="#SP10">§10</a>, <a href="#SP12">§12</a>, 3/tw (<a href="3-tw.html#SP2_2">§2.2</a>, <a href="3-tw.html#SP2_3">§2.3</a>), 4/cl (<a href="4-cl.html#SP21">§21</a>, <a href="4-cl.html#SP22">§22</a>), 4/is (<a href="4-is.html#SP14_1">§14.1</a>, <a href="4-is.html#SP14_2">§14.2</a>, <a href="4-is.html#SP18">§18</a>).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP10"></a><b>§10. </b>Marking and testing these bits:
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::mark_reserved_word</span><span class="plain">(</span><span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">e</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="identifier">hte</span><span class="plain"> = </span><span class="functiontext">Analyser::find_hash_entry</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">, </span><span class="constant">TRUE</span><span class="plain">);</span>
|
||
|
<span class="identifier">hte</span><span class="plain">-</span><span class="element">>reserved_word</span><span class="plain"> |= (1 << </span><span class="identifier">e</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Analyser::is_reserved_word</span><span class="plain">(</span><span class="reserved">section</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">e</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="identifier">hte</span><span class="plain"> = </span><span class="functiontext">Analyser::find_hash_entry</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">hte</span><span class="plain">) && (</span><span class="identifier">hte</span><span class="plain">-</span><span class="element">>reserved_word</span><span class="plain"> & (1 << </span><span class="identifier">e</span><span class="plain">))) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
||
|
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::mark_reserved_word is used in 2/tp (<a href="2-tp.html#SP1_1_6_5_1_6">§1.1.6.5.1.6</a>, <a href="2-tp.html#SP1_1_6_5_1_7">§1.1.6.5.1.7</a>), 4/cl (<a href="4-cl.html#SP3_2_2">§3.2.2</a>, <a href="4-cl.html#SP3_2_3_6">§3.2.3.6</a>, <a href="4-cl.html#SP3_4_2">§3.4.2</a>, <a href="4-cl.html#SP15">§15</a>).</p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::is_reserved_word is used in 4/cl (<a href="4-cl.html#SP18">§18</a>).</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. </b>Now we turn back to the actual analysis. When we spot an identifier that
|
||
|
we know, we record its usage with an instance of the following. Note that
|
||
|
each identifier can have at most one of these records per paragraph of code,
|
||
|
but that it can be used in multiple ways within that paragraph: for example,
|
||
|
a function might be both called and used as a constant value within the
|
||
|
same paragraph of code.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">hash_table_entry_usage</span><span class="plain"> {</span>
|
||
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">paragraph</span><span class="plain"> *</span><span class="identifier">usage_recorded_at</span><span class="plain">;</span>
|
||
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">form_of_usage</span><span class="plain">; </span> <span class="comment">bitmap of the <code class="display"><span class="extract">*_USAGE</span></code> constants defined above</span>
|
||
|
<span class="constant">MEMORY_MANAGEMENT</span>
|
||
|
<span class="plain">} </span><span class="reserved">hash_table_entry_usage</span><span class="plain">;</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The structure hash_table_entry_usage is accessed in 3/tw, 4/cl, 4/is and here.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP12"></a><b>§12. </b>And here's how we create these usages:
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::analyse_find</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">identifier</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">u</span><span class="plain">) {</span>
|
||
|
<span class="reserved">hash_table_entry</span><span class="plain"> *</span><span class="identifier">hte</span><span class="plain"> = </span><span class="functiontext">Analyser::find_hash_entry</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>owning_section</span><span class="plain">, </span><span class="identifier">identifier</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">hte</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
||
|
<span class="reserved">hash_table_entry_usage</span><span class="plain"> *</span><span class="identifier">hteu</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
||
|
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">hteu</span><span class="plain">, </span><span class="reserved">hash_table_entry_usage</span><span class="plain">, </span><span class="identifier">hte</span><span class="plain">-</span><span class="element">>usages</span><span class="plain">)</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-</span><span class="element">>owning_paragraph</span><span class="plain"> == </span><span class="identifier">hteu</span><span class="plain">-</span><span class="element">>usage_recorded_at</span><span class="plain">)</span>
|
||
|
<span class="reserved">break</span><span class="plain">;</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">hteu</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
||
|
<span class="identifier">hteu</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">hash_table_entry_usage</span><span class="plain">);</span>
|
||
|
<span class="identifier">hteu</span><span class="plain">-</span><span class="element">>form_of_usage</span><span class="plain"> = 0;</span>
|
||
|
<span class="identifier">hteu</span><span class="plain">-</span><span class="element">>usage_recorded_at</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-</span><span class="element">>owning_paragraph</span><span class="plain">;</span>
|
||
|
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">hteu</span><span class="plain">, </span><span class="reserved">hash_table_entry_usage</span><span class="plain">, </span><span class="identifier">hte</span><span class="plain">-</span><span class="element">>usages</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
<span class="identifier">hteu</span><span class="plain">-</span><span class="element">>form_of_usage</span><span class="plain"> |= </span><span class="identifier">u</span><span class="plain">;</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::analyse_find is used in <a href="#SP5">§5</a>.</p>
|
||
|
|
||
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. Open-source project support. </b>The work here is all delegated. In each case we look for a script in the web's
|
||
|
folder: failing that, we fall back on a default script belonging to Inweb.
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<pre class="display">
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::write_makefile</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">) {</span>
|
||
|
<span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">prototype</span><span class="plain"> = </span><span class="functiontext">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-</span><span class="element">>path_to_web</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"makescript.txt"</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (!(</span><span class="functiontext">TextFiles::exists</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">)))</span>
|
||
|
<span class="identifier">prototype</span><span class="plain"> = </span><span class="functiontext">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">path_to_inweb_materials</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"makescript.txt"</span><span class="plain">);</span>
|
||
|
<span class="functiontext">Makefiles::write</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">prototype</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
|
||
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Analyser::write_gitignore</span><span class="plain">(</span><span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">) {</span>
|
||
|
<span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">prototype</span><span class="plain"> = </span><span class="functiontext">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-</span><span class="element">>path_to_web</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"gitignorescript.txt"</span><span class="plain">);</span>
|
||
|
<span class="reserved">if</span><span class="plain"> (!(</span><span class="functiontext">TextFiles::exists</span><span class="plain">(</span><span class="identifier">prototype</span><span class="plain">)))</span>
|
||
|
<span class="identifier">prototype</span><span class="plain"> = </span><span class="functiontext">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">path_to_inweb_materials</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"gitignorescript.txt"</span><span class="plain">);</span>
|
||
|
<span class="functiontext">Git::write_gitignore</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">prototype</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
|
||
|
<span class="plain">}</span>
|
||
|
</pre>
|
||
|
|
||
|
<p class="inwebparagraph"></p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::write_makefile is used in 1/pc (<a href="1-pc.html#SP7_2_1">§7.2.1</a>).</p>
|
||
|
|
||
|
<p class="endnote">The function Analyser::write_gitignore is used in 1/pc (<a href="1-pc.html#SP7_2_1">§7.2.1</a>).</p>
|
||
|
|
||
|
<!--End of weave: 363 lines from a web of 20802-->
|
||
|
</body>
|
||
|
</html>
|
||
|
|