vishia - Zmake intern

vishia - Zmake intern

Inhalt


1 Parsen mit ZmakeStd.zbnf

Topic=.Zmake.internZbnf.

Dieser Abschnitt beschreibt, wie das ZBNF-Script:_xsl/ZmakeStd.zbnf funktioniert. Der Artikel bezieht sich gegebenenfalls nicht auf den letzten Stand, das ZBNF-Script soll, ein Grundverständnis vorausgesetzt, ansonsten selbstdokumentierend sein.

Die erste aktive Zeile

 Zmake::=<*|ZMAKE_RULES?> ZMAKE_RULES:  { \$<variable>; | <routine>; } \e.

definiert zunächst den Namen des Toplevel-XML-Elements als Zmake. Mit dem <*|ZMAKE_RULES?> werden dann alle Zeichen überlesen bis zur angegebenen Zeichenfolge. Diese wird dann als Terminalmorphem danach auch verlangt.

Das gesamte Script besteht aus einer Folge von $<variable>; oder <routine>. Beide Metamorpheme = Syntaxkomponenten sind danach definiert:

1.1 variable

Topic=.Zmake.internZbnf..

Eine Variable wird wie folgt definiert:

 variable::=<$?@name> = fileset ( <fileset> ).
 
 fileset::= {<?file> [<""?!prepFilePath>|<*\ \r\n,)?!prepFilePath>] ? , | + }.

Eine Variable besteht aus einem Bezeichner (<$?@name>), gefolgt von einem = und fileset(...). Etwas anderes ist derzeit nicht vorgesehen. Das <fileset> ist danach definiert:

Ein fileset besteht aus einer beliebigen Wiederholung von Filenamen, dazwischen ein , oder +. Ein fileset erzeugt pro Fileangabe ein XML-Element <file>. Ein filename kann entweder in Anführungszeichen stehen <""?!prepFilePath> oder ist eine Zeichenfolge bis ausschließlich einem Leerzeichen oder Zeilenendezeichen <* ,)?!prepFilePath>. Alles, was dazwischen steht, wird mit der Syntax prepFilePath geparst:

1.2 prepFilePath

Topic=.Zmake.internZbnf..

Diese Syntaxvorschrift wird benutzt, um eine vorher ermittelte Teilzeichenkette, die Filepathangabe, auseinanderzunehmen.

 prepFilePath::=<$NoWhiteSpaces><! *?> 
   [<!.?@drive>:]                              ## only 1 char with followed : is a drive like D: 
   [<*:?@pathbase>[?:=]:]                      ## all until : is the pathbase, not part of the 
   [<stringtolastinclChar/\\?@path>]           ## all until \\ or / is the path part of the file
                                               ## now the file can be given in several ways:
   [ **<?@allTree><*?ext>                      ## ** means: all files also in subfolders. The rest after** is extension.
   | *<?@someFiles><*?@ext>                    ## * means: Some files or placeholder for the name. The rest after * is extension. 
   | <stringtolastExclChar.?@file><*?@ext>     ## or a filename and a extension if a . is found
   | <*?@file>                                 ## or only a file if no . is found.
   ]<! *?>.

Mit <$NoWhiteSpaces> wird erstmal die Wirkung der Whitespaces in der Syntaxvorschrift ausgeschaltet. Es sind also nirgends Whitespaces zulässig. Aber am Anfang werden Leerzeichen überlesen, ausgedrückt mit dem RegularExpression <! *?>.

Danach kann ein beliebiges Zeichen folgen: RegularExpression <!.?@drive>. Wenn darauf ein : folgt, dann ist das eine Laufwerksangabe, im Xml als Attribut drive gespeichert. Folgt kein : nach einem Einzelzeichen, dann ist diese Simple-Option nicht erfüllt, es gibt keinen Laufwerksbuchstaben.

Alle danach folgenden Zeichen bis ausschließlich einem : werden als Attribut pathbase gespeichert. Danach muss ein : auch folgen. Ist das nicht der Fall, dann gibt es kein pathbase. Es wird getestet, dass der Inputtext keine Zeichenfolge := enthält, Das wäre eine Verwechslung des : mit dem : von :=.

