Project

Profile

Help

Bug #3920 ยป x.xslt

Gunther Rademacher, 2018-09-27 22:32

 
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file was generated on Thu Sep 27, 2018 22:26 (UTC+02) by REx v5.48 which is Copyright (c) 1979-2018 by Gunther Rademacher <grd@gmx.net> -->
<!-- REx command line: -xslt -main -trace x.ebnf -glr 1 -tree -->

<xsl:stylesheet version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="x">
<!--~
! The index of the lexer state for accessing the combined
! (i.e. level > 1) lookahead code.
-->
<xsl:variable name="p:lk" as="xs:integer" select="1"/>

<!--~
! The index of the lexer state for accessing the position in the
! input string of the begin of the token that has been consumed.
-->
<xsl:variable name="p:b0" as="xs:integer" select="2"/>

<!--~
! The index of the lexer state for accessing the position in the
! input string of the end of the token that has been consumed.
-->
<xsl:variable name="p:e0" as="xs:integer" select="3"/>

<!--~
! The index of the lexer state for accessing the code of the
! level-1-lookahead token.
-->
<xsl:variable name="p:l1" as="xs:integer" select="4"/>

<!--~
! The index of the lexer state for accessing the position in the
! input string of the begin of the level-1-lookahead token.
-->
<xsl:variable name="p:b1" as="xs:integer" select="5"/>

<!--~
! The index of the lexer state for accessing the position in the
! input string of the end of the level-1-lookahead token.
-->
<xsl:variable name="p:e1" as="xs:integer" select="6"/>

<!--~
! The index of the lexer state for accessing the token code that
! was expected when an error was found.
-->
<xsl:variable name="p:error" as="xs:integer" select="7"/>

<!--~
! The index of the lexer state that points to the first entry
! used for collecting action results.
-->
<xsl:variable name="p:result" as="xs:integer" select="8"/>

<!--~
! The codepoint to charclass mapping for 7 bit codepoints.
-->
<xsl:variable name="p:MAP0" as="xs:integer+" select="
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
"/>

<!--~
! The codepoint to charclass mapping for codepoints below the surrogate block.
-->
<xsl:variable name="p:MAP1" as="xs:integer+" select="
54, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 90, 90, 90, 98, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0
"/>

<!--~
! The token-set-id to DFA-initial-state mapping.
-->
<xsl:variable name="p:INITIAL" as="xs:integer+" select="
4, 1
"/>

<!--~
! The DFA transition table.
-->
<xsl:variable name="p:TRANSITION" as="xs:integer+" select="
0, 0, 6, 0
"/>

<!--~
! The DFA-state to expected-token-set mapping.
-->
<xsl:variable name="p:EXPECTED" as="xs:integer+" select="
4
"/>

<!--~
! The match-code to case-id map. Maps decision point and lookahead to next action code.
-->
<xsl:variable name="p:CASEID" as="xs:integer+" select="
12, 10, 10, 10, 8, 10, 10, 10, 0, 14, 0, 0, 0, 0, 82, 0
"/>

<!--~
! The parser tokenset table. Maps state to lookahead tokenset code.
-->
<xsl:variable name="p:TOKENSET" as="xs:integer+" select="
1, 0
"/>

<!--~
! The conflict action list table. Contains list of conflicting actions.
-->
<xsl:variable name="p:APPENDIX" as="xs:integer+" select="
42, 74
"/>

<!--~
! The parser goto table. Maps state and nonterminal to next action code.
-->
<xsl:variable name="p:GOTO" as="xs:integer+" select="
6, 4, 4, 0, 0, 0, 0, 0
"/>

<!--~
! The token-string table.
-->
<xsl:variable name="p:TOKEN" as="xs:string+" select="
'(0)',
'END',
&quot;'x'&quot;
"/>

<!--~
! The nonterminal name table.
-->
<xsl:variable name="p:NONTERMINAL" as="xs:string+" select="
'X',
'A',
'B'
"/>

<!--~
! Pass a line to fn:trace, without generating a result. Actually,
! create an empty result, but make it somehow dependent on trace,
! so the optimizer does not eliminate the trace call.
!
! @param $line the line to be traced.
! @return the empty sequence.
-->
<xsl:function name="p:trace" as="empty-sequence()">
<xsl:param name="line" as="xs:string"/>

<xsl:sequence select="if (trace($line, 'trace')) then () else ''[.]"/>
</xsl:function>

<!--~
! Add escaping to a string for being placed in XML attribute or
! element content.
!
! @param $s the string to be escaped.
! @return the escaped string.
-->
<xsl:function name="p:xml-escape" as="xs:string">
<xsl:param name="s" as="xs:string"/>

