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! </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,' ')"/> |
|||
<!-- 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==== |