Danach werden mit <stringtolastinclChar/\?@path> alle Zeichen eingelesen bis einschließlich dem letzten vorgefundenen / oder \. Das ist das Attribut path. Wird kein / oder \ gefunden. dann gibt es kein Attribut path, aber die Syntax ist ok.

Danach wird getestet, ob einer der Optionen passt:

  • Entweder es gibt die Folge **, dann wird das Attribut allTree erzeugt. Alle nachfolgenden Zeichen werden in ext gespeichert.

  • Oder es gibt ein einzelnes *. Dann wird das Attribut someFiles erzeugt. Alle nachfolgenden Zeichen werden in ext gespeichert. Das muss nicht unbedingt eine File-Extension beginnend mit einem Punkt sein, sondern kann auch ein Namensanteil nach dem * sein.

  • oder, wenn kein * gefunden wird, werden alle Zeichen bis ausschließlich dem letzten . als Attribute file gespeichert. Das Attribut file gibt es also nur, wenn kein * gefunden wird. Alles, was nach dem Punkt folgt, einschließlich des ., ist die ext.

Nachfolgende Leerzeichen werden akzeptiert und ignoriert.

1.3 Zerlegen der File-Pathes beim Parsen

Topic=.Zmake.internZbnf.FilePath.

TODO

1.4 Xml-Subroutine genTargetForEachInput

Topic=.Zmake.internZbnf.genTargetForEachInput.

Das <template name="genTargetForEachInput"> wird von mehreren Zmake-Routinen genutzt. Die gemeinsame Eigenschaft der Routinen ist, dass jeweils eine Konvertierung pro Sourcefile erfolgt. Als Targetfile wird entweder ein Verzeichnis oder eine Wildcard-Angabe erwartet. Das Template organisiert die Abarbeitung und ruft innen pro Sourcefile dann das als Parameter übergebene spezifisch benannte Template auf.

1.4.1 Anwendung

Topic=.Zmake.internZbnf.genTargetForEachInput..

Als Beispiel sei die Zmake-Routine file2Html() gegeben, die wie folgt in XSL-Script:_xsl/ZmakeStd.xslp programmiert ist:

 <xsl:template name="file2Html">
   <xsl:call-template name="genTargetForEachInput">
     <xsl:with-param name="genExecForEachInput" select="'exec_file2Html'" />
     <xsl:with-param name="xmlTool_srcFiles" >
       <srcfiles file="{'${env.XML_TOOLBASE}/Xslt.jar'}" />
     </xsl:with-param>
   </xsl:call-template>
 </xsl:template>

Übergeben werden die Parameter

  • genExecForEachInput: Name des Templates, dass die Generierungsbefehle für das ANT-Script generiert, siehe im fortlaufenden Text,

  • xmlTool_srcFiles: Ein XML-Baum mit <srcfiles...>-Elementen, die zusätzlich in den Abhängigkeitstest eingebaut werden sollen. Das sind typischerweise Tool-Files, bei deren Änderung ebenfalls neu generiert werden soll.

Dazu gehört das innen gerufene Template, dessen Name als Parameter genExecForEachInput übergeben wird:

 <xsl:template name="exec_file2Html">
 <xsl:param name="targetfile" />  
 <xsl:param name="srcfile" />
 <xsl:param name="xmlInputNode" />
 <xsl:param name="xmlTargetNode" />
   <echo message="gen HTML" />
   <exec dir="{$curDir}" executable= "java" failonerror="false">
     <xsl:variable name="i"><xsl:text>-i</xsl:text><xsl:value-of select="@srcpath" /><xsl:text>/</xsl:text><xsl:value-of select="@srcfile" /></xsl:variable>
     <xsl:variable name="o"><xsl:text>-o../html/</xsl:text><xsl:value-of select="@srcfile" /><xsl:value-of select="@dstext"/></xsl:variable>
     <arg line="{$Classpath}" />
     <arg line ="{'org.vishia.xml.Textfile2Html'}" />
     <arg line="{'-i'}{$srcfile}" />
     <arg line="{'-o'}{$targetfile}" />
   </exec>
 </xsl:template>

Mehr braucht man für diese Zmake-Routine nicht. Der Rest wird vom ..<template name="genTargetForEachInput"> erledigt.

