]> git.saurik.com Git - bison.git/blobdiff - data/xslt/xml2dot.xsl
xml: match DOT output and xml2dot.xsl processing
[bison.git] / data / xslt / xml2dot.xsl
index 416ee13e038d0b44992b590566bfaaaac9b69251..dceb8e1eebd3086b5d3293be5a5a568d2be2872e 100644 (file)
@@ -2,9 +2,8 @@
 
 <!--
     xml2dot.xsl - transform Bison XML Report into DOT.
-    $Id$
 
-    Copyright (C) 2007 Free Software Foundation, Inc.
+    Copyright (C) 2007-2012 Free Software Foundation, Inc.
 
     This file is part of Bison, the GNU Compiler Compiler.
 
   -->
 
 <xsl:stylesheet version="1.0"
-  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-  
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:bison="http://www.gnu.org/software/bison/">
+
+<xsl:import href="bison.xsl"/>
 <xsl:output method="text" encoding="UTF-8" indent="no"/>
 
 <xsl:template match="/">
 </xsl:template>
 
 <xsl:template match="bison-xml-report">
-  <xsl:apply-templates select="automaton"/>
+  <xsl:text>// Generated by GNU Bison </xsl:text>
+  <xsl:value-of select="@version"/>
+  <xsl:text>.&#10;</xsl:text>
+  <xsl:text>// Report bugs to &lt;</xsl:text>
+  <xsl:value-of select="@bug-report"/>
+  <xsl:text>&gt;.&#10;</xsl:text>
+  <xsl:text>// Home page: &lt;</xsl:text>
+  <xsl:value-of select="@url"/>
+  <xsl:text>&gt;.&#10;&#10;</xsl:text>
+  <xsl:apply-templates select="automaton">
+    <xsl:with-param name="filename" select="filename"/>
+  </xsl:apply-templates>
 </xsl:template>
 
 <xsl:template match="automaton">
-  <xsl:text>digraph Automaton {&#10;</xsl:text>
+  <xsl:param name="filename"/>
+  <xsl:text>digraph "</xsl:text>
+  <xsl:call-template name="escape">
+    <xsl:with-param name="subject" select="$filename"/>
+  </xsl:call-template>
+  <xsl:text>"&#10;{
+  node [fontname = courier, shape = box, colorscheme = paired6]
+  edge [fontname = courier]
+
+</xsl:text>
   <xsl:apply-templates select="state"/>
   <xsl:text>}&#10;</xsl:text>
 </xsl:template>
   <xsl:call-template name="output-node">
     <xsl:with-param name="number" select="@number"/>
     <xsl:with-param name="label">
-      <xsl:value-of select="@number"/>
-      <xsl:apply-templates select="itemset/rule"/>
+      <xsl:apply-templates select="itemset/item"/>
     </xsl:with-param>
   </xsl:call-template>
   <xsl:apply-templates select="actions/transitions"/>
