<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- On produit du texte -->
  <xsl:output method="text" />

  <!-- Règle principale : on affiche l'expression infixe, puis, si
  possible, on calcule la valeur -->
  <xsl:template match="/">
    <xsl:apply-templates />
    <xsl:if test="not(//ci)">
      <xsl:text> = </xsl:text>
      <xsl:apply-templates mode="computation" />
    </xsl:if>
    <xsl:text>&#xa;</xsl:text>
  </xsl:template>

  <!-- Affichage de l'expression infixe -->
  <xsl:template match="apply">
    <xsl:text>(</xsl:text>
    <xsl:apply-templates select="*[2]" />
    <xsl:for-each select="*[position()>2]">
      <xsl:apply-templates select="../*[1]" />
      <xsl:apply-templates select="." />
    </xsl:for-each>
    <xsl:text>)</xsl:text>
  </xsl:template>

  <!-- Calcul de la valeur -->
  <xsl:template match="apply" mode="computation">
    <xsl:call-template name="compute">
      <xsl:with-param name="operator" select="*[1]" />
      <xsl:with-param name="first">
        <xsl:apply-templates select="*[2]" mode="computation" />
      </xsl:with-param>
      <xsl:with-param name="second">
        <xsl:apply-templates select="*[3]" mode="computation" />
      </xsl:with-param>
      <xsl:with-param name="other" select="*[4]" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="plus">+</xsl:template>
  <xsl:template match="minus">-</xsl:template>
  <xsl:template match="power">^</xsl:template>
  <xsl:template match="times">*</xsl:template>
  <xsl:template match="div">/</xsl:template>

  <xsl:template name="compute">
    <xsl:param name="operator" />
    <xsl:param name="first" />
    <xsl:param name="second" />
    <xsl:param name="other" />    <!-- Autres arguments éventuels -->

    <xsl:variable name="result">
      <!-- Opération sur les 2 premiers arguments -->
      <xsl:choose>
        <xsl:when test="$operator/self::plus">
          <xsl:value-of select="$first+$second" />
        </xsl:when>
        <xsl:when test="$operator/self::minus">
          <xsl:value-of select="$first -$second" />
        </xsl:when>
        <xsl:when test="$operator/self::times">
          <xsl:value-of select="$first*$second" />
        </xsl:when>
        <xsl:when test="$operator/self::div">
          <xsl:value-of select="$first div $second" />
        </xsl:when>
        <xsl:when test="$operator/self::power">
          <xsl:call-template name="power">
            <xsl:with-param name="x" select="$first" />
            <xsl:with-param name="n" select="$second" />
          </xsl:call-template>
        </xsl:when>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$other">
        <xsl:call-template name="compute">
          <xsl:with-param name="operator" select="$operator" />
          <xsl:with-param name="first" select="$result" />
          <xsl:with-param name="second">
            <xsl:apply-templates select="$other" mode="computation" />
          </xsl:with-param>
          <xsl:with-param name="other"
            select="$other/following-sibling::*[1]" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$result" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Template nommée calculant x^n -->
  <xsl:template name="power">
    <xsl:param name="x" />
    <xsl:param name="n" />

    <xsl:choose>
      <xsl:when test="$n=0">1</xsl:when>
      <xsl:otherwise>
        <xsl:variable name="result">
          <xsl:call-template name="power">
            <xsl:with-param name="x" select="$x" />
            <xsl:with-param name="n" select="$n - 1" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="$result*$x" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

