Jump to content

Execute HQ9+: Difference between revisions

Line 1,172:
 
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====
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.