<xsl:sequence select="
replace(
replace(
replace($s, '&amp;', '&amp;amp;'),
'&lt;', '&amp;lt;'),
'&quot;', '&amp;quot;')
"/>
</xsl:function>

<!--~
! Predict the decision for a given decision point based on current
! lookahead.
!
! @param $input the input string.
! @param $state the parser state.
! @param $dpi the decision point index.
: @param $id the parsing thread id.
! @return the updated parser state.
-->
<xsl:function name="p:predict" as="item()+">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="state" as="item()+"/>
<xsl:param name="dpi" as="xs:integer"/>
<xsl:param name="id" as="xs:integer"/>

<xsl:variable name="state" select="p:lookahead1($p:TOKENSET[$dpi + 1], $input, $state, $id)"/>
<xsl:choose>
<xsl:when test="$state[$p:l1] lt 0">
<xsl:variable name="node">
<xsl:element name="error">
<xsl:attribute name="b" select="$state[$p:b1]"/>
<xsl:attribute name="e" select="$state[$p:e1]"/>
<xsl:attribute name="s" select="- $state[$p:l1]"/>
</xsl:element>
</xsl:variable>
<xsl:sequence select="
0,
subsequence($state, $p:lk + 1)
"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="j10" select="16 * $dpi + $state[$p:l1]"/>
<xsl:variable name="j11" select="$j10 idiv 4"/>
<xsl:variable name="action" select="$p:CASEID[$j10 mod 4 + $p:CASEID[$j11 + 1] + 1]"/>
<xsl:sequence select="$action idiv 2, subsequence($state, $p:lk + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Match next token in input string, starting at given index, using
! the DFA entry state for the set of tokens that are expected in
! the current context.
!
! @param $input the input string.
! @param $begin the index where to start in input string.
! @param $token-set the expected token set id.
: @param $id the parsing thread id.
! @return a sequence of three: the token code of the result token,
! with input string begin and end positions. If there is no valid
! token, return the negative id of the DFA state that failed, along
! with begin and end positions of the longest viable prefix.
-->
<xsl:function name="p:match" as="xs:integer+">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="begin" as="xs:integer"/>
<xsl:param name="token-set" as="xs:integer"/>
<xsl:param name="id" as="xs:integer"/>

<xsl:sequence select="p:trace(concat(' &lt;tokenize thread=&quot;', $id, '&quot; tokenset=&quot;', $token-set, '&quot;&gt;'))"/>
<xsl:variable name="result" select="$p:INITIAL[1 + $token-set]"/>
<xsl:sequence select="p:transition($input, $begin, $begin, $begin, $result, $result mod 2, 0)"/>
</xsl:function>

<!--~
! The DFA state transition function. If we are in a valid DFA state, save
! it's result annotation, consume one input codepoint, calculate the next
! state, and use tail recursion to do the same again. Otherwise, return
! any valid result or a negative DFA state id in case of an error.
!
! @param $input the input string.
! @param $begin the begin index of the current token in the input string.
! @param $current the index of the current position in the input string.
! @param $end the end index of the result in the input string.
! @param $result the result code.
! @param $current-state the current DFA state.
! @param $previous-state the previous DFA state.
! @return a sequence of three: the token code of the result token,
! with input string begin and end positions. If there is no valid
! token, return the negative id of the DFA state that failed, along
! with begin and end positions of the longest viable prefix.
-->
<xsl:function name="p:transition">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="begin" as="xs:integer"/>
<xsl:param name="current" as="xs:integer"/>
<xsl:param name="end" as="xs:integer"/>
<xsl:param name="result" as="xs:integer"/>
<xsl:param name="current-state" as="xs:integer"/>
<xsl:param name="previous-state" as="xs:integer"/>

