<?xml version="1.0"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:variable name="lang" select="/language/@name"/>

<!--
 ! This template gens the bison code for a <language/> file.
 +-->
<xsl:template match="language">

<!--
 ! If the grammar has a know number of expected shift/reduce conflicts,
 ! gen a pragma line to the parser generator.
 +-->
<xsl:if test="parser/@expected_conflicts">
%expect <xsl:value-of select="parser/@expected_conflicts"/>
  <xsl:text>&#xa;</xsl:text>
  <xsl:text>&#xa;</xsl:text>
  </xsl:if>

<!--
 ! When the <parser/> has a specified "start" symbol, use it as the basis,
 ! otherwise, use the first <nonterm/> in the language.
 +-->
%start <xsl:value-of select="$lang"/><xsl:text>_sym_</xsl:text>
<xsl:choose>
  <xsl:when test="parser/@start">
    <xsl:value-of select="parser/@start"/>
    </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="parser/nonterm[1]/@name"/>
    </xsl:otherwise>
  </xsl:choose>

<xsl:text>&#xa;</xsl:text>
<xsl:text>&#xa;</xsl:text>

<!--
 ! Generate a list of the terminals of the language which will be returned
 ! by the lexer.
 +-->
<xsl:for-each select="lexer/match/@term">
  <xsl:if test="not(preceding::match[@term=current()])">
  <!-- only select the first occurance of each terminal. -->
    <xsl:text>%token </xsl:text>
    <xsl:value-of select="concat($lang, '_sym_', .)"/>
    <xsl:text>&#xa;</xsl:text>
    </xsl:if>
  </xsl:for-each>

%token <xsl:value-of select="$lang"/>_lex_error

%{/* <xsl:value-of select="$lang"/>_parser.y */

#include &lt;libxml/tree.h&gt;
#include &lt;fcntl.h&gt;

#define YYSTYPE xmlNodePtr
#define YYERROR_VERBOSE 1

static xmlNodePtr last_node;

static int track_token_position = 0;
static int line_number;
static int column_number;

/* Include lexer generated from <xsl:value-of select="$lang"/>_lexer.l */
#include "<xsl:value-of select="$lang"/>_lexer.c"

%}

%%

<!--
 ! Generate the action code for each nonterminal which _has_ action code.
 +-->
<xsl:for-each select="parser/nonterm[production or @epsilon = 'true']">
  <xsl:text>&#xa;</xsl:text>
  <xsl:call-template name="parser_nonterm"/>
  </xsl:for-each>

%%

int yywrap(void) { return 1; }

int
yyerror
	(char *msg)
{
	fprintf(stderr, "Error at line %d: %s\n", line_number, msg);
}

const char usage[] = \
"usage: <xsl:value-of select="$lang"/>_parser [options] [file]\n" \
"Parse <xsl:value-of select="$lang"/> into XML.\n" \
"The file \"--\" is treated as standard input.\n" \
"\n" \
"Options:\n" \
"\t-h, -?, --help\n" \
"\t    Print this help.\n" \
"\n\t--track\n" \
"\t    Track lexical line numbers and positions.\n" \
"\n\t--no-track\n" \
"\t    Don't track lexical line numbers and positions.\n" \
"\n";

