Headerfiles, Bedeutung, Daten herauslesen

Headerfiles, Bedeutung, Daten herauslesen

Inhalt


Topic:.Jc.Cheader.

Last changed: 2018-01-07

Headerfiles liefern als Teil der C-Compilierung eigentlich nur die beim Compilieren notwendigen gemeinsamen Teile, also vorderhand die Definition externer Labels, die vom Linker in anderen Compilierungseinheiten oder Libraries aufzufinden sind. Dazu kommt die struct-Definition gemeinsam notwendiger Daten. Im C++-Bereich sieht es nicht anders aus, nur statt struct class und Definition der Methoden innerhalb der class.

So sehen auch Headerfiles häufig aus, kurz, durchsetzt mit #ifdef für die verschiedenen zu berücksichtigenden Varianten, Comment-frei.

Headerfiles stellen sachlich aber das Interface einer Compilierungseinheit nach außen dar. Dort ist deklariert, was die Compilierungseinheit leistet, wie man sie einsetzen kann. Wenn man diesem Gedankengang folgt, dann sollten Headerfiles wie folgt strukturiert sein:

Damit gewinnen aber Headerfiles an Bedeutung für den Software-Entwicklungsprozess: Dokumentation und Strukturierung. Mehr noch: Headerfiles sind einsetzbar beispielsweise zur Beschreibung der Daten auf Kommunikationsleitungen, unabhängig davon ob nach außen die C-Programmierung direkt verwendet wird (häufig nur innen, in der Realisierungsebene verwendet).


1 Dokumentationsstil

Topic:.Jc.Cheader..

Der Dokumenationsstil ist nirgends festgeschrieben. Man sollte sich aber an Standards halten. Verbreitet sind bestimmte Default-Styles, die mit Doxygen sich für Header etabliert haben. Allerdings nicht einheitlich. Schaut man dagegen in einem Seitenblick auf Java, dann gibt es dort eine vollkommen einheitliche Art der Dokumentation. Diese lässt sich problemlos auch in Headerfiles anwenden und wird mit den gezielten Einstellungen auch von Doxygen erkannt. Nachfolgend das Muster:

/**This struct is used for ...
 * Details
 */
typedef struct MyStruct_t
{
  /**Meaning of the element. */
  int32_t data_xy;
} MyStruct;
/**This operation is used for...
 * @param arg1 argument for...
 * @return the number of...
 */
int doSomething_MyStruct(MyStruct* thiz, int arg1);

In dem Muster ist neben dem Javadoc-Stil folgendes auffällig und empfehlenswert:


2 Parsen der Header mit Cheader.zbnf

Topic:.Jc.Cheader.zbnf.

Der ZBNF-Parser ist seit 2005 nur mit kleineren Erweiterungen in Verwendung unter anderem für das Parsen von Inputtexten auch dieser Dokumentation, für Java-Programme innerhalb des Java2C-Translators, für JZtxtcmd-Scripts und eben auch für Headerfiles. Die seit Anfang benutzte Syntax ist im File zbnfjax:zbnf/Cheader.zbnf verankert.

Für die Syntax in Cheader.zbnf gelten folgende Prämissen:

