Marcel Schaible - 2024-06-03

Table of Contents

  1. Präprozessor
    1. Präprozessor-Anweisungen
      1. Die Präprozessoranweisung #DEFINE
      2. Objekt-ähnliche Makros
      3. Funktions-ähnliche Makros
      4. Erstellen von Zeichenketten
      5. Konkatenation von Zeichenketten
      6. Vordefinierte Makros
      7. Die Präprozessoranweisung #UNDEF
      8. Die Präprozessoranweisung #INCLUDE
      9. Die Präprozessoranweisung #IF
      10. Die Präprozessoranweisung #IFDEF
      11. Die Präprozessoranweisung #IFUDEF

Präprozessor

Der Präprozessor führt Transformationen an dem OpenPEARL Quelltext aus
und übergibt diese danach an den Übersetzer.

Präprozessor-Anweisungen

Präprozessoranweisungen müssen stets am Zeilenanfang stehen und dürfen
bei Bedarf um zu Beispiel eine bessere Strukturierung zu erreichen,
eingerückt werden.

Die Anweisungen richten sich weitgehend an denen aus RTOS-UH bekannten
Befehlen aus. Die bei RTOS-UH notwendige Abschluss einer Anweisung mit
einem Semikolon ist beim OpenPEARL-Präprozessor optional.

Anweisung Funktion
#DEFINE Definiere eine benamte Konstante
#ENDEF Schließt einen #DEFINE-Block ab
#UNDEF Undefiniere eine definierte Konstante
#INCLUDE Bette eine Datei ein
#IF Compiliere Folgetext wenn Bedingung nicht Null ergibt
#IFDEF Compiliere Folgetext wenn Objekt existiert
#IFUDEF Compiliere Folgetext wenn Objekt nicht existiert
#ELSE Alternativer Zweig zum #IF
#FIN Schließt das letzte #IF ab

DONE Die Präprozessoranweisung #DEFINE

Die Präprozessoranweisung #DEFINE definiert ein Makro.
Dabei werden folgende zwei Alternativen unterschieden:

Objekt-ähnliche Makros

Ein objekt-ähnliches Makro defineirt einen Bezeichner, welcher im
nachfolgenden Quellcode durch das Code-Fragment ersetzt wird.

#DEFINE <id> <text>;

Das abschliessende Semikolon ist optional.

Diese Art von Makros wird oft dazu verwendet, numerischen Konstanten
eine sprechenden namen zu geben:

Beispiel:

#DEFINE NO_OF_ELEMENTS 42;

Funktions-ähnliche Makros

Funktions-ähnliche Makros sehen aus wie gewöhnliche Prozeduraufrufe,
werden jedoch zur Übersetzungszeit ausgeführt.

#DEFINE <id> (<param-list>);
    <text>
#ENDEF;

Die abschliessenden Semikola sind optional.

Beispiel:

#DEFINE ASSERT(expr)
  IF NOT (expr) THEN
    PUT 'ASSERTION FAILED' TO CONSOLE;
  FIN;  
#ENDEF

Dieses Makro wird wie folgt umgesetzt:

ASSERT(var < 10);

->

IF NOT (var < 10) THEN
   PUT 'ASSERTION FAILED' TO CONSOLE;
FIN;

DONE Erstellen von Zeichenketten

Oft ist es notendig ein Makro-Argument in eine Zeichenkette
umzuwandeln. Dies kann mittels dem #-Operator erfolgen. Wird ein
Makroargument mit einem führenden # verwendet, so wird dieses mit
der Zeichenkette ersetzt.

Beispiel:

#DEFINE warn_if(expr)
  IF (expr) THEN
    PUT 'WARNING: ', #expr TO CONSOLE BY A,A;
  FIN;
#ENDEF

DONE Konkatenation von Zeichenketten

Es ist oft sinnvoll beim Expandieren eines Makros zwei Argumente zu
konkatinieren. Hierzu wird der ##-Operator eingesetzt:

Beispiel:

#DEFINE cmd(name)
   name ## _test()
#ENDEF

Der Aufruf cmd(add) erzeugt folgenden Text:

add_test()

DONE Vordefinierte Makros

Folgende Makros sind vordefiniert:

Makro Bedeutung
__FILE_NAME__ Dieses Makros wird zu dem aktuellen Dateinamen expandiert.

DONE Die Präprozessoranweisung #UNDEF

Die Präprozessoransweisung #UNDEF undefiniert ein vorher
definiertes Makro.

#UNDEF <id>;

Falls <id> nicht vorhanden ist, wird eine Warnung generiert.

Das abschliessende Semikolon ist optional.

DONE Die Präprozessoranweisung #INCLUDE

Mittels der Präprozessoranweisung #INCLUDE wird weitere Quelldatei
eingefügt.

#INCLUDE <file>;

Hierbei wird <file> als Zeichenkette behandelt und darin enthaltene
Kommentare werden nicht herausgefiltert.

Das abschliessende Semikolon ist optional.

Folgt nach dem Dateinamen außer einem Semikolon oder eines
Kommentares, so wird dieses als Fehler betrachtet.

DONE Die Präprozessoranweisung #IF

Die Präprozessoranweisung 'IF' wertet einen =FIXED-Ausdruck aus
fügt, falls dieser nicht Null ergibt, fügt die Textzeilen A
ansonsten die Textzeilen B ein. Der #ELSE-Zweig ist optional.

#IF <fixed-expression>;
 Text A
#ELSE;
 Text B
#FIN;

Die abschliessenden Semikola sind optional.

DONE Die Präprozessoranweisung #IFDEF

Mittels der Präprozessoranweisung #IFDEF wird geprüft, ob das Makro <id>
definiert ist und falls ja, werden die Textzeilen A eingefügt
ansonsten die Textzeilen B. Der #ELSE-Zweig ist optional.

#IFDEF <id>;
 Text A
#ELSE;
 Text B
#FIN;

Die abschliessenden Semikola sind optional.

DONE Die Präprozessoranweisung #IFUDEF

TestMerged.prl war mein Entwicklungsversuch so etwas wie Googletests
nachzubauen. Dieses Programm sollte bei dir schon laufen.

Daraus abgeleitet: TestFramework.system und TestFramework.problem mit
den Einträgen im SYSTEM- und PROBLEM-Teil. Falls wir mehrere SYSTEM
und PROBLEM-Teile in einem Modul zuliessen, dann könnten diese beiden
zusammenfallen.

Test.prl wäre dann die eigentliche Testanwendung

Welche Notation für die Verwendung von Makroparametern muss noch
geklärt werden, sodass es einfach zu implementieren ist. Die Notation
mit BEGIN/END könnte kritisch werden, wenn in einem Macro auch ein
END stehen sollte.

Mit den Signalen muss ich noch ein paar Kleinigkeiten im Sprachreport
und Kontrollflussgrafen fertigstellen.

#DEFINE TEST(partition, test) 
  #partition\ 5F \#test: PROC RETURNS(FIXED);
#ENDDEF

Die Präprozessoranweisung #IFUDEF verhält sich ähnlich wie #IFDEF* mit dem Unterschiede, dass geprüft wird , ob das Makro =<id> nicht
definiert ist und falls ja, werden die Textzeilen A eingefügt
ansonsten die Textzeilen B. Der #ELSE-Zweig ist optional.

#IFUDEF <id>;
 Text A
#ELSE;
 Text B
#FIN;

Die abschliessenden Semikola sind optional.