<xsl:choose>
<xsl:when test="$current-state eq 0">
<xsl:variable name="result" select="$result idiv 2"/>
<xsl:variable name="end" select="if ($end gt string-length($input)) then string-length($input) + 1 else $end"/>
<xsl:sequence select="
if ($result ne 0) then
(
p:trace(concat(' &lt;done result=&quot;', p:xml-escape($p:TOKEN[$result]), '&quot; begin=&quot;', $begin, '&quot; end=&quot;', $end, '&quot;/&gt;')),
p:trace(' &lt;/tokenize&gt;'),
$result - 1,
$begin,
$end
)
else
(
p:trace(concat(' &lt;fail begin=&quot;', $begin, '&quot; end=&quot;', $current - 1, '&quot; state=&quot;', $previous-state, '&quot;/&gt;')),
p:trace(' &lt;/tokenize&gt;'),
- $previous-state,
$begin,
$current - 1
)
"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="c0" select="(string-to-codepoints(substring($input, $current, 1)), 0)[1]"/>
<xsl:variable name="c1" as="xs:integer">
<xsl:choose>
<xsl:when test="$c0 &lt; 128">
<xsl:sequence select="$p:MAP0[1 + $c0]"/>
</xsl:when>
<xsl:when test="$c0 &lt; 55296">
<xsl:variable name="c1" select="$c0 idiv 32"/>
<xsl:variable name="c2" select="$c1 idiv 32"/>
<xsl:sequence select="$p:MAP1[1 + $c0 mod 32 + $p:MAP1[1 + $c1 mod 32 + $p:MAP1[1 + $c2]]]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="0"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="current" select="$current + 1"/>
<xsl:variable name="i0" select="2 * $c1 + $current-state - 1"/>
<xsl:variable name="next-state" select="$p:TRANSITION[$i0 + 1]"/>
<xsl:sequence select="
p:trace
(
string-join
(
(
' &lt;next state=&quot;', string($current-state), '&quot;',
' offset=&quot;', string($current - 1), '&quot;',
if ($c0 lt 32 or $c0 gt 126) then
()
else
(' char=&quot;', p:xml-escape(substring($input, $current - 1, 1)), '&quot;'),
' codepoint=&quot;', string($c0), '&quot;',
' class=&quot;', string($c1), '&quot;',
if ($next-state lt 2) then
()
else
(
' result=&quot;',
p:xml-escape($p:TOKEN[$next-state idiv 2 mod 4]), '&quot;',
if ($next-state lt 8) then
''
else
(' trailing-context-size=&quot;', string($next-state idiv 8), '&quot;')
),
'/&gt;'
),
''
)
),
if ($next-state &gt; 1) then
p:transition($input, $begin, $current, $current, $next-state, $next-state mod 2, $current-state)
else
p:transition($input, $begin, $current, $end, $result, $next-state, $current-state)
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Recursively translate one 32-bit chunk of an expected token bitset
! to the corresponding sequence of token strings.
!
! @param $result the result of previous recursion levels.
! @param $chunk the 32-bit chunk of the expected token bitset.
! @param $base-token-code the token code of bit 0 in the current chunk.
! @return the set of token strings.
-->
<xsl:function name="p:token">
<xsl:param name="result" as="xs:string*"/>
<xsl:param name="chunk" as="xs:integer"/>
<xsl:param name="base-token-code" as="xs:integer"/>

<xsl:sequence select="
if ($chunk = 0) then
$result
else
p:token
(
($result, if ($chunk mod 2 != 0) then $p:TOKEN[$base-token-code] else ()),
if ($chunk &lt; 0) then $chunk idiv 2 + 2147483648 else $chunk idiv 2,
$base-token-code + 1
)
"/>
</xsl:function>

<!--~
! Get GOTO table entry for given nonterminal and parser state.
!
! @param $nonterminal the nonterminal.
! @param $state the LR parser state.
! @return the GOTO table entry.
-->
<xsl:function name="p:goto" as="xs:integer">
<xsl:param name="nonterminal" as="xs:integer"/>
<xsl:param name="state" as="xs:integer"/>

<xsl:variable name="i0" select="8 * $state + $nonterminal"/>
<xsl:sequence select="$p:GOTO[$i0 + 1]"/>
</xsl:function>

<!--~
! Calculate expected token set for a given DFA state as a sequence
! of strings.
!
! @param $state the DFA state.
! @return the set of token strings
-->
<xsl:function name="p:expected-token-set" as="xs:string*">
<xsl:param name="state" as="xs:integer"/>

<xsl:if test="$state > 0">
<xsl:for-each select="0 to 0">
<xsl:variable name="i0" select=". * 1 + $state - 1"/>
<xsl:sequence select="p:token((), $p:EXPECTED[$i0 + 1], . * 32 + 1)"/>
</xsl:for-each>
</xsl:if>
</xsl:function>

<!--~
! Determine index of the next thread that must be parsed, by comparing
! threads in $threads starting at $i with the candidate at $thread.
!
! @param $threads the sequence of all current threads.
! @param $thread the index of the next thread candidate.
! @param $i the index where to start searching.
! @return the index of the next thread.
-->
<xsl:function name="p:next-thread">
<xsl:param name="threads" as="map(*)*"/>
<xsl:param name="thread" as="xs:integer"/>
<xsl:param name="i" as="xs:integer"/>

