|
<?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',
|
|
"'x'"
|
|
"/>
|
|
|
|
<!--~
|
|
! 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;'),
|
|
'<', '&lt;'),
|
|
'"', '&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(' <tokenize thread="', $id, '" tokenset="', $token-set, '">'))"/>
|
|
<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(' <done result="', p:xml-escape($p:TOKEN[$result]), '" begin="', $begin, '" end="', $end, '"/>')),
|
|
p:trace(' </tokenize>'),
|
|
$result - 1,
|
|
$begin,
|
|
$end
|
|
)
|
|
else
|
|
(
|
|
p:trace(concat(' <fail begin="', $begin, '" end="', $current - 1, '" state="', $previous-state, '"/>')),
|
|
p:trace(' </tokenize>'),
|
|
- $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 < 128">
|
|
<xsl:sequence select="$p:MAP0[1 + $c0]"/>
|
|
</xsl:when>
|
|
<xsl:when test="$c0 < 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
|
|
(
|
|
(
|
|
' <next state="', string($current-state), '"',
|
|
' offset="', string($current - 1), '"',
|
|
if ($c0 lt 32 or $c0 gt 126) then
|
|
()
|
|
else
|
|
(' char="', p:xml-escape(substring($input, $current - 1, 1)), '"'),
|
|
' codepoint="', string($c0), '"',
|
|
' class="', string($c1), '"',
|
|
if ($next-state lt 2) then
|
|
()
|
|
else
|
|
(
|
|
' result="',
|
|
p:xml-escape($p:TOKEN[$next-state idiv 2 mod 4]), '"',
|
|
if ($next-state lt 8) then
|
|
''
|
|
else
|
|
(' trailing-context-size="', string($next-state idiv 8), '"')
|
|
),
|
|
'/>'
|
|
),
|
|
''
|
|
)
|
|
),
|
|
if ($next-state > 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 < 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
|
|
(
|
|
(
|
|
' <parse thread="', $thread?id, '" offset="', $lexer-state[$p:e0], '" state="', string($state), '" input="',
|
|
$p:NONTERMINAL[$nonterminal + 1],
|
|
' '[$nonterminal ge 0 and $lexer-state[$p:l1] gt 0],
|
|
p:xml-escape(p:lookahead-string($lexer-state)),
|
|
'" action="'
|
|
),
|
|
''
|
|
)
|
|
"/>
|
|
<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"/>')),
|
|
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"/>')),
|
|
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"/>')),
|
|
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, '"/>')),
|
|
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" nonterminal="', $p:NONTERMINAL[$reduce + 1], '" count="', $symbols, '"/>')"/>
|
|
<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',
|
|
' ',
|
|
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])]
|
|
),
|
|
' ',
|
|
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), ': ',
|
|
'...', 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, "'")) 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'), '
 Usage: java net.sf.saxon.Transform -xsl:x.xslt -it:main input=INPUT

 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('<trace>'),
|
|
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('</trace>')
|
|
"/>
|
|
<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)], ' '"/>
|
|
</xsl:result-document>
|
|
<xsl:sequence select="error(xs:QName('p:parse-X'), concat(' ', replace($result[self::ERROR], ' ', ' ')))"/>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
</xsl:stylesheet>
|