Trotz dieser Prämissen sollten jegliche ordentlich geschriebene Headerfiles (ohne strukturzerstörende Makros) geparst werden können. Bestimmte zielgerichtet zweckmäßige Makros oder doch nicht berücksichtigte Syntaxmöglichkeiten der C(++-Programmierung können mit Erweiterung der Syntax in Cheader.zbnf berücksichtigt werden.


3 Ablage der geparsten Daten

Topic:.Jc.Cheader..

Es gibt hierbei 3 Möglichkeiten:

Es liegt nun nahe für eigene Arbeiten das dritte Verfahren zu verwenden, wenn man nicht Java programmieren möchte oder XML im Auge hat. Das dritte Verfahren legt die Daten in einer Instanz von srcJava_Zbnf/org/vishia/header2Reflection/CheaderParser mit seinen Subclass-Instanzen als Baum ab. Man kann diese Daten dann direkt in einem JZtxtcmd-Script herauslesen und passend ein Output-Textfile zusammensetzen. Die Java-class CheaderParser muss für alle Semantik-Ergebnisse auch entsprechende Ziel-Elemente haben. Diese werden per Reflection mittels der Java-Funktionalität aufgesucht. Wird ein Zielelement nicht gefunden, dann gibt es eine Klartextfehlermeldung. Diese kann genutzt werden, um die noch fehlende Ziel-Elemente einzubringen. Das ist der Stand 2018-01.

Es gibt eine weitere Überlegung, die im Moment(2018-01) noch nicht realisiert ist:

Kontrolle der abgelegten Daten:

Über die Funktion srcJava_vishiaBase/org/vishia/cmd/JZtxtcmdTester#dataHtml(java.lang.Object, org.vishia.cmd.JZtxtcmdFilepath) oder aus Java gerufen mit der class srcJava_vishiaBase/org/vishia/util/DataShow kann der Inhalt einer Java-Instanz mit allen referenzierten Daten als html ausgegeben werden. Damit ist eine manuelle Navigation in den Daten möglich, insbesondere für Datenpfade für das JZtxtcmd-Script.


4 Reflectiongenerierung mit JZtxtcmd-Script

Topic:.Jc.Cheader..

Die Reflectiongenerierung in der CRuntimeJavalike wird ab 2018-01 successive auf die hier vorgestellte Variante umgestellt. Das Start-Script, beispielsweise für ...vishia/Jc/CRuntimeJavalike/make/genRefl_FwcJc.jz.cmd sieht wie folgt aus:

REM start problem: The batch needs the zbnf.jar File. Either the ZBNFJAX_HOME environment variable is set already,
REM or it is set via a found setZBNFJAX_HOME.bat, or it is on D:\vishia... or you should adapt it.
call setZBNFJAX_HOME.bat
if "%ZBNFJAX_HOME%" == "" set ZBNFJAX_HOME=D:/vishia/ZBNF/zbnfjax
java -cp %ZBNFJAX_HOME%/zbnf.jar org.vishia.jztxtcmd.JZtxtcmd %0
if ERRORLEVEL 1 pause
exit /B
==JZtxtcmd==
include $ZBNFJAX_HOME/jzTc/Cheader2Refl.jztxt.cmd;
currdir=scriptdir;
Fileset headers =
( source:Fwc/*.h
, source:Jc/*.h
);
main()
{
  mkdir T:/header/Jc;
  zmake "../genRefl/*.crefl" := genReflection(..&headers, html="T:/header");
  <+out>success<.+n>
}

Es ist eine Kombination aus batch-File (Windows) und JZtxtcmd-Script. Letzteres ist ein Zmake-Script. Es werden die Header im Fileset benannt. Die Arbeit wird dann im includiertem Script ...zbnfjax/jzTc/Cheader2Refl.jztxt.cmd ausgeführt. Die html-Ausgabe wird hier bestimmt oder abgeschaltet (html-Argument weglassen).

Der Kern des JZtxtcmd-Scripts für das einzelne Parsen der Header sieht dann wie folgt aus:

Obj headerTranslator = java new org.vishia.header2Reflection.CheaderParser(console);

sub genReflectionFile(Obj filepath :org.vishia.cmd.JZtxtcmdFilepath, String fileRefl, String html = null)
{
 ##java org.vishia.util.DataAccess.debugMethod("setSrc");
 Obj args = java new org.vishia.header2Reflection.CheaderParser$Args();
 args.addSrc(filepath.absfile(), filepath.localname());
 args.setZbnfHeader(<:><&scriptdir>/../zbnf/Cheader.zbnf<.>);

 Obj headers = headerTranslator.execute(args);

 for(headerfile: headers.files){
   <+out>generate <&headerfile.fileName> <.+n>
   ##Only to help change the script, output all parsed data:
   if(html !=null && html.length()>0) {
     <+out>html: <&html>/<&headerfile.fileName><.+n>
     mkdir <:><&html>/<&headerfile.fileName>'<.>;
     test.dataHtml(headers, File:<:><&html>/<&headerfile.fileName>.html<.>);
   }
   call genReflectionHeader(headerfile = headerfile, fileRefl = fileRefl);
 }
}

Die Instanz des headerTranslator ist global im Script angelegt. Sie wird wiederverwendet. Diese Subroutine im Script wird mit den einzelnen bereits separierten Files gerufen, also mehrfach. Der Filename wird in die angelegte args-Variable geschrieben. Der CheaderParser kann mehrere Files verarbeiten, verarbeitet hier aber nur einen. Damit ist die for...-Schleife singular, sie holt die einzige headerfile-Instanz aus dem Container headers.files heraus.

In diesem Script wird die html-Testausgabe gezeigt. Die Reflectiongenerierung erfolgt dann mit der danach gerufenen Subroutine.