inweb-bootstrap/docs/inweb/3-tt.html
2020-04-10 21:29:28 +01:00

392 lines
49 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>The Tangler</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<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>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../inweb/index.html">inweb</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../foundation-module/index.html">foundation-module</a></li>
<li><a href="../foundation-test/index.html">foundation-test</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'The Tangler' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="index.html">inweb</a></li><li><a href="index.html#3">Chapter 3: Outputs</a></li><li><b>The Tangler</b></li></ul><p class="purpose">To transcribe a version of the text in the web into a form which can be compiled as a program.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. The Master Tangler</a></li><li><a href="#SP3">&#167;3. The Code Tangler</a></li><li><a href="#SP4">&#167;4. Prinary target</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. The Master Tangler. </b>Here's what has happened so far, on a <code class="display"><span class="extract">-tangle</span></code> run of Inweb: on any
other sort of run, of course, we would never be in this section of code.
The web was read completely into memory, and then fully parsed, with all
of the arrays and hashes populated. Program Control then sent us straight
here for the tangling to begin...
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Tangler::go</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">tangle_target</span><span class="plain"> *</span><span class="identifier">target</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">dest_file</span><span class="plain">) {</span>
<span class="reserved">programming_language</span><span class="plain"> *</span><span class="identifier">lang</span><span class="plain"> = </span><span class="identifier">target</span><span class="plain">-&gt;</span><span class="element">tangle_language</span><span class="plain">;</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">" tangling &lt;%/f&gt; (written in %S)\n"</span><span class="plain">, </span><span class="identifier">dest_file</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">-&gt;</span><span class="element">language_name</span><span class="plain">);</span>
<span class="reserved">text_stream</span><span class="plain"> </span><span class="identifier">TO_struct</span><span class="plain">;</span>
<span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">OUT</span><span class="plain"> = &amp;</span><span class="identifier">TO_struct</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">STREAM_OPEN_TO_FILE</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">dest_file</span><span class="plain">, </span><span class="constant">ISO_ENC</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">)</span>
<span class="functiontext">Errors::fatal_with_file</span><span class="plain">(</span><span class="string">"unable to write tangled file"</span><span class="plain">, </span><span class="identifier">dest_file</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Perform the actual tangle</span> <span class="cwebmacronumber">1.1</span>&gt;<span class="plain">;</span>
<span class="identifier">STREAM_CLOSE</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Tangle any imported headers</span> <span class="cwebmacronumber">1.2</span>&gt;<span class="plain">;</span>
<span class="functiontext">LanguageMethods::additional_tangling</span><span class="plain">(</span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">target</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Tangler::go is used in 1/pc (<a href="1-pc.html#SP7_4_2">&#167;7.4.2</a>).</p>
<p class="inwebparagraph"><a id="SP1_1"></a><b>&#167;1.1. </b>All of the sections are tangled together into one big file, the structure
of which can be seen below.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="identifier">LOOP_OVER_PARAGRAPHS</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="identifier">T</span><span class="plain">, </span><span class="identifier">P</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">-&gt;</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">-&gt;</span><span class="element">sections</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_target</span><span class="plain"> == </span><span class="identifier">T</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="reserved">paragraph</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">paragraphs</span><span class="plain">)</span>
</pre>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Perform the actual tangle</span> <span class="cwebmacronumber">1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="comment"> (a) The shebang line, a header for scripting languages, and other heading matter</span>
<span class="functiontext">LanguageMethods::shebang</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">target</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::disclaimer</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">target</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::additional_early_matter</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">target</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="reserved">paragraph</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_PARAGRAPHS</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="identifier">target</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">P</span><span class="plain">-&gt;</span><span class="element">placed_very_early</span><span class="plain">) &amp;&amp; (</span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">defines_macro</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">))</span>
<span class="functiontext">Tangler::tangle_paragraph</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="comment"> (b) Results of <code class="display"><span class="extract">@d</span></code> declarations</span>
&lt;<span class="cwebmacro">Tangle all the constant definitions in section order</span> <span class="cwebmacronumber">1.1.1</span>&gt;<span class="plain">;</span>
<span class="comment"> (c) Miscellaneous automated C predeclarations</span>
<span class="functiontext">LanguageMethods::additional_predeclarations</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="comment"> (d) Above-the-bar code from all of the sections (global variables, and such)</span>
<span class="identifier">LOOP_OVER_PARAGRAPHS</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="identifier">target</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">P</span><span class="plain">-&gt;</span><span class="element">placed_early</span><span class="plain">) &amp;&amp; (</span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">defines_macro</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">))</span>
<span class="functiontext">Tangler::tangle_paragraph</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="comment"> (e) Below-the-bar code: the bulk of the program itself</span>
<span class="identifier">LOOP_OVER_PARAGRAPHS</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="identifier">target</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">P</span><span class="plain">-&gt;</span><span class="element">placed_early</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) &amp;&amp; (</span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">placed_very_early</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) &amp;&amp; (</span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">defines_macro</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">))</span>
<span class="functiontext">Tangler::tangle_paragraph</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="comment"> (f) Opposite of the shebang: a footer</span>
<span class="functiontext">LanguageMethods::gnabehs</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP1">&#167;1</a>.</p>
<p class="inwebparagraph"><a id="SP1_1_1"></a><b>&#167;1.1.1. </b>This is the result of all those <code class="display"><span class="extract">@d</span></code> definitions; note that these sometimes
extend across multiple lines.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Tangle all the constant definitions in section order</span> <span class="cwebmacronumber">1.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<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="identifier">target</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">category</span><span class="plain"> == </span><span class="constant">BEGIN_DEFINITION_LCAT</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">default_defn</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Define the constant</span> <span class="cwebmacronumber">1.1.1.1</span>&gt;<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="identifier">target</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">category</span><span class="plain"> == </span><span class="constant">BEGIN_DEFINITION_LCAT</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">default_defn</span><span class="plain">) {</span>
<span class="functiontext">LanguageMethods::open_ifdef</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text_operand</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Define the constant</span> <span class="cwebmacronumber">1.1.1.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">LanguageMethods::close_ifdef</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text_operand</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="functiontext">Enumerations::define_extents</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">target</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP1_1">&#167;1.1</a>.</p>
<p class="inwebparagraph"><a id="SP1_1_1_1"></a><b>&#167;1.1.1.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Define the constant</span> <span class="cwebmacronumber">1.1.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">owning_paragraph</span><span class="plain"> == </span><span class="identifier">NULL</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">"misplaced definition"</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Tags::open_ifdefs</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">owning_paragraph</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::start_definition</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">,</span>
<span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text_operand</span><span class="plain">,</span>
<span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text_operand2</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="identifier">next_line</span><span class="plain">) &amp;&amp; (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">next_line</span><span class="plain">-&gt;</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">-&gt;</span><span class="element">next_line</span><span class="plain">;</span>
<span class="functiontext">LanguageMethods::prolong_definition</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="functiontext">LanguageMethods::end_definition</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">owning_paragraph</span><span class="plain">) </span><span class="functiontext">Tags::close_ifdefs</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">owning_paragraph</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP1_1_1">&#167;1.1.1</a> (twice).</p>
<p class="inwebparagraph"><a id="SP1_2"></a><b>&#167;1.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Tangle any imported headers</span> <span class="cwebmacronumber">1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</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">W</span><span class="plain">-&gt;</span><span class="element">headers</span><span class="plain">)</span>
<span class="functiontext">Shell::copy</span><span class="plain">(</span><span class="identifier">F</span><span class="plain">, </span><span class="functiontext">Reader::tangled_folder</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">), </span><span class="string">""</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP1">&#167;1</a>.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>So here is the main tangler for a single paragraph. We basically expect to
act only on <code class="display"><span class="extract">CODE_BODY_LCAT</span></code> lines (those containing actual code), unless
something quirky has been done to support a language feature.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Tangler::tangle_paragraph</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">paragraph</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain">) {</span>
<span class="functiontext">Tags::open_ifdefs</span><span class="plain">(</span><span class="identifier">OUT</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">contiguous</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">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">first_line_in_paragraph</span><span class="plain">;</span>
<span class="plain">((</span><span class="identifier">L</span><span class="plain">) &amp;&amp; (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">owning_paragraph</span><span class="plain"> == </span><span class="identifier">P</span><span class="plain">)); </span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">next_line</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">LanguageMethods::will_insert_in_tangle</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">under_section</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">)) {</span>
&lt;<span class="cwebmacro">Insert line marker if necessary to show the origin of this code</span> <span class="cwebmacronumber">2.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">LanguageMethods::insert_in_tangle</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">under_section</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">category</span><span class="plain"> != </span><span class="constant">CODE_BODY_LCAT</span><span class="plain">) || (</span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">suppress_tangling</span><span class="plain">)) {</span>
<span class="identifier">contiguous</span><span class="plain"> = </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
&lt;<span class="cwebmacro">Insert line marker if necessary to show the origin of this code</span> <span class="cwebmacronumber">2.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">Tangler::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">-&gt;</span><span class="element">text</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">under_section</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\n"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="functiontext">Tags::close_ifdefs</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Tangler::tangle_paragraph is used in <a href="#SP1_1">&#167;1.1</a>, <a href="#SP3_1">&#167;3.1</a>.</p>
<p class="inwebparagraph"><a id="SP2_1"></a><b>&#167;2.1. </b>The tangled file is, as the term suggests, a tangle, with lines coming
from many different origins. Some programming languages (C, for instance)
support a notation to tell the compiler that code has come from somewhere
else; if so, here's where we use it.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Insert line marker if necessary to show the origin of this code</span> <span class="cwebmacronumber">2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">contiguous</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) {</span>
<span class="identifier">contiguous</span><span class="plain"> = </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="functiontext">LanguageMethods::insert_line_marker</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="element">under_section</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP2">&#167;2</a> (twice).</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. The Code Tangler. </b>All of the final tangled code passes through the following routine.
Almost all of the time, it simply prints <code class="display"><span class="extract">original</span></code> verbatim to the file <code class="display"><span class="extract">OUT</span></code>.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Tangler::tangle_code</span><span class="plain">(</span><span class="constant">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">original</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">source_line</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">mlen</span><span class="plain">, </span><span class="identifier">slen</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">mpos</span><span class="plain"> = </span><span class="functiontext">Regexp::find_expansion</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="character">'@'</span><span class="plain">, </span><span class="character">'&lt;'</span><span class="plain">, </span><span class="character">'@'</span><span class="plain">, </span><span class="character">'&gt;'</span><span class="plain">, &amp;</span><span class="identifier">mlen</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">spos</span><span class="plain"> = </span><span class="functiontext">Regexp::find_expansion</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="character">'['</span><span class="plain">, </span><span class="character">'['</span><span class="plain">, </span><span class="character">']'</span><span class="plain">, </span><span class="character">']'</span><span class="plain">, &amp;</span><span class="identifier">slen</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">mpos</span><span class="plain"> &gt;= </span><span class="constant">0</span><span class="plain">) &amp;&amp; ((</span><span class="identifier">spos</span><span class="plain"> == -1) || (</span><span class="identifier">mpos</span><span class="plain"> &lt;= </span><span class="identifier">spos</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">LanguageMethods::allow_expansion</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">original</span><span class="plain">)))</span>
&lt;<span class="cwebmacro">Expand a paragraph macro</span> <span class="cwebmacronumber">3.1</span>&gt;
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">spos</span><span class="plain"> &gt;= </span><span class="constant">0</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Expand a double-square command</span> <span class="cwebmacronumber">3.2</span>&gt;
<span class="reserved">else</span>
<span class="functiontext">LanguageMethods::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">original</span><span class="plain">); </span><span class="comment"> this is usually what happens</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Tangler::tangle_code is used in <a href="#SP2">&#167;2</a>, <a href="#SP3_1">&#167;3.1</a>, <a href="#SP3_2">&#167;3.2</a>, 4/as (<a href="4-as.html#SP3">&#167;3</a>), 4/cl (<a href="4-cl.html#SP4">&#167;4</a>), 4/is (<a href="4-is.html#SP9_1_2_1">&#167;9.1.2.1</a>).</p>
<p class="inwebparagraph"><a id="SP3_1"></a><b>&#167;3.1. </b>The first form of escape is a paragraph macro in the middle of code. For
example, we handle
</p>
<pre class="display">
<span class="plain">if (banana_count == 0) @&lt;Yes, we have no bananas@&gt;;</span>
</pre>
<p class="inwebparagraph">by calling the lower-level tangler on <code class="display"><span class="extract">if (banana_count == 0) </span></code> (a substring
which we know can't involve any macros, since we are detecting macros from
left to right, and this is to the left of the one we found); then by tangling
the definition of "Yes, we have no bananas"; then by calling the upper-level
code tangler on <code class="display"><span class="extract">;</span></code>. (In this case, of course, there's nothing much there,
but in principle it could contain further macros.)
</p>
<p class="inwebparagraph">Note that when we've expanded "Yes, we have no bananas" we have certainly
placed code into the tangled file from a different location; that will insert
a <code class="display"><span class="extract">#line</span></code> marker for the definition location; and we don't want the eventual
C compiler to think that the code which follows is also from that location.
So we insert a fresh line marker.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Expand a paragraph macro</span> <span class="cwebmacronumber">3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">);</span>
<span class="functiontext">Str::copy</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">original</span><span class="plain">); </span><span class="functiontext">Str::truncate</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">mpos</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">temp</span><span class="plain">);</span>
<span class="reserved">programming_language</span><span class="plain"> *</span><span class="identifier">lang</span><span class="plain"> = </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</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">mlen</span><span class="plain">-4; </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="identifier">mpos</span><span class="plain">+2+</span><span class="identifier">i</span><span class="plain">));</span>
<span class="functiontext">Str::truncate</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">mlen</span><span class="plain">-4);</span>
<span class="reserved">para_macro</span><span class="plain"> *</span><span class="identifier">pmac</span><span class="plain"> = </span><span class="functiontext">Macros::find_by_name</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pmac</span><span class="plain">) {</span>
<span class="functiontext">LanguageMethods::before_macro_expansion</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">pmac</span><span class="plain">);</span>
<span class="functiontext">Tangler::tangle_paragraph</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">pmac</span><span class="plain">-&gt;</span><span class="element">defining_paragraph</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::after_macro_expansion</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">pmac</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::insert_line_marker</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</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">"unknown macro"</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="constant">STDERR</span><span class="plain">, </span><span class="string">"Macro is '%S'\n"</span><span class="plain">, </span><span class="identifier">temp</span><span class="plain">);</span>
<span class="functiontext">LanguageMethods::comment</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">lang</span><span class="plain">, </span><span class="identifier">temp</span><span class="plain">); </span><span class="comment"> recover by putting macro name in comment</span>
<span class="plain">}</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">);</span>
<span class="functiontext">Str::substr</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">, </span><span class="functiontext">Str::at</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="identifier">mpos</span><span class="plain"> + </span><span class="identifier">mlen</span><span class="plain">), </span><span class="functiontext">Str::end</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">));</span>
<span class="functiontext">Tangler::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">rest</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3">&#167;3</a>.</p>
<p class="inwebparagraph"><a id="SP3_2"></a><b>&#167;3.2. </b>This is a similar matter, except that it expands bibliographic data:
</p>
<pre class="display">
<span class="plain">printf("This is build [[Build Number]].\n");</span>
</pre>
<p class="inwebparagraph">takes the bibliographic data for "Build Number" (as set on the web's contents
page) and substitutes that, so that we end up with (say)
</p>
<pre class="display">
<span class="identifier">printf</span><span class="plain">(</span><span class="string">"This is build 5Q47.\n"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph">In some languages there are also special expansions (for example, in
InC <code class="display"><span class="extract">[[nonterminals]]</span></code> has a special meaning).
</p>
<p class="inwebparagraph">If the text in double-squares isn't recognised, that's not an error: it simply
passes straight through. So <code class="display"><span class="extract">[[water]]</span></code> becomes just <code class="display"><span class="extract">[[water]]</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Expand a double-square command</span> <span class="cwebmacronumber">3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">web</span><span class="plain"> *</span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">owning_web</span><span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">temp</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">spos</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">));</span>
<span class="functiontext">LanguageMethods::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">temp</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">slen</span><span class="plain">-4; </span><span class="identifier">i</span><span class="plain">++) </span><span class="functiontext">Str::put_at</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">, </span><span class="functiontext">Str::get_at</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="identifier">spos</span><span class="plain">+2+</span><span class="identifier">i</span><span class="plain">));</span>
<span class="functiontext">Str::truncate</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">, </span><span class="identifier">slen</span><span class="plain">-4);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">LanguageMethods::special_tangle_command</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">-&gt;</span><span class="element">sect_language</span><span class="plain">, </span><span class="identifier">temp</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="functiontext">Bibliographic::look_up_datum</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-&gt;</span><span class="element">md</span><span class="plain">, </span><span class="identifier">temp</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="functiontext">Bibliographic::get_datum</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">-&gt;</span><span class="element">md</span><span class="plain">, </span><span class="identifier">temp</span><span class="plain">));</span>
<span class="reserved">else</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[[%S]]"</span><span class="plain">, </span><span class="identifier">temp</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">);</span>
<span class="functiontext">Str::substr</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">, </span><span class="functiontext">Str::at</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">, </span><span class="identifier">spos</span><span class="plain"> + </span><span class="identifier">slen</span><span class="plain">), </span><span class="functiontext">Str::end</span><span class="plain">(</span><span class="identifier">original</span><span class="plain">));</span>
<span class="functiontext">Tangler::tangle_code</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">rest</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">rest</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">temp</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3">&#167;3</a>.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Prinary target. </b>The first target in a web is always the one for the main program.
</p>
<pre class="display">
<span class="reserved">tangle_target</span><span class="plain"> *</span><span class="functiontext">Tangler::primary_target</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="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"no such web"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FIRST_IN_LINKED_LIST</span><span class="plain">(</span><span class="reserved">tangle_target</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">-&gt;</span><span class="element">tangle_targets</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Tangler::primary_target is used in 1/pc (<a href="1-pc.html#SP7_4_2">&#167;7.4.2</a>), 3/ta (<a href="3-ta.html#SP4">&#167;4</a>, <a href="3-ta.html#SP4_1">&#167;4.1</a>), 4/cl (<a href="4-cl.html#SP2">&#167;2</a>, <a href="4-cl.html#SP2_2">&#167;2.2</a>, <a href="4-cl.html#SP5_1">&#167;5.1</a>, <a href="4-cl.html#SP5_4">&#167;5.4</a>), 4/is (<a href="4-is.html#SP3">&#167;3</a>, <a href="4-is.html#SP6">&#167;6</a>, <a href="4-is.html#SP7">&#167;7</a>).</p>
<hr class="tocbar">
<ul class="toc"><li><a href="3-tw.html">Back to 'The Weaver'</a></li><li><i>(This section ends Chapter 3: Outputs.)</i></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>