+  <xsl:apply-templates select="actions/reductions">
+    <xsl:with-param name="staten">
+      <xsl:value-of select="@number"/>
+    </xsl:with-param>
+  </xsl:apply-templates>
+</xsl:template>
+
+<xsl:template match="actions/reductions">
+  <xsl:param name="staten"/>
+  <xsl:for-each select='reduction'>
+    <!-- These variables are needed because the current context can't be
+         refered to directly in XPath expressions. -->
+    <xsl:variable name="rul">
+      <xsl:value-of select="@rule"/>
+    </xsl:variable>
+    <xsl:variable name="ena">
+      <xsl:value-of select="@enabled"/>
+    </xsl:variable>
+    <!-- The foreach's body is protected by this, so that we are actually
+         going to iterate once per reduction rule, and not per lookahead. -->
+    <xsl:if test='not(preceding-sibling::*[@rule=$rul and @enabled=$ena])'>
+      <xsl:variable name="rule">
+        <xsl:choose>
+          <!-- The acceptation state is refered to as 'accept' in the XML, but
+               just as '0' in the DOT. -->
+          <xsl:when test="@rule='accept'">
+            <xsl:text>0</xsl:text>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="@rule"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <!-- The edge's beginning -->
+      <xsl:call-template name="reduction-edge-start">
+        <xsl:with-param name="state" select="$staten"/>
+        <xsl:with-param name="rule" select="$rule"/>
+        <xsl:with-param name="enabled" select="@enabled"/>
+      </xsl:call-template>
+
+      <!-- The edge's tokens -->
+      <!-- Don't show labels for the default action. In other cases, there will
+           always be at least one token, so 'label="[]"' will not occur. -->
+      <xsl:if test='$rule!=0 and not(../reduction[@enabled=$ena and @rule=$rule and @symbol="$default"])'>
+        <xsl:text>label="[</xsl:text>
+        <xsl:for-each select='../reduction[@enabled=$ena and @rule=$rule]'>
+          <xsl:call-template name="escape">
+            <xsl:with-param name="subject" select="@symbol"/>
+          </xsl:call-template>
+          <xsl:if test="position() != last ()">
+            <xsl:text>, </xsl:text>
+          </xsl:if>
+        </xsl:for-each>
+        <xsl:text>]", </xsl:text>
+      </xsl:if>
+
+      <!-- The edge's end -->
+      <xsl:text>style=solid]&#10;</xsl:text>
+
+      <!-- The diamond representing the reduction -->
+      <xsl:call-template name="reduction-node">
+        <xsl:with-param name="state" select="$staten"/>
+        <xsl:with-param name="rule" select="$rule"/>
+        <xsl:with-param name="color">
+          <xsl:choose>
+            <xsl:when test='@enabled="true"'>
+              <xsl:text>3</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:text>5</xsl:text>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:for-each>
 </xsl:template>
 
 <xsl:template match="actions/transitions">
   <xsl:apply-templates select="transition"/>
 </xsl:template>
 
+<xsl:template match="item">
+  <xsl:param name="prev-rule-number"
+    select="preceding-sibling::item[1]/@rule-number"/>
+  <xsl:apply-templates select="key('bison:ruleByNumber', @rule-number)">
+    <xsl:with-param name="point" select="@point"/>
+    <xsl:with-param name="num" select="@rule-number"/>
+    <xsl:with-param name="prev-lhs"
+      select="key('bison:ruleByNumber', $prev-rule-number)/lhs[text()]"
+   />
+  </xsl:apply-templates>
+  <xsl:apply-templates select="lookaheads"/>
+</xsl:template>
+
 <xsl:template match="rule">
+  <xsl:param name="point"/>
+  <xsl:param name="num"/>
+  <xsl:param name="prev-lhs"/>
   <xsl:text>&#10;</xsl:text>
-  <xsl:value-of select="lhs"/>
-  <xsl:text> -&gt;</xsl:text>
-  <xsl:apply-templates select="rhs/symbol|rhs/point|rhs/empty"/>
-  <xsl:apply-templates select="lookaheads"/>
+  <xsl:choose>
+    <xsl:when test="$num &lt; 10">
+      <xsl:text>  </xsl:text>
+    </xsl:when>
+    <xsl:when test="$num &lt; 100">
+      <xsl:text> </xsl:text>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:text></xsl:text>
+    </xsl:otherwise>
+  </xsl:choose>
+  <xsl:value-of select="$num"/>
+  <xsl:text> </xsl:text>
+  <xsl:choose>
+  <xsl:when test="$prev-lhs = lhs[text()]">
+      <xsl:call-template name="lpad">
+        <xsl:with-param name="str" select="'|'"/>
+        <xsl:with-param name="pad" select="number(string-length(lhs[text()])) + 1"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="lhs"/>
+      <xsl:text>:</xsl:text>
+    </xsl:otherwise>
+  </xsl:choose>
+  <xsl:if test="$point = 0">
+    <xsl:text> .</xsl:text>
+  </xsl:if>
+  <xsl:for-each select="rhs/symbol|rhs/empty">
+    <xsl:apply-templates select="."/>
+    <xsl:if test="$point = position()">
+      <xsl:text> .</xsl:text>
+    </xsl:if>
+  </xsl:for-each>
 </xsl:template>
 
 <xsl:template match="symbol">
   <xsl:value-of select="."/>
 </xsl:template>
 
-<xsl:template match="point">
-  <xsl:text> .</xsl:text>
-</xsl:template>
-
-<xsl:template match="empty">
-  <xsl:text> /* empty */</xsl:text>
-</xsl:template>
+<xsl:template match="empty"/>
 
 <xsl:template match="lookaheads">