Das innen gerufene Template bekommt die gezeigten Parameter aus den Informationen des jeweiligen Sourcefiles:

  • targetfile ist der fertig zusammengebaute Name des zu erzeugenden Files als Absolut-Path.

  • srcfile ist der fertig zusammengebaute Name des Sourcefiles als Absolut-Path.

  • xmlInputNode ist die Referenz auf die <input> oder <file>-Element, dass die Informationen zum Inputfile enthält.

  • xmlTargetNode ist die Referenz auf das <target>-Element der Zmake-Routine. Über dieses Element können Parameter eingelesen werden.

Bereits generiert ist pro Inputfile das Haupt-ANT-<target> mit ANT-<target name="isuptodate_... zwecks Test der Neuigkeit des Sourcefiles gegenüber dem Targetfile. Damit braucht in dem spezifisch zu schreibenden Template relativ wenig organisiert werden.

1.4.2 Realisierung

Topic=.Zmake.internZbnf.genTargetForEachInput..

Das Template beginnt wie folgt:

 <xsl:template name="genTargetForEachInput">
 <xsl:param name="genExecForEachInput" /><!-- name of the generateExec-Routine. -->
 <xsl:param name="xmlTool_srcFiles" /><!-- contains some <srcfiles ...> elements there are additinal to consider --> 
   <xsl:variable name="targetName"><xsl:call-template name="targetName" /></xsl:variable>
   <xsl:variable name="outputPre"><xsl:for-each select="output"><xsl:call-template name="pathPre" /></xsl:for-each></xsl:variable>
   <xsl:variable name="outputPost"><xsl:for-each select="output"><xsl:call-template name="pathPost" /></xsl:for-each></xsl:variable>
   <xsl:call-template name="evaluateInput">
     <xsl:with-param name="call" select="'genTargetForInput'" />
     <xsl:with-param name="p1" select="$targetName" /><!-- base for the some targets names -->
     <xsl:with-param name="p2" select="$outputPre" />
     <xsl:with-param name="p3" select="$outputPost" />
     <xsl:with-param name="p4" select="$genExecForEachInput" />
     <xsl:with-param name="p5" select="." /><!-- xmlTargetNode -->
     <xsl:with-param name="p6" select="$xmlTool_srcFiles" />
   </xsl:call-template>

Es wird also vermittels des template name="evaluateInput" pro Input folgendes Template gerufen, wobei die Parameter p1..05 durchgereicht werden:

 <xsl:template name="genTargetForInput">
 <xsl:param name="p1" /><!-- name of the superior target as basename -->
 <xsl:param name="p2" /><!-- pre-part to build the targetfile name with input file path/name.ext -->
 <xsl:param name="p3" /><!-- post-part,the targetfile name is built with p2+inputfilfile.ext+p3 -->
 <xsl:param name="p4" /><!-- name of the template to generate the ant.xml-code for the exec routine -->
 <xsl:param name="p5" /><!-- The xml target node of the Zmake Routine to get parameters -->
 <xsl:param name="p6" /><!-- additional uptodate src $xmlTool_srcFiles -->
   <xsl:variable name="targetName"><xsl:text>(?$p1?):(?@path?)(?@file?)(?@ext?)</xsl:text></xsl:variable>
   <xsl:variable name="targetUptodate"><xsl:value-of select="$targetName" />_isUptodate</xsl:variable>
   <xsl:variable name="targetfile"><xsl:text>(?$p2?)(?@path?)(?@file?)(?@ext?)(?$p3?)</xsl:text></xsl:variable>
   <xsl:variable name="srcfile"><xsl:call-template name="pathfile" /></xsl:variable>
   <target name="{$targetName}" 
     description="{'generate from ZmakeStd.xslp: genTargetForInput: '}{$p4}" 
     depends="{$targetUptodate}" unless="{$targetUptodate}">
     <saxon:call-template name="{$p4}">
       <xsl:with-param name="srcfile" select="$srcfile" />
       <xsl:with-param name="targetfile" select="$targetfile" />
       <xsl:with-param name="xmlInputNode" select="." />
       <xsl:with-param name="xmlTargetNode" select="$p5" />
     </saxon:call-template>
   </target>
   <target name="{$targetUptodate}">
     <uptodate property="{$targetUptodate}" targetfile="{$targetfile}">
       <srcfiles file="{$srcfile}" />
       <xsl:copy-of select="$p6" />
     </uptodate> 
   </target>
 </xsl:template>  

