xref: /aosp_15_r20/prebuilts/build-tools/common/bison/xslt/xml2dot.xsl (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1<?xml version="1.0" encoding="UTF-8"?>
2
3<!--
4    xml2dot.xsl - transform Bison XML Report into DOT.
5
6    Copyright (C) 2007-2015, 2018-2021 Free Software Foundation, Inc.
7
8    This file is part of Bison, the GNU Compiler Compiler.
9
10    This program is free software: you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation, either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <https://www.gnu.org/licenses/>.
22
23    Written by Wojciech Polak <[email protected]>.
24  -->
25
26<xsl:stylesheet version="1.0"
27  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
28  xmlns:bison="https://www.gnu.org/software/bison/">
29
30<xsl:import href="bison.xsl"/>
31<xsl:output method="text" encoding="UTF-8" indent="no"/>
32
33<xsl:template match="/">
34  <xsl:apply-templates select="bison-xml-report"/>
35</xsl:template>
36
37<xsl:template match="bison-xml-report">
38  <xsl:text>// Generated by GNU Bison </xsl:text>
39  <xsl:value-of select="@version"/>
40  <xsl:text>.&#10;</xsl:text>
41  <xsl:text>// Report bugs to &lt;</xsl:text>
42  <xsl:value-of select="@bug-report"/>
43  <xsl:text>&gt;.&#10;</xsl:text>
44  <xsl:text>// Home page: &lt;</xsl:text>
45  <xsl:value-of select="@url"/>
46  <xsl:text>&gt;.&#10;&#10;</xsl:text>
47  <xsl:apply-templates select="automaton">
48    <xsl:with-param name="filename" select="filename"/>
49  </xsl:apply-templates>
50</xsl:template>
51
52<xsl:template match="automaton">
53  <xsl:param name="filename"/>
54  <xsl:text>digraph "</xsl:text>
55  <xsl:call-template name="escape">
56    <xsl:with-param name="subject" select="$filename"/>
57  </xsl:call-template>
58  <xsl:text>"&#10;{
59  node [fontname = courier, shape = box, colorscheme = paired6]
60  edge [fontname = courier]
61
62</xsl:text>
63  <xsl:apply-templates select="state"/>
64  <xsl:text>}&#10;</xsl:text>
65</xsl:template>
66
67<xsl:template match="automaton/state">
68  <xsl:call-template name="output-node">
69    <xsl:with-param name="number" select="@number"/>
70    <xsl:with-param name="label">
71      <xsl:apply-templates select="itemset/item"/>
72    </xsl:with-param>
73  </xsl:call-template>
74  <xsl:apply-templates select="actions/transitions"/>
75  <xsl:apply-templates select="actions/reductions">
76    <xsl:with-param name="staten">
77      <xsl:value-of select="@number"/>
78    </xsl:with-param>
79  </xsl:apply-templates>
80</xsl:template>
81
82<xsl:template match="actions/reductions">
83  <xsl:param name="staten"/>
84  <xsl:for-each select='reduction'>
85    <!-- These variables are needed because the current context can't be
86         referred to directly in XPath expressions. -->
87    <xsl:variable name="rul">
88      <xsl:value-of select="@rule"/>
89    </xsl:variable>
90    <xsl:variable name="ena">
91      <xsl:value-of select="@enabled"/>
92    </xsl:variable>
93    <!-- The foreach's body is protected by this, so that we are actually
94         going to iterate once per reduction rule, and not per lookahead. -->
95    <xsl:if test='not(preceding-sibling::*[@rule=$rul and @enabled=$ena])'>
96      <xsl:variable name="rule">
97        <xsl:choose>
98          <!-- The acceptation state is referred to as 'accept' in the XML, but
99               just as '0' in the DOT. -->
100          <xsl:when test="@rule='accept'">
101            <xsl:text>0</xsl:text>
102          </xsl:when>
103          <xsl:otherwise>
104            <xsl:value-of select="@rule"/>
105          </xsl:otherwise>
106        </xsl:choose>
107      </xsl:variable>
108
109      <!-- The edge's beginning -->
110      <xsl:call-template name="reduction-edge-start">
111        <xsl:with-param name="state" select="$staten"/>
112        <xsl:with-param name="rule" select="$rule"/>
113        <xsl:with-param name="enabled" select="@enabled"/>
114      </xsl:call-template>
115
116      <!-- The edge's tokens -->
117      <!-- Don't show labels for the default action. In other cases, there will
118           always be at least one token, so 'label="[]"' will not occur. -->
119      <xsl:if test='$rule!=0 and not(../reduction[@enabled=$ena and @rule=$rule and @symbol="$default"])'>
120        <xsl:text>label="[</xsl:text>
121        <xsl:for-each select='../reduction[@enabled=$ena and @rule=$rule]'>
122          <xsl:call-template name="escape">
123            <xsl:with-param name="subject" select="@symbol"/>
124          </xsl:call-template>
125          <xsl:if test="position() != last ()">
126            <xsl:text>, </xsl:text>
127          </xsl:if>
128        </xsl:for-each>
129        <xsl:text>]", </xsl:text>
130      </xsl:if>
131
132      <!-- The edge's end -->
133      <xsl:text>style=solid]&#10;</xsl:text>
134
135      <!-- The diamond representing the reduction -->
136      <xsl:call-template name="reduction-node">
137        <xsl:with-param name="state" select="$staten"/>
138        <xsl:with-param name="rule" select="$rule"/>
139        <xsl:with-param name="color">
140          <xsl:choose>
141            <xsl:when test='@enabled="true"'>
142              <xsl:text>3</xsl:text>
143            </xsl:when>
144            <xsl:otherwise>
145              <xsl:text>5</xsl:text>
146            </xsl:otherwise>
147          </xsl:choose>
148        </xsl:with-param>
149      </xsl:call-template>
150    </xsl:if>
151  </xsl:for-each>
152</xsl:template>
153
154<xsl:template match="actions/transitions">
155  <xsl:apply-templates select="transition"/>
156</xsl:template>
157
158<xsl:template match="item">
159  <xsl:param name="prev-rule-number"
160    select="preceding-sibling::item[1]/@rule-number"/>
161  <xsl:apply-templates select="key('bison:ruleByNumber', @rule-number)">
162    <xsl:with-param name="dot" select="@dot"/>
163    <xsl:with-param name="num" select="@rule-number"/>
164    <xsl:with-param name="prev-lhs"
165      select="key('bison:ruleByNumber', $prev-rule-number)/lhs[text()]"
166   />
167  </xsl:apply-templates>
168  <xsl:apply-templates select="lookaheads"/>
169</xsl:template>
170
171<xsl:template match="rule">
172  <xsl:param name="dot"/>
173  <xsl:param name="num"/>
174  <xsl:param name="prev-lhs"/>
175  <xsl:text>&#10;</xsl:text>
176  <xsl:choose>
177    <xsl:when test="$num &lt; 10">
178      <xsl:text>  </xsl:text>
179    </xsl:when>
180    <xsl:when test="$num &lt; 100">
181      <xsl:text> </xsl:text>
182    </xsl:when>
183    <xsl:otherwise>
184      <xsl:text></xsl:text>
185    </xsl:otherwise>
186  </xsl:choose>
187  <xsl:value-of select="$num"/>
188  <xsl:text> </xsl:text>
189  <xsl:choose>
190  <xsl:when test="$prev-lhs = lhs[text()]">
191      <xsl:call-template name="lpad">
192        <xsl:with-param name="str" select="'|'"/>
193        <xsl:with-param name="pad" select="number(string-length(lhs[text()])) + 1"/>
194      </xsl:call-template>
195    </xsl:when>
196    <xsl:otherwise>
197      <xsl:value-of select="lhs"/>
198      <xsl:text>:</xsl:text>
199    </xsl:otherwise>
200  </xsl:choose>
201  <xsl:if test="$dot = 0">
202    <xsl:text> .</xsl:text>
203  </xsl:if>
204
205  <!-- RHS -->
206  <xsl:for-each select="rhs/symbol|rhs/empty">
207    <xsl:apply-templates select="."/>
208    <xsl:if test="$dot = position()">
209      <xsl:text> .</xsl:text>
210    </xsl:if>
211  </xsl:for-each>
212</xsl:template>
213
214<xsl:template match="symbol">
215  <xsl:text> </xsl:text>
216  <xsl:value-of select="."/>
217</xsl:template>
218
219<xsl:template match="empty">
220  <xsl:text> %empty</xsl:text>
221</xsl:template>
222
223<xsl:template match="lookaheads">
224  <xsl:text>  [</xsl:text>
225  <xsl:apply-templates select="symbol"/>
226  <xsl:text>]</xsl:text>
227</xsl:template>
228
229<xsl:template match="lookaheads/symbol">
230  <xsl:value-of select="."/>
231  <xsl:if test="position() != last()">
232    <xsl:text>, </xsl:text>
233  </xsl:if>
234</xsl:template>
235
236<xsl:template name="reduction-edge-start">
237  <xsl:param name="state"/>
238  <xsl:param name="rule"/>
239  <xsl:param name="enabled"/>
240
241  <xsl:text>  </xsl:text>
242  <xsl:value-of select="$state"/>
243  <xsl:text> -> "</xsl:text>
244  <xsl:value-of select="$state"/>
245  <xsl:text>R</xsl:text>
246  <xsl:value-of select="$rule"/>
247  <xsl:if test='$enabled = "false"'>
248    <xsl:text>d</xsl:text>
249  </xsl:if>
250  <xsl:text>" [</xsl:text>
251</xsl:template>
252
253<xsl:template name="reduction-node">
254  <xsl:param name="state"/>
255  <xsl:param name="rule"/>
256  <xsl:param name="color"/>
257
258  <xsl:text> "</xsl:text>
259  <xsl:value-of select="$state"/>
260  <xsl:text>R</xsl:text>
261  <xsl:value-of select="$rule"/>
262  <xsl:if test="$color = 5">
263    <xsl:text>d</xsl:text>
264  </xsl:if>
265  <xsl:text>" [label="</xsl:text>
266  <xsl:choose>
267  <xsl:when test="$rule = 0">
268    <xsl:text>Acc", fillcolor=1</xsl:text>
269  </xsl:when>
270  <xsl:otherwise>
271    <xsl:text>R</xsl:text>
272    <xsl:value-of select="$rule"/>
273    <xsl:text>", fillcolor=</xsl:text>
274    <xsl:value-of select="$color"/>
275  </xsl:otherwise>
276  </xsl:choose>
277  <xsl:text>, shape=diamond, style=filled]&#10;</xsl:text>
278</xsl:template>
279
280<xsl:template match="transition">
281  <xsl:call-template name="output-edge">
282    <xsl:with-param name="src" select="../../../@number"/>
283    <xsl:with-param name="dst" select="@state"/>
284    <xsl:with-param name="style">
285      <xsl:choose>
286        <xsl:when test="@symbol = 'error'">
287          <xsl:text>dotted</xsl:text>
288        </xsl:when>
289        <xsl:when test="@type = 'shift'">
290          <xsl:text>solid</xsl:text>
291        </xsl:when>
292        <xsl:otherwise>
293          <xsl:text>dashed</xsl:text>
294        </xsl:otherwise>
295      </xsl:choose>
296    </xsl:with-param>
297    <xsl:with-param name="label">
298      <xsl:if test="not(@symbol = 'error')">
299        <xsl:value-of select="@symbol"/>
300      </xsl:if>
301    </xsl:with-param>
302  </xsl:call-template>
303</xsl:template>
304
305<xsl:template name="output-node">
306  <xsl:param name="number"/>
307  <xsl:param name="label"/>
308  <xsl:text>  </xsl:text>
309  <xsl:value-of select="$number"/>
310  <xsl:text> [label="</xsl:text>
311  <xsl:text>State </xsl:text>
312  <xsl:value-of select="$number"/>
313  <xsl:text>\n</xsl:text>
314  <xsl:call-template name="escape">
315    <xsl:with-param name="subject" select="$label"/>
316  </xsl:call-template>
317  <xsl:text>\l"]&#10;</xsl:text>
318</xsl:template>
319
320<xsl:template name="output-edge">
321  <xsl:param name="src"/>
322  <xsl:param name="dst"/>
323  <xsl:param name="style"/>
324  <xsl:param name="label"/>
325  <xsl:text>  </xsl:text>
326  <xsl:value-of select="$src"/>
327  <xsl:text> -> </xsl:text>
328  <xsl:value-of select="$dst"/>
329  <xsl:text> [style=</xsl:text>
330  <xsl:value-of select="$style"/>
331  <xsl:if test="$label and $label != ''">
332    <xsl:text> label="</xsl:text>
333    <xsl:call-template name="escape">
334      <xsl:with-param name="subject" select="$label"/>
335    </xsl:call-template>
336    <xsl:text>"</xsl:text>
337  </xsl:if>
338  <xsl:text>]&#10;</xsl:text>
339</xsl:template>
340
341<xsl:template name="escape">
342  <xsl:param name="subject"/> <!-- required -->
343  <xsl:call-template name="string-replace">
344    <xsl:with-param name="subject">
345      <xsl:call-template name="string-replace">
346        <xsl:with-param name="subject">
347          <xsl:call-template name="string-replace">
348            <xsl:with-param name="subject" select="$subject"/>
349            <xsl:with-param name="search" select="'\'"/>
350            <xsl:with-param name="replace" select="'\\'"/>
351          </xsl:call-template>
352        </xsl:with-param>
353        <xsl:with-param name="search" select="'&quot;'"/>
354        <xsl:with-param name="replace" select="'\&quot;'"/>
355      </xsl:call-template>
356    </xsl:with-param>
357    <xsl:with-param name="search" select="'&#10;'"/>
358    <xsl:with-param name="replace" select="'\l'"/>
359  </xsl:call-template>
360</xsl:template>
361
362<xsl:template name="string-replace">
363  <xsl:param name="subject"/>
364  <xsl:param name="search"/>
365  <xsl:param name="replace"/>
366  <xsl:choose>
367    <xsl:when test="contains($subject, $search)">
368      <xsl:variable name="before" select="substring-before($subject, $search)"/>
369      <xsl:variable name="after" select="substring-after($subject, $search)"/>
370      <xsl:value-of select="$before"/>
371      <xsl:value-of select="$replace"/>
372      <xsl:call-template name="string-replace">
373        <xsl:with-param name="subject" select="$after"/>
374        <xsl:with-param name="search" select="$search"/>
375        <xsl:with-param name="replace" select="$replace"/>
376      </xsl:call-template>
377    </xsl:when>
378    <xsl:otherwise>
379      <xsl:value-of select="$subject"/>
380    </xsl:otherwise>
381  </xsl:choose>
382</xsl:template>
383
384<xsl:template name="lpad">
385  <xsl:param name="str" select="''"/>
386  <xsl:param name="pad" select="0"/>
387  <xsl:variable name="diff" select="$pad - string-length($str)" />
388  <xsl:choose>
389    <xsl:when test="$diff &lt; 0">
390      <xsl:value-of select="$str"/>
391    </xsl:when>
392    <xsl:otherwise>
393      <xsl:call-template name="space">
394        <xsl:with-param name="repeat" select="$diff"/>
395      </xsl:call-template>
396      <xsl:value-of select="$str"/>
397    </xsl:otherwise>
398  </xsl:choose>
399</xsl:template>
400
401</xsl:stylesheet>
402