Willkommen bei Bartels
Preprozessor-Anweisungen - Deutsche Version Preprocessor Statements - English Version
Bartels

Bartels System GmbH
Bartels
Bartels AutoEngineer
BAE Produktinfo
BAE Preisliste
BAE Downloads
BAE Dokumentation
BAE Installationsanleitung
BAE Benutzerhandbuch
BAE Bibliotheken
User Language Programmierhandbuch
Vorwort
1 Einleitung
2 Sprachbeschreibung
2.1 Einführung in die User Language Programmierung
2.2 Konventionen
2.3 Datentypen und Definitionen
2.4 Ausdrücke
2.5 Kontrollstrukturen
2.6 Preprozessor-Anweisungen
2.6.1 Dateieinbindung
2.6.2 Konstantendefinition
2.6.3 Bedingte Übersetzung
2.6.4 BNF-Precompiler
2.6.5 Programmaufruftyp und Undo-Mechanismus
2.7 Syntaxdefinition
3 Programmiersystem
4 BAE User Language-Programme
A Konventionen und Definitionen
B Index-Variablen-Typen
C Systemfunktionen
BAE Update-Historie
BAE Nächste Version Freigabemitteilungen Vorabinfo
BAE V8.0 Freigabemitteilungen
BAE V7.8 Freigabemitteilungen
BAE V7.6 Freigabemitteilungen
BAE V7.4 Freigabemitteilungen
BAE V7.2 Freigabemitteilungen
BAE V7.0 Freigabemitteilungen
BAE V6.8 Freigabemitteilungen
BAE V6.6 Freigabemitteilungen
BAE V6.4 Freigabemitteilungen
BAE V6.2 Freigabemitteilungen
BAE V6.0 Freigabemitteilungen
BAE V5.4 Freigabemitteilungen
BAE V5.0 Freigabemitteilungen
BAE V4.6 Freigabemitteilungen
BAE V4.4 Freigabemitteilungen
BAE V4.2 Freigabemitteilungen
BAE V4.0 Freigabemitteilungen
BAE V3.4 Freigabemitteilungen
BAE Support
BAE Contrib
BAE Entwickler und Dienstleister
Elektronikentwicklung
Sport
Firmenprofil
Impressum
Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Preprozessor-Anweisungen
Bartels User Language - Programmierhandbuch

2.6 Preprozessor-Anweisungen

Bartels AutoEngineer® Dokumentation

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 Zoom All-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)
ULCALLERSTDalle BAE Programm-Module
ULCALLERCAPalle Schematic Capture Programm-Module
ULCALLERSCMSchaltplaneditor
ULCALLERLAYalle Layout Programm-Module
ULCALLERGEDLayouteditor
ULCALLERAR Autorouter
ULCALLERCAMCAM-Prozessor
ULCALLERCV CAM-View
ULCALLERICDalle IC Design Programm-Module
ULCALLERCEDChipeditor

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.

Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Preprozessor-Anweisungen

Preprozessor-Anweisungen
© 1985-2024 Oliver Bartels F+E • Aktualisiert: 11. November 2009, 11:49 [UTC]

© 1985-2024 Oliver Bartels F+E Bartels Startseite Kontakt und Impressum

Webentwicklung Baumeister Mediasoft Engineering

Preprozessor-Anweisungen - Deutsche Version Preprocessor Statements - English Version