-  <xsl:text>[</xsl:text>
+  <xsl:text>  [</xsl:text>
   <xsl:apply-templates select="symbol"/>
   <xsl:text>]</xsl:text>
 </xsl:template>
   </xsl:if>
 </xsl:template>
 
+<xsl:template name="reduction-edge-start">
+  <xsl:param name="state"/>
+  <xsl:param name="rule"/>
+  <xsl:param name="enabled"/>
+
+  <xsl:text>  </xsl:text>
+  <xsl:value-of select="$state"/>
+  <xsl:text> -> "</xsl:text>
+  <xsl:value-of select="$state"/>
+  <xsl:text>R</xsl:text>
+  <xsl:value-of select="$rule"/>
+  <xsl:if test='$enabled = "false"'>
+    <xsl:text>d</xsl:text>
+  </xsl:if>
+  <xsl:text>" [</xsl:text>
+</xsl:template>
+
+<xsl:template name="reduction-node">
+  <xsl:param name="state"/>
+  <xsl:param name="rule"/>
+  <xsl:param name="color"/>
+
+  <xsl:text> "</xsl:text>
+  <xsl:value-of select="$state"/>
+  <xsl:text>R</xsl:text>
+  <xsl:value-of select="$rule"/>
+  <xsl:if test="$color = 5">
+    <xsl:text>d</xsl:text>
+  </xsl:if>
+  <xsl:text>" [label="</xsl:text>
+  <xsl:choose>
+  <xsl:when test="$rule = 0">
+    <xsl:text>Acc", fillcolor=1</xsl:text>
+  </xsl:when>
+  <xsl:otherwise>
+    <xsl:text>R</xsl:text>
+    <xsl:value-of select="$rule"/>
+    <xsl:text>", fillcolor=</xsl:text>
+    <xsl:value-of select="$color"/>
+  </xsl:otherwise>
+  </xsl:choose>
+  <xsl:text>, shape=diamond, style=filled]&#10;</xsl:text>
+</xsl:template>
+
 <xsl:template match="transition">
   <xsl:call-template name="output-edge">
     <xsl:with-param name="src" select="../../../@number"/>
   <xsl:text>  </xsl:text>
   <xsl:value-of select="$number"/>
   <xsl:text> [label="</xsl:text>
+  <xsl:text>State </xsl:text>
+  <xsl:value-of select="$number"/>
+  <xsl:text>\n</xsl:text>
   <xsl:call-template name="escape">
     <xsl:with-param name="subject" select="$label"/>
   </xsl:call-template>
-  <xsl:text>"]&#10;</xsl:text>
+  <xsl:text>\l"]&#10;</xsl:text>
 </xsl:template>
 
 <xsl:template name="output-edge">
 </xsl:template>
 
 <xsl:template name="escape">
-  <xsl:param name="subject" required="yes"/>
+  <xsl:param name="subject"/> <!-- required -->
   <xsl:call-template name="string-replace">
     <xsl:with-param name="subject">
       <xsl:call-template name="string-replace">
       </xsl:call-template>
     </xsl:with-param>
     <xsl:with-param name="search" select="'&#10;'"/>
-    <xsl:with-param name="replace" select="'\n'"/>
+    <xsl:with-param name="replace" select="'\l'"/>
   </xsl:call-template>
 </xsl:template>
 
         <xsl:with-param name="search" select="$search"/>
         <xsl:with-param name="replace" select="$replace"/>
       </xsl:call-template>
-    </xsl:when> 
+    </xsl:when>
     <xsl:otherwise>
-      <xsl:value-of select="$subject"/>  
+      <xsl:value-of select="$subject"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template name="lpad">
+  <xsl:param name="str" select="''"/>
+  <xsl:param name="pad" select="0"/>
+  <xsl:variable name="diff" select="$pad - string-length($str)" />
+  <xsl:choose>
+    <xsl:when test="$diff &lt; 0">
+      <xsl:value-of select="$str"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:call-template name="space">
+        <xsl:with-param name="repeat" select="$diff"/>
+      </xsl:call-template>
+      <xsl:value-of select="$str"/>
     </xsl:otherwise>
-  </xsl:choose>            
+  </xsl:choose>
 </xsl:template>
 
 </xsl:stylesheet>