<xsl:choose>
<xsl:when test="$i gt count($threads)">
<xsl:sequence select="$thread"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="thread">
<xsl:choose>
<xsl:when test="$threads[$thread]?accepted ne $threads[$i]?accepted">
<xsl:sequence select="if ($threads[$thread]?accepted) then $i else $thread"/>
</xsl:when>
<xsl:when test="$threads[$thread]?lexer-state[$p:e0] ne $threads[$i]?lexer-state[$p:e0]">
<xsl:sequence select="if ($threads[$thread]?lexer-state[$p:e0] lt $threads[$i]?lexer-state[$p:e0]) then $thread else $i"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="if ($threads[$thread]?id le $threads[$i]?id) then $thread else $i"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="p:next-thread($threads, $thread, $i + 1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Compare two parsing threads for equality. A result of false indicates an
! ambiguity.
!
! @param $t1 the first thread data.
! @param $t2 the second thread data.
! @return true(), if threads are equal.
-->
<xsl:function name="p:thread-equals" as="xs:boolean">
<xsl:param name="t1" as="map(*)"/>
<xsl:param name="t2" as="map(*)"/>

<xsl:sequence select="
if ($t1?accepted ne $t2?accepted) then false() else
if ($t1?b1 ne $t2?lexer-state[$p:b1]) then false() else
if ($t1?e1 ne $t2?lexer-state[$p:e1]) then false() else
if ($t1?l1 ne $t2?lexer-state[$p:l1]) then false() else
if ($t1?state ne $t2?state) then false() else
if ($t1?action ne $t2?action) then false() else deep-equal($t1?stack, $t2?stack)
"/>
</xsl:function>

<!--~
! Perform GLR parsing by selecting a thread and invoke the LR parse function
! on it for a single token. Process result with respect to thread management.
!
! @param $input the input string.
! @param $target the target symbol code.
! @param $max-id the maximum thread id.
! @param $threads the sequence of all current threads.
! @return the lexer state of the accepting (or error) thread.
-->
<xsl:function name="p:parse-glr">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="target" as="xs:integer"/>
<xsl:param name="max-id" as="xs:integer"/>
<xsl:param name="threads" as="map(*)+"/>

<xsl:variable name="i" select="p:next-thread($threads, 1, 2)"/>
<xsl:variable name="thread" select="$threads[$i]"/>
<xsl:variable name="lexer-state" select="$thread?lexer-state"/>
<xsl:choose>
<xsl:when test="$thread?accepted">
<xsl:variable name="max-e0" select="max($threads!?lexer-state[$p:e0])"/>
<xsl:variable name="longest-accept" select="$threads[?lexer-state[$p:e0] eq $max-e0]"/>
<xsl:choose>
<xsl:when test="count($longest-accept) eq 1">
<xsl:sequence select="$longest-accept?lexer-state"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="p:reject-ambiguity($longest-accept[1], $longest-accept[2])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="threads" select="(subsequence($threads, 1, $i - 1), subsequence($threads, $i + 1))"/>
<xsl:variable name="other" select="if (exists($threads)) then $threads[p:next-thread($threads, 1, 2)] else ()"/>
<xsl:choose>
<xsl:when test="exists($other) and p:thread-equals($thread, $other)">
<xsl:sequence select="p:reject-ambiguity($thread, $other)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="thread" select="p:parse($input, $target, $max-id, $thread)"/>
<xsl:variable name="lexer-state" select="$thread?lexer-state"/>
<xsl:sequence select="
if (count($thread) gt 1) then
p:parse-glr($input, $target, $max-id + 1, ($threads, $thread))
else if (not($lexer-state[$p:error])) then
p:parse-glr($input, $target, $max-id, ($threads, $thread))
else if (exists($threads)) then
p:parse-glr($input, $target, $max-id, $threads)
else
$lexer-state
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Raise an error for ambiguous input.
!
! @param $thread the parsing thread data.
! @param $other the parsing thread data of the other thread.
! @return a lexer state containing an error element describing the ambiguity.
-->
<xsl:function name="p:reject-ambiguity" as="item()+">
<xsl:param name="thread" as="map(*)"/>
<xsl:param name="other" as="map(*)"/>

<xsl:variable name="lexer-state" select="$thread?lexer-state"/>
<xsl:variable name="first-tree" select="$lexer-state[last()]"/>
<xsl:variable name="second-tree" select="$other?lexer-state[last()]"/>
<xsl:variable name="node">
<xsl:element name="error">
<xsl:attribute name="b" select="$thread?stack[last() - 2]"/>
<xsl:attribute name="e" select="$lexer-state[$p:e0]"/>
<xsl:attribute name="ambiguous-input" select="true()"/>
<xsl:element name="AMBIGUOUS">
<xsl:element name="ALTERNATIVE">
<xsl:sequence select="p:rewrite-ambiguity($first-tree, $second-tree, true())"/>
</xsl:element>
<xsl:element name="ALTERNATIVE">
<xsl:sequence select="p:rewrite-ambiguity($second-tree, $first-tree, true())"/>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:variable>
<xsl:sequence select="
subsequence($lexer-state, 1, $p:error - 1),
$node/node(),
subsequence($lexer-state, $p:error + 1)
"/>
</xsl:function>