int
main
	(int argc,
	 char **argv)
{
	/* This programs parses data from stdin,
         * and writes its output to stdout. */

	FILE *f;
	int i, ret;
	xmlDocPtr doc;

	line_number = 1;
	column_number = 1;

	if (argc == 1) {
		printf("%s", usage);
		return 0;
	}

	for (i = 1; i &lt; argc; i++) {
		if (!strcmp("-h", argv[i])) {
			printf("%s\n", usage);
			return 0;

		} else if (!strcmp("-?", argv[i])) {
			printf("%s\n", usage);
			return 0;

		} else if (!strcmp("--help", argv[i])) {
			printf("%s\n", usage);
			return 0;

		} else if (!strcmp("--track", argv[i])) {
			track_token_position = 1;

		} else if (!strcmp("--no-track", argv[i])) {
			track_token_position = 0;

		} else if (!strcmp("--", argv[i])) {
			yyrestart(stdin);

		} else {
			f = fopen(argv[i], "r");
			if (f == NULL) {
				perror("<xsl:value-of
				select="$lang"/>_parser");
				return 1;
			}
			yyrestart(f);
			break;
		}
	}

	ret = yyparse( );

	if (ret == 0) {
		doc = xmlNewDoc("1.0");
		xmlSetTreeDoc(last_node, doc);
		xmlDocSetRootElement(doc, last_node);

		xmlDocFormatDump(stdout, doc, 1);
		xmlFreeDoc(doc);
		ret = 0;
	} else {
		ret = 1;
	}

	return ret;
}
	</xsl:template>


<!--
 ! This template generates the code for a single <nonterm/> element.
 +-->
<xsl:template name="parser_nonterm">
  <!--
   ! Gen and namespace the nonterm's symbol.
   !
   ! Ex: <nonterm name="SYM"/> => "LANG_sym_SYM:"
   +-->
  <xsl:value-of select="$lang"/>_sym_<xsl:value-of select="@name"/>
  <xsl:text>:&#xa;</xsl:text>

  <!--
   ! This for-each gens the code for each <production/> of the <nonterm/>.
   +-->
  <xsl:for-each select="production">
    <!--
     ! Gen and namespace the symbols of the production.
     ! 
     ! Ex: <production>
     !       <symbol>A</symbol>
     !       <symbol>B</symbol>
     !       <symbol>C</symbol>
     !       </production> => "LANG_sym_A LANG_sym_B LANG_sym_C"
     +-->
    <xsl:text>	</xsl:text>
    <xsl:if test="position()!=1">| </xsl:if>
    <xsl:for-each select="symbol">
      <xsl:value-of select="$lang"/>
      <xsl:text>_sym_</xsl:text>
      <xsl:value-of select="."/>
      <xsl:if test="position() != last()">
        <xsl:text> </xsl:text>
        </xsl:if>
      </xsl:for-each>
{
	last_node = $$ = xmlNewNode(NULL, "<xsl:value-of select="../@name"/>
	<xsl:text>");&#xa;</xsl:text>

	<xsl:for-each select="symbol">

        <!--
         ! Calculate the action to take for this symbol.
         ! It defaults to "preserve".
         +-->
	<xsl:variable name='action'>
	  <xsl:choose>
	    <xsl:when test="@action">
	      <xsl:value-of select="@action"/>
	      </xsl:when>
	    <xsl:otherwise>preserve</xsl:otherwise>
	    </xsl:choose>
	  </xsl:variable>

        <!--
         ! This generates a nice comment about what the action code will be
         ! doing.
         !
         ! Ex: /* Symbol: action='preserve', rename='DifferentSymbol' */
         +-->
	<xsl:text>&#xa;&#x9;/* </xsl:text><xsl:value-of select="."/>
	<xsl:text>: action='</xsl:text>
	<xsl:value-of select='$action'/>
	<xsl:text>'</xsl:text>
	<xsl:if test="@rename and @rename != ''">
	  <xsl:text>, rename='</xsl:text>
	  <xsl:value-of select='@rename'/>
	  <xsl:text>'</xsl:text>
	  </xsl:if>
	<xsl:text> */</xsl:text>

        <!--
         ! Action code for "rename".
         ! We rename the root of the sub-tree. This happens before any
         ! other action, so we needn't worry about any interactions with
         ! those actions.
         +-->
	<xsl:if test="@rename and @rename != ''">
	xmlNodeSetName($<xsl:value-of select="position()"/>
	  <xsl:text>, "</xsl:text>
          <xsl:value-of select="@rename"/>
	  <xsl:text>");</xsl:text>
		</xsl:if>

        <!--
         ! Action code for "preserve".
         ! We keep the entire sub-tree.
         +-->
	<xsl:choose>
	<xsl:when test="$action = 'preserve'">
	xmlAddChild($$, $<xsl:value-of select="position()"/>);
		</xsl:when>

        <!--
         ! Action code for "token".
         ! We keep only the root of the sub-tree, discarding it's children.
         +-->
	<xsl:when test="$action = 'token'">
	xmlAddChild($$, $<xsl:value-of select="position()"/>);
	if ($<xsl:value-of select="position()"/>->children) {
		xmlFreeNodeList($<xsl:value-of select="position()"/>
		<xsl:text>->children);</xsl:text>
		$<xsl:value-of select="position()"/>->children = NULL;
	}
		</xsl:when>

        <!--
         ! Action code for "content".
         ! We keep only the children (if there are any) of the sub-tree.
         +-->
	<xsl:when test="$action = 'content'">
	if ($<xsl:value-of select="position()"/>->children) {
		xmlAddChildList($$, $<xsl:value-of select="position()"/>
		<xsl:text>->children);</xsl:text>
		$<xsl:value-of select="position()"/>->children = NULL;
	}
	xmlFreeNode($<xsl:value-of select="position()"/>);
	$<xsl:value-of select="position()"/> = NULL;
		</xsl:when>

        <!--
         ! Action code for "drop".
         ! We free the sub-tree.
         +-->
	<xsl:when test="$action = 'drop'">
	xmlFreeNode($<xsl:value-of select="position()"/>);
	$<xsl:value-of select="position()"/> = NULL;
		</xsl:when>
		</xsl:choose>

		</xsl:for-each>
}
</xsl:for-each>
        <!--
         ! Action code for epsilon productions.
         +-->
	<xsl:if test="@epsilon and @epsilon = 'true'">	|
{
	last_node = $$ = xmlNewNode(NULL, "<xsl:value-of select="@name"/>");
}
</xsl:if>	;
	</xsl:template>


</xsl:transform>

