|
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.
2.6.1 Dateieinbindung
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);
}
2.6.2 Konstantendefinition
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
2.6.3 Bedingte Übersetzung
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
:
}
2.6.4 BNF-Precompiler
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
2.6.5 Programmaufruftyp und Undo-Mechanismus
Setzen des Programmaufruftyps
Ü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
Inkompatible Index-/Funktions-Referenz(en)!. 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
(UL(Zeile): System-Funktion in dieser Umgebung nicht verfuegbar!) ab.
Undo-Mechanismus konfigurieren
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.
Preprozessor-Anweisungen © 1985-2025 Oliver Bartels F+E • Aktualisiert: 11. November 2009, 11:49 [UTC]
|