<!--~
! Rewrite a parse tree fragment $first, combining elements into an "UNAMBIGUOUS"
! element as long as they match elements in $second, in node order.
!
! @param $first the first node.
! @param $second the second node.
! @return $first rewritten, with initial element nodes possibly combined.
-->
<xsl:function name="p:rewrite-ambiguity">
<xsl:param name="first" as="node()"/>
<xsl:param name="second" as="node()?"/>
<xsl:param name="unambiguous" as="xs:boolean"/>

<xsl:choose>
<xsl:when test="$first instance of element()">
<xsl:choose>
<xsl:when test="$unambiguous and deep-equal($first, $second)">
<xsl:variable name="node">
<xsl:element name="UNAMBIGUOUS">
<xsl:sequence select="string($first)"/>
</xsl:element>
</xsl:variable>
<xsl:sequence select="$node/node()"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="node">
<xsl:element name="{node-name($first)}">
<xsl:for-each select="1 to count($first/node())">
<xsl:variable name="i" select="."/>
<xsl:sequence select="
p:rewrite-ambiguity
(
$first/node()[$i], $second/node()[$i],
$unambiguous and (every $j in 1 to $i - 1 satisfies deep-equal($first/node()[$j], $second/node()[$j]))
)
"/>
</xsl:for-each>
</xsl:element>
</xsl:variable>
<xsl:sequence select="$node/node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$first"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Construct a new map containing data for one parsing thread.
!
! @param $id the parsing thread id.
! @param $accepted true(), if this thread has accepted.
! @param $state the LR parser state number.
! @param $action the action code.
! @param $nonterminal current nonterminal, -1 if processing a terminal.
! @param $bw the whitespace begin input index.
! @param $bs the symbol begin input index.
! @param $es the symbol end input index.
! @param $stack the LR stack.
! @param $lexer-state lexer state, error indicator, and result stack.
! @return the thread data map.
-->
<xsl:function name="p:thread" as="map(*)">
<xsl:param name="id" as="xs:integer"/>
<xsl:param name="accepted" as="xs:boolean"/>
<xsl:param name="state" as="xs:integer"/>
<xsl:param name="action" as="xs:integer"/>
<xsl:param name="nonterminal" as="xs:integer"/>
<xsl:param name="bw" as="xs:integer"/>
<xsl:param name="bs" as="xs:integer"/>
<xsl:param name="es" as="xs:integer"/>
<xsl:param name="stack" as="xs:integer*"/>
<xsl:param name="lexer-state" as="item()+"/>

<xsl:sequence select="
map
{
'id': $id,
'accepted': $accepted,
'state': $state,
'action': $action,
'nonterminal': $nonterminal,
'bw': $bw,
'bs': $bs,
'es': $es,
'stack': $stack,
'lexer-state': $lexer-state
}
"/>
</xsl:function>

<!--~
! Parse input for given target symbol using LR tables. Each invocation
! handles one parsing action (shift, reduce, shift+reduce, accept).
! Subsequent actions are handled by tail-recursion.
!
! @param $input the input string.
! @param $target the target symbol code.
! @param $max-id the maximum thread id.
! @param $thread the parsing thread data.
! @return the updated state.
-->
<xsl:function name="p:parse">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="target" as="xs:integer"/>
<xsl:param name="max-id" as="xs:integer"/>
<xsl:param name="thread" as="map(*)"/>