Dieses Template erzeugt als ANT.xml-Ausgabetext zwei <target>, eines zur Ausführung und eines für den Neuigkeitstest. Der targetName wird als Variable zusammengebaut, und zwar aus dem als p1 übergebenen Namen mit nachfolgendem PathFileExt des jeweiligen Inputfiles. Damit ist er eindeutig.

Der targetfile rekrutiert sich aus den Parametern p2 und p3, die übergeordnet aus dem Anteil des targetfile vor und nach einem Wildcard gewonnen werden, oder den Base-Path für die erzeugten Files und deren Extension entsprechen. Dazwischen steht als lokaler Pfad und Filename die Angaben aus den Srcfile.

Der Pfad des srcfile wird dagegen mit einer template-Routine gewonnen und ermittelt den Absolut-Pfad des srcfile. Dazu zählt ein möglicher Basepath und ein ${curDir}, falls der Pfad ansonsten relativ ist. Diese Parameter werden die inneren Routine übergeben und dienen auch als Bausteine für das <target name="{$targetUptodate}">.

Das hier gebaute <target name="{$targetName}" hat innen eine Abfolge, die mit dem vom Anwender bereitgestelltem Template gebaut wird und damit den spezifisch Anteil produziert. Das Anwender-Template wird per Zeichenkette in einer Variablen, $p4, gerufen. Das geht nicht mehr mit den Standard-XSLT-Mitteln sondern benötigt eine Saxon-Erweiterung, die hoffentlich in zukünftigen XSLT-Versionen als Standard verfügbar sein wird. Damit kann als XSLT-Translator nur SAXON (http://www.saxonica.com) von Michael Kay verwendet werden. Das ist aber nicht störend, da Michael Kay selbst im w3c-Konsortium beim XSLT 2.0-Standard wesentlich mitgewirkt hat (das ist also kein propritärer Selbstbau) und den Standard-XSLT-Translator ohne Kosten per Download bereitstellt. Versionen gibt es sogar für die dot-net-Welt.

Im oben begonnenen <xsl:template name="genTargetForEachInput"> geht es aber weiter:

   <xsl:variable name="targetUptodate"><xsl:value-of select="$targetName" />_isUptodate</xsl:variable>
   <xsl:variable name="targetfile"><xsl:text>(?call pathfile:"output"()?)</xsl:text></xsl:variable>
   <target name="{$targetName}" 
     description="{'generate from genTargetForEachInput: '}{$genExecForEachInput}" 
     unless="{$targetUptodate}">
     <xsl:variable name="depends">
       <xsl:call-template name="evaluateInput">
         <xsl:with-param name="call" select="'genDependsToTarget-dependsInput'" />
         <xsl:with-param name="p1" select="$targetName" /><!-- base for the some targets names -->
       </xsl:call-template>
     </xsl:variable>
     <xsl:attribute name="depends"><xsl:text>(?$depends?)(?$targetUptodate?)</xsl:text></xsl:attribute>
   </target>
   <target name="{$targetUptodate}">
     <uptodate property="{$targetUptodate}" targetfile="{$targetfile}">
       <xsl:call-template name="evaluateInput">
         <xsl:with-param name="call" select="'uptodateSource'" />
       </xsl:call-template>
       <xsl:copy-of select="$xmlTool_srcFiles" />
     </uptodate> 
   </target>
   <!-- xxx -->
 </xsl:template>

Im zweiten Teil werden zwei gemeinsame Targets gebaut. Im ersten wird per depends organisiert, dass auch die <target> pro Srcfile aufgerufen werden. Im zweiten <target> wird ein Uptodate-Test für alle Files ...TODO das ist unnötig. Das Target wird aber im depends verlangt, einfach weglassen, dann steht hinten ein Komma. Muss man noch was übergeordnetes tun? Tool-Files aufbereitsen, mit zusätzlichem Input-Paramter?