Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Preprozessor-Anweisungen |
Bartels User Language - Programmierhandbuch2.6 Preprozessor-Anweisungen |
Der
Bartels User Language Compiler kann spezielle Preprozessor-Anweisungen zur Steuerung der Quelltextabarbeitung verarbeiten. Derartige Anweisungen beginnen mit dem Zeichen
#
und werden durch das Zeilenende begrenzt. Preprozessor-Anweisungen sind an beliebigen Stellen des Quelltextes zulässig; ihr Wirkungsbereich erstreckt sich bis zum Ende des jeweiligen Quelltextes.
Im Sprachumfang der
User Language ist die aus Standard C bekannte
#include
-Anweisung enthalten. Die
#include
-Anweisung dient dazu, Deklarationen und Funktionen, die in unterschiedlichen Programmen identisch verwendet werden und in einer gesonderten Includedatei abgelegt sind, in die gewünschten Quelldateien einzubinden. Dadurch lässt sich der Aufwand für die Entwicklung und Pflege von
User Language-Programmen erheblich reduzieren (eine in verschiedenen Programmen benötigte Funktion muss nur einmal im Quelltext definiert werden). Die Syntax für die
#include
-Anweisung lautet:
#include "filename" EOLN
Die
#include
-Anweisung sorgt dafür, dass der
User Language Compiler an dieser Stelle mit der Kompilierung der in der
#include
-Anweisung angegebenen Quellcode-Datei beginnt. Diese Anweisung wird durch das Zeilenende abgeschlossen. Ist das Dateiende der Includedatei erreicht, dann wird der Übersetzungsvorgang an der der
#include
-Anweisung nachfolgenden Anweisung fortgesetzt. Innerhalb einer Includedatei sind wiederum
#include
-Anweisungen zulässig, sofern sich dadurch keine Mehrfachbearbeitung identischer Quellcodedateien (Datenrekursion!) ergibt. Bei der Verwendung von
#include
-Anweisungen ist zu berücksichtigen, dass bestimmte Teile der eingebundenen Includedateien in dem jeweiligen Programm u.U. gar nicht benötigt werden. Man sollte beim Compilerlauf daher in jedem Fall den Optimierer aktivieren, um redundante Programmteile zu eliminieren. Das folgende Beispiel zeigt das Include-File
baecall.ulh mit der Routine
call
zur Aktivierung von
AutoEngineer-Menüfunktionen:
// baecall.ulh -- BAE menu call facilities void call(int menuitem) // Call a BAE menu function { // Perform the BAE menu call if (bae_callmenu(menuitem)) { // Error; print error message and exit from program perror("BAE menu call fault!"); exit(-1); } }
Das folgende Beispiel zeigt den Source-Code für das Programm
zoomall zur Ausführung des
-Kommandos im
AutoEngineer; hierbei wird die über das Include-File
baecall.ulh eingebundene Routine
call
verwendet:
// ZOOMALL -- Call the BAE Zoom All command #include "baecall.ulh" // BAE menu call include main() { // Call Zoom All call(101); }
Eine Preprozessor-Anweisung der Form
#define IDENT constexpr EOLN
sorgt dafür, dass im nachfolgenden Programmtext der über IDENT spezifizierte Identifier jeweils durch den Wert des konstanten Ausdrucks (constexpr) ersetzt wird. Die Anweisung wird durch das Zeilenende abgeschlossen. Diese Anweisung eignet sich insbesondere zur Definition wesentlicher Konstanten.
Die Gültigkeit der Konstantendefinition erstreckt sich bis zum Ende des Programmtextes, sofern die Definition nicht vorher durch eine Preprozessor-Anweisung der Form
#undef IDENT EOLN
gelöscht wird.
Eine besondere Form der
#define
-Anweisung ist durch die Syntax
#define IDENT EOLN
gegeben. Hierbei wird lediglich ein Name definiert, dessen Existenz durch die Preprozessor-Anweisungen
#ifdef
bzw.
#ifndef
abgefragt werden kann (siehe hierzu Kapitel 2.6.3).
Typische Beispiele für die Verwendung der
#define
-Anweisung sind:
#define DDBCLASSLAYOUT 100 #define mmtoinch 25.4 #define inchtomm 1.0/mmtoinch #define REPABORT "Operation aborted." #define ERRCLASS "Operation not allowed for this element!" #define GERMAN 1 #define ENGLISH 0 #define LANGUAGE GERMAN #define DEBUG
Eine Preprozessor-Anweisung der Form
#if constexpr EOLN
überprüft, ob der angegebene konstante Ausdruck einen von Null verschiedenen Wert besitzt. Eine Preprozessor-Anweisung der Form
#ifdef IDENT EOLN
überprüft, ob der über den Identifier spezifizierte Name (durch eine
#define
-Anweisung) definiert ist. Eine Preprozessor-Anweisung der Form
#ifndef IDENT EOLN
überprüft, ob der über den Identifier spezifizierte Name unbekannt ist.
Die auf
#if
,
#ifdef
bzw.
#ifndef
folgenden Zeilen des Programmtextes werden nur dann übersetzt, wenn die entsprechende Bedingung erfüllt. Ansonsten wird der entsprechenden Programmteil lediglich auf korrekte Syntax geprüft.
Auf eine If-Preprozessor-Anweisung kann optional eine Prepozessor-Anweisung der Form
#else EOLN
folgen. Durch eine Preprozessor-Anweisung der Form
#endif EOLN
wird die entsprechende If-Konstruktion abgeschlossen. Wenn die
If-Bedingung erfüllt ist, dann werden alle Zeilen zwischen
#else
und
#endif
von der eigentlichen Übersetzung ausgenommen. Ist die If-Bedingung nicht erfüllt, dann wird der Programmteil zwischen der If-Anweisung und
#else
(oder in dessen Abwesenheit
#endif
) von der Übersetzung ausgenommen. Derartige If-Preprozessor-Konstruktionen dürfen verschachtelt sein.
Das folgende Beispiel illustriert die Möglichkeiten der bedingten Übersetzung:
#define ENGLISH 0 #define GERMAN 1 #define LANGUAGE ENGLISH #if LANGUAGE == GERMAN #define MSGSTART "Programm gestartet." #endif #if LANGUAGE == ENGLISH #define MSGSTART "Program started." #endif #define DEBUG main() { #ifdef DEBUG perror(MSGSTART); #endif : }
In die Bartels User Language ist ein BNF-Precompiler zur Realisierung von Interface-Programmen für die Bearbeitung von Fremddatenformaten integriert. Unter Verwendung der zugehörigen Scanner- und Parserfunktionen lassen sich in einfacher und eleganter Weise Programme zur Verarbeitung praktisch beliebiger ASCII-Datenformate implementieren.
Jeder User Language-Programmtext darf eine Preprozessor-Anweisung der Form
#bnf { ... }
enthalten. Das
#bnf
-Statement darf sich über beliebig viele Zeilen des Quelltextes erstrecken. Diese Anweisung aktiviert den BNF-Precompiler des
Bartels User Language Compilers. BNF (Backus Naur Form) ist ein Formalismus zur Beschreibung der Syntax einer Sprache. Die BNF-Definition (innerhalb der geschweiften Klammern des
#bnf
-Statements) einer Sprache besteht aus einer Folge von Regeln durch die die Grammatik der Sprache (d.h. die in dieser Sprache gültigen Folgen von Worten bzw. Zeichen zur Bildung von Sätzen) festgelegt wird. In der BNF-Notation besteht eine Regel aus einem eindeutigen Grammatikbegriff (non-terminal symbol), dem über den Doppelpunkt-Operator
:
(zu lesen als "besteht aus") eine Folge von einer oder mehreren alternativen (durch das Zeichen
|
voneinander getrennten) Formulierungen zugewiesen wird. Eine Formulierung wiederum besteht aus einer Folge von Grammatikbegriffen und Eingabesymbolen (terminal symbols), wobei auch leere Formulierungen zulässig sind. Der Grammatikbegriff der ersten Regel einer BNF-Definition wird als Startsymbol bezeichnet. Durch die rekursive Verwendung von Grammatikbegriffen innerhalb der Regeln lassen sich unendlich viele bzw. unendlich lange zulässige Sätze definieren. Die Definition einer jeden Regel ist durch einen Strichpunkt
;
abzuschließen.
Die in der BNF-Definition angegebenen Terminalsymbole definieren den Wortschatz, d.h. die Menge der zulässigen Worte der Sprache. Hierbei kennzeichnen die Schlüsselwörter
IDENT
(Identifier),
NUMBER
(numerische Konstante),
SQSTR
(Single Quoted String, Zeichenkette in einfachen Anführungszeichen),
DQSTR
(Double Quoted String, Zeichenkette in Doppelten Anführungszeichen),
EOLN
(End Of Line, Zeilenende
\n
),
EOF
(End Of File; Dateiende bzw. End of String bei der Abarbeitung von Zeichenketten),
EOFINC
(End Of Include File, Ende Dateieinbindung) und
UNKNOWN
(nicht explizit definierte Sonderzeichenketten) nicht näher spezifizierte Terminalsymbole aus den entsprechenden Wortklassen. Die Spezifikation spezieller, anwendungsspezifischer Terminalsymbole geschieht durch die Angabe der entsprechenden Zeichenketten in Anführungszeichen, wobei der BNF-Precompiler automatisch eine Unterteilung in reservierte Worte (Schlüsselwort, Keyword; Identifier bestehend aus mindestens 3 Zeichen) und Operatoren (Single Character Operatoren bestehend aus einem Sonderzeichen bzw. Double Character Operatoren bestehend aus zwei Sonderzeichen) vornimmt.
Beispiele für die Spezifikation von Schlüsselwörtern sind:
"SECTION" 'ENDSEC' 'Inch' 'begin' "end" 'include'
Beispiele für die Spezifikation von Double Character Operatoren sind:
'<=' '++' "&&" "+=" '::' ':='
Beispiele für die Spezifikation von Single Character Operatoren sind:
'+' '-' "*" "/" "=" "[" "}" '#' '.'
Zwischenräume (Leerzeichen, Tabulatoren, Zeilentrenner) sind üblicherweise bei der Definition einer Grammatik nicht signifikant; sie dienen lediglich der Trennung von benachbarten Symbolen. Auch Kommentare stellen letztendlich nichts anderes als Zwischenräume dar. Von Bedeutung ist in in diesem Zusammenhang lediglich die Definition entsprechender Kommentarbegrenzungs-Operatoren.
Per Default trägt der BNF-Precompiler hierfür die Operatoren
/*
(Kommentarstart) und
*/
(Kommentarende) für zeilenübergreifende Kommentare ein. Diese Zuordnung lässt sich mit Hilfe eines speziellen Kommandos am Beginn der BNF-Definition ändern. Die diesbezügliche Anweisung für die Defaulteinstellung lautet wie folgt:
COMMENT ('/*', '*/');
Durch die Angabe nur eines Kommentarbegrenzungsoperators wie z.B. in
COMMENT ('//');
werden Kommentare konfiguriert, die sich bis zum Zeilenende erstrecken. Es ist zu beachten, dass die Kommentardefaulteinstellung verloren geht, sobald auch nur eine
COMMENT
-Anweisung in die BNF-Definition eingetragen wird. Will man also z.B. sowohl
/*
und
*/
für zeilenübergreifende Kommentare als auch den Operator
//
für Kommentare bis zum Zeilenende definieren, dann sind explizit die folgenden beiden
COMMENT
-Anweisungen am Beginn der BNF-Definition einzutragen:
COMMENT ('/*', '*/'); COMMENT ('//');
Eine Besonderheit des
Bartels User Language BNF-Precompilers besteht darin, dass zu jedem in einer Formulierung aufgeführten Grammatikbegriff bzw. Eingabesymbol optional eine Aktion definiert werden kann. Die Definition einer Aktion besteht aus der in runden Klammern
((
und
)
) eingeschlossenen Angabe einer
User Language-Anwenderfunktion, die bei Erkennung des entsprechenden Symbols auszulösen ist. Per Konvention müssen diese Anwenderfunktionen vom Datentyp
int
sein; der Rückgabewert einer solchen Funktion muss Null sein, wenn kein Fehler aufgetreten ist, und (-1) im anderen Fall. Optional ist ein Parameter vom Datentyp
int
zulässig, welcher in der BNF-Definition als Konstante in runden Klammern nach dem Funktionsnamen anzugeben ist.
Die exakte Definition der Syntax der BNF-Notation ist in der Syntaxdefinition der Bartels User Language (siehe Kapitel 2.7) enthalten.
Der BNF-Precompiler übersetzt die BNF-Definition in User Language-Maschinencode, der eine State-Maschine zur Abarbeitung eines Textes in der definierten Sprache festlegt. Zur Aktivierung dieser State-Maschine stehen die User Language-Systemfunktionen synparsefile und synparsestring zur Verfügung. Die Funktion synparsefile aktiviert einen Parser zur Abarbeitung einer durch Dateinamen spezifizierten Eingabedatei während mit der Funktion synparsestring eine Zeichenkette anstelle eines Dateiinhaltes abgearbeitet werden kann. Beide Funktionen lösen nach Bedarf automatisch die definierten Aktionen bzw. Anwenderfunktionen aus. Innerhalb dieser Anwenderfunktionen kann mit der Systemfunktion synscanline die aktuelle Zeilennummer der Eingabedatei und mit synscanstring die aktuell eingelesene Zeichenkette ermittelt werden, wobei die aktuelle Zeichenkette nach Bedarf auch einer semantischen Prüfung unterzogen werden kann. Die Funktionen synparsefile bzw. synparsestring werden beendet, sobald das Ende der Eingabedatei bzw. des abzuarbeitenden Strings erreicht ist oder ein Syntaxfehler (bzw. ein durch eine Anwenderfunktion erkannter semantischer Fehler) aufgetreten ist.
Der Vollständigkeit halber sei an dieser Stelle noch auf die Systemfunktionen
synscaneoln,
synscanigncase und
synparseincfile hingewiesen. Mit der Scannerfunktion
synscaneoln kann die Zeilenendeerkennung des BNF-Parsers aktiviert bzw. deaktiviert werden (default: Zeilenendeerkennung deaktiviert). Die Verwendung des Terminalsymbols
EOLN
in der BNF-Definition ist demnach nur sinnvoll bzw. zulässig, wenn für die Dateibearbeitung auch die Zeilenendeerkennung aktiviert wird. Mit der Scannerfunktion
synscanigncase kann die per Default aktivierte Unterscheidung zwischen Groß- und Kleinschreibung bei der Schlüsselworterkennung deaktiviert bzw. wieder aktiviert werden. Mit der Parserfunktion
synparseincfile wird die Bearbeitung einer eingebundenen Datei (Includedatei) aktiviert, d.h. der Parser setzt bei Aufruf dieser Funktion den Einlesevorgang unmittelbar am Beginn der namentlich spezifizierten Includedatei fort. Sobald das Ende der Includedatei erreicht ist, wird das
EOFINC
Terminalsymbol als erkannt gemeldet, und der Einlesevorgang wird an der in der übergeordneten Datei unterbrochenen Stelle fortgesetzt. Bei Verwendung der Funktion
synparseincfile ist demnach auch eine entsprechende Einbindung des Terminalsymbols
EOFINC
in die BNF-Definition erforderlich (andernfalls ist dieses Terminalsymbol obsolet).
Die genauen Beschreibungen der Scanner- und Parserfunktionen finden sich im Anhang C.
Die Funktionalität des BNF-Precompilers soll an dieser Stelle anhand eines Beispiels zur Übernahme von Bauteil-Platzierungsdaten in das aktuell im Layouteditor geladene Layout verdeutlicht werden. Die Eingabedaten sollen dabei nach folgendem Schema aufgebaut sein:
// This is a comment @ LAYOUT # This is a comment extending to the end of line UNITS { LENGTH = ( 1.0 INCH ) ; ANGLE = ( 1.0 DEGREE ) ; } PLACEMENT { 'ic1' : 'dil16' { POSITION = (0.000,0.000) ; ROTATION = 0.000 ; MIRROR = 0 ; } 'ic2' : 'dil16' { POSITION = (2.250,0.100) ; } 'ic3' : 'dil16' { POSITION = (1.000,0.394) ; ROTATION = 23.500 ; } 'ic4' : 'so16' { POSITION = (0.000,0.700) ; ROTATION = 0.000 ; MIRROR = 1 ; } } END
Das Programm zum Einlesen von Platzierungsdaten aus externen Dateien gemäß obigem Beispiel kann unter Verwendung des BNF-Precompilers und der Scanner- und Parserfunktionen auf folgende Weise implementiert werden:
// READLPLC -- Read Layout Placement from ASCII File //_________________________________________________________ // BNF input syntax definition #bnf { COMMENT ("//", "@") ; COMMENT ("#") ; placefile : "LAYOUT" placeunits placedata "END" ; placeunits : "UNITS" "{" "LENGTH" "=" "(" floatnum placelengthunit ")" ";" "ANGLE" "=" "(" floatnum placeangleunit ")" ";" "}" ; placelengthunit : "INCH" (p_unitl(1)) | "MM" (p_unitl(2)) | "MIL" (p_unitl(3)) ; placeangleunit : "DEGREE" (p_unita(1)) | "RAD" (p_unita(2)) ; placedata : "PLACEMENT" "{" placecommands "}" ; placecommands : placecommands placecommand | ; placecommand : identifier (p_pname) ":" identifier (p_plname) "{" placepos placerot placemirror "}" (p_storepart) ; placepos : "POSITION" "=" "(" floatnum (p_px) "," floatnum (p_py) ")" ";" ; placerot : "ROTATION" "=" floatnum (p_pa) ";" | ; placemirror : "MIRROR" "=" NUMBER (p_pm) ";" | ; identifier : SQSTR (p_ident) ; floatnum : NUMBER (p_fltnum(0)) | "-" NUMBER (p_fltnum(1)) ; } //______________________________________________________________ // Globals double plannx=bae_planwsnx(); // Element origin X coordinate double planny=bae_planwsny(); // Element origin Y coordinate double lenconv; // Length conversion factor double angconv; // Angle conversion factor string curpn; // Current part name string curpln; // Current physical library name double curx,cury; // Current coordinates double cura = 0.0; // Current angle (default: 0.0) int curm = 0; // Current mirror flag (default: 0) string curid; // Current identifier double curflt; // Current float value struct partdes { // Part descriptor string pn; // Part name string pln; // Physical library name double x,y; // Coordinates double a; // Angle int m; // Mirror flag } pl[]; // Part list int pn=0; // Part count //______________________________________________________________ // Main program main() { string fname; // Input file name // Test if layout loaded if (bae_planddbclass()!=100) errormsg("Command not allowed for this element!",""); // Get and test the placement file name if ((fname=askstr("Placement File : ",40))=="") errormsg("Operation aborted.",""); // Parse the placement file perror("Reading placement data..."); parseerr(synparsefile(fname),fname); // Perform the placement placement(); // Done perror("Operation completed without errors."); } //______________________________________________________________ // Part list management and placement void gcpart() // Get or create some part list entry { index L_CPART cpart; // Part index index L_NREF nref; // Named reference index int slb=0; // Search lower boundary int sub=pn-1; // Search upper boundary int idx; // Search index int compres; // Compare result // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=strcmp(curpn,pl[idx].pn))==0) errormsg("Multiple defined part '%s'!",curpn); // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Check if part is placed already forall (nref where curpn==nref.NAME) // Part already placed; abort return; // Check net list consistence forall (cpart where curpn==cpart.NAME) { // Check the plname if (curpln!=cpart.PLNAME) // Netlist definition mismatch errormsg("Wrong part macro name '%s'!",curpln); // Done break; } // Insert the new entry to the part list pn++; for (idx=pn-2;idx>=slb;idx--) pl[idx+1]=pl[idx]; pl[slb].pn=curpn; pl[slb].pln=curpln; pl[slb].x=curx; pl[slb].y=cury; pl[slb].a=cura; pl[slb].m=curm; } void placement() // Perform the placement { int i; // Loop control variable // Iterate part list for (i=0;i<pn;i++) { // Place the part if (ged_storepart(pl[i].pn,pl[i].pln, pl[i].x,pl[i].y,pl[i].a,pl[i].m)) errormsg("Error placing part '%s'!",pl[i].pn); } } //______________________________________________________________ // Error handling void parseerr(status,fn) // Handle a syntax/parser error int status; // Scan status string fn; // File name { string msg; // Error message // Evaluate the scan status switch (status) { case 0 : // No error return; case 1 : msg="No BNF definition available!"; break; case 2 : msg="Parser already active!"; break; case 3 : sprintf(msg," Error opening file '%s'!",fn); break; case 4 : msg="Too many open files!"; break; case 5 : sprintf(msg,"[%s/%d] Fatal read/write error!", fn,synscanline()); break; case 6 : sprintf(msg,"[%s/%d] Scan item '%s' too long!", fn,synscanline(),synscanstring()); break; case 7 : sprintf(msg,"[%s/%d] Syntax error at '%s'!", fn,synscanline(),synscanstring()); break; case 8 : sprintf(msg,"[%s/%d] Unexpected end of file!", fn,synscanline()); break; case 9 : sprintf(msg,"[%s/%d] Stack overflow (BNF too complex)!", fn,synscanline()); break; case 10 : sprintf(msg,"[%s/%d] Stack underflow (BNF erroneous)!", fn,synscanline()); break; case 11 : sprintf(msg,"[%s/%d] Error from parse action function!", fn,synscanline()); break; default : sprintf(msg,"Unknown parser error code %d!",status); break; } // Print the error message errormsg(msg,""); } void errormsg(string errfmt,string erritem) // Print an error message with error item and exit from program { string errmsg; // Error message string // Build and print the error message string sprintf(errmsg,errfmt,erritem); perror(errmsg); // Exit from program exit(-1); } //______________________________________________________________ // Parser action routines int p_unitl(code) // Handle the length units definition request // Returns : zero if done or (-1) on error { // Set the length conversion factor switch (code) { case 1 : lenconv=cvtlength(curflt,1,0); break; // Inch case 2 : lenconv=cvtlength(curflt,2,0); break; // mm case 3 : lenconv=cvtlength(curflt,3,0); break; // mil default : return(-1); // Error } // Return without errors return(0); } int p_unita(code) // Handle the angle units definition request // Returns : zero if done or (-1) on error { // Set the angle conversion factor switch (code) { case 1 : angconv=cvtangle(curflt,1,0); break; // Deg case 2 : angconv=cvtangle(curflt,2,0); break; // Rad default : return(-1); // Error } // Return without errors return(0); } int p_storepart() // Handle the store part request // Returns : zero if done or (-1) on error { // Get or create the part list entry gcpart(); // Re-init the current angle and mirror mode cura=0.0; curm=0; // Return without errors return(0); } int p_pname() // Receive a part name // Returns : zero if done or (-1) on error { // Store the current part name strlower(curpn=curid); // Return without errors return(0); } int p_plname() // Receive a physical library name // Returns : zero if done or (-1) on error { // Store the current physical library name strlower(curpln=curid); // Return without errors return(0); } int p_px() // Receive a part X coordinate // Returns : zero if done or (-1) on error { // Store the current part X coordinate curx=curflt*lenconv+plannx; // Return without errors return(0); } int p_py() // Receive a part Y coordinate // Returns : zero if done or (-1) on error { // Store the current part Y coordinate cury=curflt*lenconv+planny; // Return without errors return(0); } int p_pa() // Receive a part angle // Returns : zero if done or (-1) on error { // Store the current part angle cura=curflt*angconv; // Return without errors return(0); } int p_pm() // Receive a part mirror flag // Returns : zero if done or (-1) on error { // Get and store the current part mirror flag curm=atoi(synscanstring())==0?0:1; // Return without errors return(0); } int p_ident() // Receive an identifier // Returns : zero if done or (-1) on error { // Store the current string curid=synscanstring(); // Return without errors return(0); } int p_fltnum(negflag) // Receive a float value // Returns : zero if done or (-1) on error int negflag; // Negative number flag { // Get the current float value curflt=atof(synscanstring()); // Set negative on request if (negflag) curflt*=(-1); // Return without errors return(0); } //______________________________________________________________ // User Language program end
Über die Preprozessoranweisung
#pragma
kann der Aufruftyp des generierten
User Language-Programms explizit gesetzt werden. Damit kann bei der Kompilierung ungeachtet der Verwendung modulspezifischer Systemfunktionen oder Indexvariablen die Kompatibilität des
User Language-Programms erweitert oder eingeschränkt werden. Es können die in der nachfolgenden Tabelle angegebenen Aufruftypen spezifiziert werden (siehe hierzu auch
Anhang A.1.2).
Aufruftyp | Gültige Interpreterumgebung(en) |
---|---|
ULCALLERSTD | alle BAE Programm-Module |
ULCALLERCAP | alle Schematic Capture Programm-Module |
ULCALLERSCM | Schaltplaneditor |
ULCALLERLAY | alle Layout Programm-Module |
ULCALLERGED | Layouteditor |
ULCALLERAR | Autorouter |
ULCALLERCAM | CAM-Prozessor |
ULCALLERCV | CAM-View |
ULCALLERICD | alle IC Design Programm-Module |
ULCALLERCED | Chipeditor |
Mit der Preprozessoranweisung
#pragma ULCALLERSTD
kann der Aufruftyp des generierten
User Language-Programms explizit auf Standard (STD) gesetzt werden. Ohne obige Preprozessoranweisung quittiert der
User Language Compiler die Verwendung von Funktionen und Indexvariablen zueinander inkompatibler Aufruftypen mit der Fehlermeldung
. Bei Verwendung obiger
#pragma
-Anweisung ist das generierte Programm in allen Interpreterumgebungen aufrufbar, auch wenn im Programm zur aktuellen Interpreterumgebung inkompatible Indexvariablen oder Funktionen verwendet werden. Es liegt dann in der Verantwortung des Programmierers, den Programmfluss so zu steuern, dass nur solche Indexvariablen bzw. Funktionen tatsächlich referenziert bzw. aufgerufen werden, die zur aktuellen Interpreterumgebung kompatibel sind. Damit lassen sich Programme mit ähnlicher Funktionalität für unterschiedliche Interpreterumgebungen implementieren. Sollte es zur Programmlaufzeit dennoch zu Zugriffen auf inkompatible Indexvariablen oder Funktionen kommen, dann bricht der
User Language Interpreter das Programm mit einer entsprechenden Fehlermeldung
( ) ab.
Die Ausführung eines User Language-Programms generiert per Standard einen Undoschritt im BAE-System. Die Präprozessoranweisung
#pragma ULCALLERNOUNDO
deaktiviert den Undo-Mechanismus für das kompilierte Programm. Damit können redundante Undoschritte für Programme, die keine für das Undo relevanten Operationen ausführen, vermieden werden.
Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Preprozessor-Anweisungen |
Preprozessor-Anweisungen
© 1985-2024 Oliver Bartels F+E