<xsl:variable name="lexer-state" select="$thread?lexer-state"/>
<xsl:choose>
<xsl:when test="$lexer-state[$p:error]">
<xsl:sequence select="$thread"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="state" select="$thread?state"/>
<xsl:variable name="action" select="$thread?action"/>
<xsl:variable name="nonterminal" select="$thread?nonterminal"/>
<xsl:variable name="bw" select="$thread?bw"/>
<xsl:variable name="bs" select="$thread?bs"/>
<xsl:variable name="es" select="$thread?es"/>
<xsl:variable name="stack" select="$thread?stack"/>
<xsl:variable name="trace" select="
string-join
(
(
' &lt;parse thread=&quot;', $thread?id, '&quot; offset=&quot;', $lexer-state[$p:e0], '&quot; state=&quot;', string($state), '&quot; input=&quot;',
$p:NONTERMINAL[$nonterminal + 1],
' '[$nonterminal ge 0 and $lexer-state[$p:l1] gt 0],
p:xml-escape(p:lookahead-string($lexer-state)),
'&quot; action=&quot;'
),
''
)
"/>
<xsl:variable name="argument" select="$action idiv 32"/>
<xsl:variable name="lookback" select="($action idiv 8) mod 4"/>
<xsl:variable name="action" select="$action mod 8"/>
<xsl:choose>
<xsl:when test="$action eq 6"> <!-- SHIFT+ACCEPT -->
<xsl:sequence select="
p:trace(concat($trace, 'accept&quot;/>')),
p:thread($thread?id, true(), $state, $action, $nonterminal, $bw, $bs, $es, $stack, $lexer-state)
"/>
</xsl:when>
<xsl:when test="$action eq 7"> <!-- FORK -->
<xsl:sequence select="
p:trace(concat($trace, 'fork&quot;/>')),
for $i in (1, 2)
return p:thread(($max-id + 1, $thread?id)[$i], false(), $state, $p:APPENDIX[$argument + $i], -1, $bw, $bs, $es, $stack, $lexer-state)
"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="shift-reduce-symbols" select="
if ($action eq 1) then (: SHIFT :)
($argument, -1, -1)
else if ($action eq 2) then (: REDUCE :)
(-1, $argument, $lookback)
else if ($action eq 4) then (: SHIFT+REDUCE :)
($state, $argument, $lookback + 1)
else (: ERROR :)
(-1, -1, -1)
"/>
<xsl:variable name="shift" select="$shift-reduce-symbols[1]"/>
<xsl:variable name="reduce" select="$shift-reduce-symbols[2]"/>
<xsl:variable name="symbols" select="$shift-reduce-symbols[3]"/>
<xsl:variable name="es" select="if ($shift lt 0 or $nonterminal ge 0) then $es else $lexer-state[$p:e1]"/>
<xsl:variable name="trace" select="if ($shift lt 0) then $trace else concat($trace, 'shift')"/>
<xsl:variable name="lexer-state" select="
if ($shift lt 0 or $nonterminal ge 0) then
$lexer-state
else
p:consume
(
$lexer-state[$p:l1],
$input,
$lexer-state
)
"/>
<xsl:variable name="stack" select="
if ($shift lt 0) then
$stack
else
($stack, if ($nonterminal lt 0) then $lexer-state[$p:b0] else $bs, $state, $lookback)
"/>
<xsl:variable name="state" select="if ($shift lt 0) then $state else $shift"/>
<xsl:choose>
<xsl:when test="$reduce lt 0">
<xsl:choose>
<xsl:when test="$shift lt 0">
<xsl:variable name="node">
<xsl:element name="error">
<xsl:attribute name="b" select="$lexer-state[$p:b1]"/>
<xsl:attribute name="e" select="$lexer-state[$p:e1]"/>
<xsl:if test="$lexer-state[$p:l1] gt 0">
<xsl:attribute name="o" select="$lexer-state[$p:l1]"/>
</xsl:if>
<xsl:attribute name="s" select="$p:TOKENSET[$state + 1] + 1"/>
</xsl:element>
</xsl:variable>
<xsl:sequence select="
p:trace(concat($trace, 'fail&quot;/>')),
p:thread
(
$thread?id, false(), $state, 0, -1, $bw, $bs, $es, $stack,
(
subsequence($lexer-state, 1, $p:error - 1),
$node/node(),
subsequence($lexer-state, $p:error + 1)
)
)
"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="lexer-state" select="p:predict($input, $lexer-state, $state, $thread?id)"/>
<xsl:sequence select="
p:trace(concat($trace, '&quot;/&gt;')),
p:thread($thread?id, false(), $state, $lexer-state[$p:lk], -1, $bw, $bs, $es, $stack, $lexer-state)
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="trace" select="concat($trace, if ($shift lt 0) then '' else ' ', 'reduce&quot; nonterminal=&quot;', $p:NONTERMINAL[$reduce + 1], '&quot; count=&quot;', $symbols, '&quot;/>')"/>
<xsl:variable name="state" select="if ($symbols gt 0) then $stack[last() - 3 * $symbols + 2] else $state"/>
<xsl:variable name="bs" select="if ($symbols gt 0) then $stack[last() - 3 * $symbols + 1] else $lexer-state[$p:b1]"/>
<xsl:variable name="es" select="if ($symbols gt 0) then $es else $bs"/>
<xsl:variable name="stack" select="if ($symbols gt 0) then subsequence($stack, 1, count($stack) - 3 * $symbols) else $stack"/>
<xsl:variable name="accept" select="$reduce eq $target and count($stack) eq 3"/>
<xsl:variable name="bs" select="if ($accept) then $bw else $bs"/>
<xsl:variable name="es" select="if ($accept) then $lexer-state[$p:b1] else $es"/>
<xsl:variable name="bw" select="if ($accept) then $es else $bw"/>
<xsl:variable name="index" select="if ($accept) then $p:result else p:first-child-node-index($lexer-state, count($lexer-state) + 1, $symbols)"/>
<xsl:variable name="node">
<xsl:element name="{$p:NONTERMINAL[$reduce + 1]}">
<xsl:sequence select="subsequence($lexer-state, $index)"/>
</xsl:element>
</xsl:variable>
<xsl:variable name="lexer-state" select="subsequence($lexer-state, 1, $index - 1), $node/node()"/>
<xsl:variable name="nonterminal" select="$reduce"/>
<xsl:variable name="thread" select="p:thread($thread?id, false(), $state, p:goto($nonterminal, $state), $nonterminal, $bw, $bs, $es, $stack, $lexer-state)"/>
<xsl:sequence select="p:trace($trace), p:parse($input, $target, $max-id, $thread)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Decrement given index by the given number of elements on the result
! stack, skipping any non-element nodes.
!
! @param $state lexer state, error indicator, and result stack.
! @param $index the index into the result stack.
! @param $element-count the number of elements to be handled.
! @return the decremented index.
-->
<xsl:function name="p:first-child-node-index">
<xsl:param name="state" as="item()+"/>
<xsl:param name="index" as="xs:integer"/>
<xsl:param name="element-count" as="xs:integer"/>

