Execute HQ9+: Difference between revisions

Content added Content deleted
Line 1,172: Line 1,172:


Characters other than <code>HQhq9+</code> are no-ops, but are echoed verbatim by <code>Q</code>/<code>q</code>.
Characters other than <code>HQhq9+</code> are no-ops, but are echoed verbatim by <code>Q</code>/<code>q</code>.

====Implementation supporting multiple programs and accumulator output====

Requires <code>bottles.xsl</code> (below)

<lang xml><?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- bottles.xsl defines $entire-bottles-song -->
<xsl:import href="bottles.xsl"/>

<xsl:output method="xml" encoding="utf-8"/>

<xsl:variable name="hello-world">
<xsl:text>Hello, world!&#10;</xsl:text>
</xsl:variable>

<!-- Main template -->
<xsl:template match="/">
<results>
<xsl:apply-templates select="//code"/>
</results>
</xsl:template>

<!-- <code/> template -->
<xsl:template match="code">
<xsl:call-template name="run">
<xsl:with-param name="code" select="string(.)"/>
</xsl:call-template>
</xsl:template>

<!-- Runs HQ9+ code from string -->
<xsl:template name="run">
<xsl:param name="code"/>

<xsl:call-template name="_run-remaining-code">
<!-- Initial value is the entire input program plus a newline -->
<xsl:with-param name="quine" select="concat($code,'&#10;')"/>

<!-- Initial value is the entire input program with [hq] changed to upper-case -->
<xsl:with-param name="code" select="translate($code, 'hq', 'HQ')"/>

<!-- Initial value is empty -->
<xsl:with-param name="output"/>

<!-- Initial value is 0 -->
<xsl:with-param name="accumulator" select="0"/>
</xsl:call-template>
</xsl:template>

<!-- Runs the remainder of some already-started HQ9+ code -->
<!-- Tail recursion allows this function to effectively update its own state -->
<xsl:template name="_run-remaining-code">
<!-- The text to be output on 'Q' -->
<xsl:param name="quine"/>
<!-- The remaining instructions for the program, already upper-case -->
<xsl:param name="code"/>
<!-- Output that has already been collected -->
<xsl:param name="output"/>
<!-- Current accumulator value -->
<xsl:param name="accumulator"/>

<!--
If there are instructions remaining, runs the next instruction and then recurses.
If there are no instructions left, produces the final output and accumulator before exiting.
-->
<xsl:choose>
<xsl:when test="$code = ''">
<!-- Reached the end of the program; output results -->
<result>
<xsl:if test="$accumulator != 0">
<xsl:attribute name="accumulator"><xsl:value-of select="$accumulator"/></xsl:attribute>
</xsl:if>
<xsl:copy-of select="$output"/>
</result>
</xsl:when>
<xsl:otherwise>
<!-- At least one more instruction; run and recurse -->
<xsl:variable name="inst" select="substring($code, 1, 1)"/>
<xsl:variable name="remaining" select="substring($code, 2)"/>

<!-- Decide what to add to accumulator -->
<xsl:variable name="accumulator-inc">
<xsl:choose>
<xsl:when test="$inst = '+'">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<!-- Decide what to append to output -->
<xsl:variable name="output-inc">
<xsl:choose>
<xsl:when test="$inst = 'H'"><xsl:value-of select="$hello-world"/></xsl:when>
<xsl:when test="$inst = 'Q'"><xsl:value-of select="$quine"/></xsl:when>
<xsl:when test="$inst = '9'"><xsl:value-of select="$entire-bottles-song"/></xsl:when>
</xsl:choose>
</xsl:variable>

<!-- Recurse to continue processing program -->
<xsl:call-template name="_run-remaining-code">
<!-- $quine is the $quine originally passed without changes -->
<xsl:with-param name="quine" select="$quine"/>
<!-- $code is the $code from this invocation with the first character removed -->
<xsl:with-param name="code" select="$remaining"/>
<!-- $output is the $output from this invocation with $output-inc appended -->
<xsl:with-param name="output">
<xsl:copy-of select="$output"/>
<xsl:copy-of select="$output-inc"/>
</xsl:with-param>
<!-- $accumulator is the $accumulator from this invocation with $accumulator-inc added -->
<xsl:with-param name="accumulator" select="$accumulator + $accumulator-inc"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet></lang>

=====Details=====

This sheet demonstrates the use of a tail-recursive template to simulate a narrowly mutable state, which is used for both the output and the accumulator.

Input to this sheet is given by placing one or more sources as <code><nowiki><code/></nowiki></code> elements. For example, to run the example program <code>qqqq</code>, use the sheet to transform the document

<lang xml><code>qqqq</code></lang>

or the programs <code>qqqq</code> and <code>++++</code> can be run in the same pass by transforming

<lang xml><programs>
<code>qqqq</code>
<code>++++</code>
</programs></lang>

The output document is a <code><nowiki><results/></nowiki></code> element containing a <code><nowiki><result/></nowiki></code> element for each <code><nowiki><code/></nowiki></code> element processed from the input. If a <code>+</code> appeared in the program, the <code><nowiki><result/></nowiki></code> element will indicate the final value of the accumulator in its <code>accumulator</code> attribute. For example, the output for the latter example, would be

<lang xml><results><result>qqqq
qqqq
qqqq
qqqq
</result><result accumulator="4"/></results></lang>


====bottles.xsl====
====bottles.xsl====