<xsl:choose>
<xsl:when test="$element-count eq 0">
<xsl:sequence select="$index"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="index" select="$index - 1"/>
<xsl:variable name="element-count" select="$element-count - (if ($state[$index] instance of element()) then 1 else 0)"/>
<xsl:sequence select="p:first-child-node-index($state, $index, $element-count)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Assemble a string showing current lookahead tokens, as far as they have
! been tokenized.
!
! @param $state lexer state, error indicator, and result stack.
! @return a string containing the space-separated list of lookahead tokens.
-->
<xsl:function name="p:lookahead-string" as="xs:string">
<xsl:param name="state" as="item()+"/>

<xsl:sequence select="
string-join
(
(
if ($state[$p:l1] le 0) then
()
else
(
$p:TOKEN[$state[$p:l1] + 1]
)
),
' '
)
"/>
</xsl:function>

<!--~
! Create a textual error message from a parsing error.
!
! @param $input the input string.
! @param $error the parsing error descriptor.
! @return the error message.
-->
<xsl:function name="p:error-message" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="error" as="element(error)"/>

<xsl:variable name="begin" select="xs:integer($error/@b)"/>
<xsl:variable name="context" select="string-to-codepoints(substring($input, 1, $begin - 1))"/>
<xsl:variable name="linefeeds" select="index-of($context, 10)"/>
<xsl:variable name="line" select="count($linefeeds) + 1"/>
<xsl:variable name="column" select="($begin - $linefeeds[last()], $begin)[1]"/>
<xsl:variable name="expected" select="if ($error/@x or $error/@ambiguous-input) then () else p:expected-token-set($error/@s)"/>
<xsl:sequence select="
string-join
(
(
if ($error/@ambiguous-input) then
'ambiguous input'
else if ($error/@o) then
('syntax error, found ', $p:TOKEN[$error/@o + 1])
else
'lexical analysis failed',
'&#10;',
if ($error/@ambiguous-input) then
()
else
(
'while expecting ',
if ($error/@x) then
$p:TOKEN[$error/@x + 1]
else
(
'['[exists($expected[2])],
string-join($expected, ', '),
']'[exists($expected[2])]
),
'&#10;',
if ($error/@o or $error/@e = $begin) then
()
else
('after successfully scanning ', string($error/@e - $begin), ' characters beginning ')
),
'at line ', string($line), ', column ', string($column), ':&#10;',
'...', substring($input, $begin, 64), '...'
),
''
)
"/>
</xsl:function>

<!--~
! Consume one token, i.e. compare lookahead token 1 with expected
! token and in case of a match, shift lookahead tokens down such that
! l1 becomes the current token, and higher lookahead tokens move down.
! When lookahead token 1 does not match the expected token, raise an
! error by saving the expected token code in the error field of the
! lexer state.
!
! @param $code the expected token.
! @param $input the input string.
! @param $state lexer state, error indicator, and result.
! @return the updated state.
-->
<xsl:function name="p:consume" as="item()+">
<xsl:param name="code" as="xs:integer"/>
<xsl:param name="input" as="xs:string"/>
<xsl:param name="state" as="item()+"/>

<xsl:choose>
<xsl:when test="$state[$p:error]">
<xsl:sequence select="$state"/>
</xsl:when>
<xsl:when test="$state[$p:l1] eq $code">
<xsl:variable name="begin" select="$state[$p:e0]"/>
<xsl:variable name="end" select="$state[$p:b1]"/>
<xsl:variable name="whitespace">
<xsl:if test="$begin ne $end">
<xsl:value-of select="substring($input, $begin, $end - $begin)"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="token" select="$p:TOKEN[1 + $state[$p:l1]]"/>
<xsl:variable name="name" select="if (starts-with($token, &quot;'&quot;)) then 'TOKEN' else $token"/>
<xsl:variable name="begin" select="$state[$p:b1]"/>
<xsl:variable name="end" select="$state[$p:e1]"/>
<xsl:variable name="node">
<xsl:element name="{$name}">
<xsl:sequence select="substring($input, $begin, $end - $begin)"/>
</xsl:element>
</xsl:variable>
<xsl:sequence select="
subsequence($state, $p:l1, 3),
0, 0, 0,
subsequence($state, 7),
$whitespace/node(),
$node/node()
"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="error">
<xsl:element name="error">
<xsl:attribute name="b" select="$state[$p:b1]"/>
<xsl:attribute name="e" select="$state[$p:e1]"/>
<xsl:choose>
<xsl:when test="$state[$p:l1] lt 0">
<xsl:attribute name="s" select="- $state[$p:l1]"/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="o" select="$state[$p:l1]"/>
<xsl:attribute name="x" select="$code"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:variable>
<xsl:sequence select="
subsequence($state, 1, $p:error - 1),
$error/node(),
subsequence($state, $p:error + 1)
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Lookahead one token on level 1.
!
! @param $set the code of the DFA entry state for the set of valid tokens.
! @param $input the input string.
! @param $state lexer state, error indicator, and result stack.
! @param $id the parsing thread id.
! @return the updated state.
-->
<xsl:function name="p:lookahead1" as="item()+">
<xsl:param name="set" as="xs:integer"/>
<xsl:param name="input" as="xs:string"/>
<xsl:param name="state" as="item()+"/>
<xsl:param name="id" as="xs:integer"/>

<xsl:choose>
<xsl:when test="$state[$p:l1] ne 0">
<xsl:sequence select="$state"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="match" select="
p:match($input, $state[$p:e0], $set, $id)
"/>
<xsl:sequence select="
$match[1],
subsequence($state, $p:b0, 2),
$match,
subsequence($state, 7)
"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! Parse start symbol X from given string.
!
! @param $s the string to be parsed.
! @return the result as generated by parser actions.
-->
<xsl:function name="p:parse-X" as="item()*">
<xsl:param name="s" as="xs:string"/>

<xsl:variable name="state" select="0, 1, 1, 0, 0, 0, false()"/>
<xsl:variable name="state" select="p:predict($s, $state, 0, 0)"/>
<xsl:variable name="state" select="p:parse-glr($s, 0, 0, p:thread(0, false(), 0, $state[$p:lk], -1, 1, 1, 1, (1, -1, 0), $state))"/>
<xsl:variable name="error" select="$state[$p:error]"/>
<xsl:choose>
<xsl:when test="$error">
<xsl:variable name="ERROR">
<xsl:element name="ERROR">
<xsl:sequence select="$error/@*, p:error-message($s, $error)"/>
</xsl:element>
</xsl:variable>
<xsl:sequence select="$error/AMBIGUOUS, $ERROR/node()"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="subsequence($state, $p:result)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>

<!--~
! The input filename, or string, if surrounded by curly braces.
-->
<xsl:param name="input" as="xs:string?" select="()"/>

<!--~
! The (simple) main program.
-->
<xsl:template name="main" match="/">
<xsl:param name="input" as="xs:string?" select="$input"/>

<xsl:choose>
<xsl:when test="empty($input)">
<xsl:sequence select="error(xs:QName('main'), '&#xA; Usage: java net.sf.saxon.Transform -xsl:x.xslt -it:main input=INPUT&#xA;&#xA; parse INPUT, which is either a filename or literal text enclosed in curly braces')"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="result" select="
p:trace('&lt;trace&gt;'),
if (matches($input, '^\{.*\}$')) then
p:parse-X(substring($input, 2, string-length($input) - 2))
else
p:parse-X(unparsed-text($input, 'utf-8')),
p:trace('&lt;/trace&gt;')
"/>
<xsl:choose>
<xsl:when test="empty($result/self::ERROR)">
<xsl:sequence select="$result"/>
</xsl:when>
<xsl:otherwise>
<xsl:result-document>
<xsl:sequence select="$result[not(self::ERROR)], '&#10;'"/>
</xsl:result-document>
<xsl:sequence select="error(xs:QName('p:parse-X'), concat('&#10; ', replace($result[self::ERROR], '&#10;', '&#10; ')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>
    (1-1/1)