Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Einführung in die User Language Programmierung |
Bartels User Language - Programmierhandbuch2.1 Einführung in die User Language Programmierung |
An dieser Stelle sollen anhand kleiner Programmbeispiele die wichtigsten Sprachelemente der User Language kurz vorgestellt werden, ohne zunächst Wert auf Vollständigkeit zu legen bzw. auf Details oder gar Ausnahmeregelungen einzugehen. Ziel dabei ist, möglichst schnell die Vorgehensweise bei der User Language Programmierung aufzuzeigen.
Als erstes soll ein Programm erstellt werden, welches lediglich eine Meldung ausgibt und dann auf eine Eingabe wartet, um den Programmlauf abzubrechen. Dies ist im Übrigen bereits ein Programmkonstrukt, das innerhalb des
Bartels AutoEngineer relativ häufig benötigt wird. Wie Sie bereits aus der Einleitung wissen, muss ein
User Language-Programm mindestens aus der
main
-Funktion bestehen. Was innerhalb der
main
-Funktion benötigt wird, ist eine Anweisung, die die gewünschte Meldung ausgibt, sowie eine Anweisung, die eine Benutzerabfrage aktiviert. Beide Anweisungen werden durch den Aufruf entsprechender
User Language Systemfunktionen
(printf und
askstr) realisiert. Diese Systemfunktionen sind dem Compiler bekannt, und in den Interpreter eingebunden, d.h. der Programmierer muss lediglich wissen, wie diese Funktionen aufzurufen sind, und was sie tun (diese Information kann dem
Anhang C dieses Handbuchs entnommen werden). Erstellen Sie nun mit Ihrem Texteditor folgendes
User Language-Programm und speichern Sie dieses unter dem Dateinamen
ulprog.ulc
ab (an der File-Extension
.ulc
erkennt der Compiler, dass es sich um ein User Language Programm handelt):
main() { printf("User Language Program"); askstr("Press ENTER to continue ",1); }
Wie Sie sehen, besteht das Programm lediglich aus der Definition der Funktion
main
. Innerhalb der runden Klammern nach dem Funktionsnamen stehen normalerweise die formalen Parameter der Funktion. Um den Funktionsnamen von anderen Variablennamen zu unterscheiden, sind diese Klammern auch anzugeben, wenn, wie in obigem Beispiel, keine Parameter existieren. Innerhalb der geschweiften Klammern befindet sich der Rumpf der Funktion, d.h. die Anweisungen, die die Funktion ausführen soll. Jede Anweisung wird durch ein Semikolon
(;
) abgeschlossen. Die erste Anweisung innerhalb der Funktion
main
ist der Aufruf der Funktion
printf, was an der nachfolgenden runden Klammer zu erkennen ist. Als Argument bzw. Parameter wird an
printf (in doppelten Anführungszeichen) eine konstante Zeichenkette übergeben, die das Programm bei fehlerfreier Übersetzung und Ausführung am Bildschirm ausgibt. Die zweite Anweisung ist ein Aufruf der Funktion
askstr. Diese Funktion gibt in der Eingabe- bzw. Mitteilungszeile des
Bartels AutoEngineer ihr erstes Argument in Form eines Prompts aus und wartet auf die Eingabe einer Zeichenkette durch den Anwender. Der zweite Parameter zu
askstr gibt dabei die maximal zulässige Länge der einzugebenden Zeichenkette an. Der Aufruf von
askstr ist zugleich die letzte Anweisung des Programms, d.h. nach der Bearbeitung des
askstr-Aufrufs wird das Programm beendet. Wenn das Programm fertig codiert und unter
ulprog.ulc
abgespeichert ist, kann es mit folgendem Aufruf des
User Language Compilers übersetzt werden:
ulc ulprog
Falls keine Fehler auftreten, gibt der Compiler die folgende Meldung auf dem Bildschirm aus:
============================== BARTELS USER LANGUAGE COMPILER ============================== Quellcodedatei "ulprog.ulc" wird kompiliert... Programm 'ulprog' erfolgreich generiert. Quellcodedatei "ulprog.ulc" erfolgreich kompiliert. Keine Fehler, keine Warnungen. User Language Compiler-Lauf erfolgreich beendet.
Der Compiler hat das Programm übersetzt und unter dem Namen
ulprog
in der Datei
ulcprog.vdb
im
Bartels AutoEngineer Programmverzeichnis abgespeichert. Jetzt kann das Programm durch den
User Language Interpreter ausgeführt werden. Hierzu ist z.B. der
Schaltplaneditor des
Bartels AutoEngineer aufzurufen und die Funktion
im Menü
zu aktivieren. Auf die Abfrage nach dem Namen des auszuführenden Programms ist anschließend
ulprog
einzugeben:
Datei |
Anwenderfunktion |
Programmname ? | ulprog |
Der Grafikarbeitsbereich des AutoEngineer wird in den Textmodus geschaltet und es wird die Meldung angezeigt. Anschließend wird im Eingabefenster der Prompt angezeigt. Betätigt der Anwender daraufhin die Return-Taste, dann wird das User Language-Programm beendet und der Grafikarbeitsbereich wieder in den Grafikmodus zurückgeschaltet.
Anhand des nächsten Beispiels sollen eine ganze Reihe weiterer spezifischer Eigenschaften der User Language veranschaulicht werden. Das folgende Programm überprüft einige durch ihren Mittelpunkt und ihren Radius definierte Kreise daraufhin, ob sie sich überlappen (Bohrdatentest?!), und gibt entsprechende Meldungen aus:
// Circle Test Program double tol=0.254*5; // Tolerance struct pos { // Position descriptor double x; // X coordinate double y; // Y coordinate }; struct circle { // Circle descriptor double rad; // Circle radius struct pos c; // Circle position }; // Main program main() { // Define three circles struct circle c1 = { 4.5, { 19.4, 28.3} }; struct circle c2 = { 17.0, { 37.6, 9.71} }; struct circle c3 = { 1.5E01, { 25, 0.2e2} }; // Perform circle test printf("Circle 1 - 2 overlap : %d\n",circletest(c1,c2)); printf("Circle 1 - 3 overlap : %d\n",circletest(c1,c3)); printf("Circle 2 - 3 overlap : %d\n",circletest(c2,c3)); // Prompt for continue askstr("Press ENTER to continue ",1); } int circletest(c1,c2) // Circle test function // Returns: nonzero if overlapping or zero else struct circle c1,c2 /* Test circles 1 and 2 */; { double d /* Distance value */; // Get circle center point distances d=distance(c1.c,c2.c); // Error tolerant check distance against radius sum return(d<=(c1.rad+c2.rad+tol)); } double distance(p1,p2) // Get distance between two points // Returns: distance length value struct pos p1 /* Point 1 */; struct pos p2 /* Point 2 */; { double xd=p2.x-p1.x /* X distance */; double yd=p2.y-p1.y /* Y distance */; // Calculate and return distance return(sqrt(xd*xd+yd*yd)); }
Obiger Quelltext enthält eine Reihe von Kommentaren, die durch
/*
und
*/
eingeklammert sind; diese Kommentare dürfen sich über mehrere Zeilen erstrecken, aber sie dürfen nicht verschachtelt werden. Ein anderer Typ von Kommentar beginnt mit
//
und erstreckt sich jeweils bis zum Zeilenende. Sie sollten sich angewöhnen, Ihre Programme mit derartiger Inline-Dokumentation zu versehen, damit der Programmcode gut verständlich bleibt und somit - auch durch dritte - leichter gepflegt bzw. weiterentwickelt werden kann.
Das Programm enthält weiterhin eine Reihe von Variablendefinitionen. Variablen müssen grundsätzlich vor ihrer Verwendung definiert werden. Dabei wird sowohl der Datentyp als auch der Variablenname festgelegt. Unterschieden wird zwischen globalen Variablen, lokalen Variablen und Funktionsparametern. Der Geltungsbereich globaler Variablen erstreckt sich über das gesamte Programm. Lokale Variablen sind nur innerhalb der Funktion, in der sie definiert wurden, gültig. Funktionsparameter dienen dazu, Werte an Funktionen zu übergeben. In obigem Beispiel wird als einzige globale Variable
tol
mit dem Datentyp
double
definiert. Beispiele für lokale Variablen sind die
double
-Variablen
xd
und
yd
in der Funktion
distance
. Funktionsparameter sind z.B.
c1
und
c2
in der Funktion
circletest
. Diese sind von dem speziell definierten zusammengesetzten
struct
-Datentyp
circle
. Initialisierungen globaler und lokaler Variablen lassen sich bereits bei deren Deklaration durchführen. Beispiele hierfür sind die globale Variable
tol
sowie die lokalen Variablen
xd
und
yd
der Funktion
distance
. Auch zusammengesetzte Datentypen lassen sich initialisieren, wie die Beispiele für die lokalen
struct
-Variablen
c1
,
c2
und
c3
der Funktion
main
zeigen. Bei der Variablendeklaration besteht darüber hinaus die Möglichkeit, gleich eine ganze Liste von Variablennamen anzugeben (siehe Parameterdeklaration für
c1
und
c2
in der Funktion
circletest
).
Die Berechnung von Werten erfolgt über Ausdrücke, wobei das Gleichheitszeichen
(=
) als Zuweisungsoperator fungiert.
Bei der Definition von Funktionen ist ebenfalls ein Datentyp zu spezifizieren. In obigem Beispiel ist die Funktion
distance
vom Typ
double
, die Funktion
circletest
vom Typ
int
. Wird die Datentypspezifikation - wie bei der Funktion
main
- weggelassen, dann wird deren Typ automatisch auf
int
gesetzt. Ein spezieller Datentyp für Funktionen ist
void
. Jede Funktion außer den
void
-Funktionen liefert einen zum Funktionsdatentyp kompatiblen Rückgabewert. Die Übergabe des Rückgabewerts geschieht mit der
return
-Funktion, welche gleichzeitig die Funktionsausführung beendet.
An dieser Stelle sei abschließend ein Beispiel für die Verwendung von Vektoren und Kontrollstrukturen aufgeführt. Das nachfolgende Programm wandelt eine ganze Liste von Integerwerten in Strings um und gibt diese aus:
// Integer list int intary[]={ 0,17,-12013,629,0770,0xFF,-16*4+12 }; // Main program main() { int i /* Loop control variable */; // Set last integer value intary[10]=(-1); // Loop through integer list for (i=0;i<=10;i++) // Print integer and integer string printf("%8d : \"%s\"\n",intary[i],inttostr(intary[i])); // Prompt for continue askstr("Press ENTER to continue ",1); } string inttostr(int intval) // Convert integer value to a string // Returns: resulting string { string resstr="" /* Result string */; int n=intval,i=0 /* Integer value, loop counter */; char sign /* Sign character */; // Test for negative integer value if (n==0) // Return zero integer string return("0"); else if (n>0) // Set sign to plus character sign='+'; else { // Make integer value positive n=-n; // Set sign to minus character sign='-'; } // Build result string do { // Get and append next character resstr[i++]=n%10+'0'; } while ((n/=10)!=0); // Append zeros while (i++<15) resstr+='0'; // Append sign character resstr+=sign; // Reverse string strreverse(resstr); // Return string result return(resstr); }
In obigem Programm wird ein Vektor aus Integerwerten (globale
int
-Variable
intary
) deklariert und dabei auch bereits (teilweise) initialisiert. Wie leicht zu erkennen ist, definiert das eckige Klammernpaar nach dem Variablennamen
intary
einen eindimensionalen
int
-Vektor. Mehrdimensionale Vektoren sind durch entsprechendes Anfügen weiterer eckiger Klammernpaare
(intary[][]...[]
) zu deklarieren. Zu beachten ist dabei, dass die Angabe einer Feldlänge entfällt. Dies resultiert aus der Fähigkeit der
User Language, Vektoren dynamisch zu verwalten, d.h. sowohl dem Compiler als auch dem Interpreter genügt die Information über die Dimension des Vektors. Allerdings erfolgen doch einige Prüfungen, die den Zugriff auf nicht existente Vektorelemente (und damit eine Speicherzugriffsverletzung) unterbinden. So erkennt der Compiler z.B., wenn versucht wird, über einen konstanten, negativen (also ungültigen) Index auf ein Vektorelement zuzugreifen. Ebenso prüft der Interpreter Vektorindizes, die außerhalb des aktuell belegten Vektorfeldbereiches liegen. Beachten Sie hierbei, dass der Index mit dem Wert 0 auf das erste Element eines Vektors verweist.
Eine spezielle Form eines Vektors stellt der Datentyp
string
dar.
User Language erlaubt die direkte Zuweisung von Vektoren kompatiblen Datentyps und gleicher Dimension. Dies wurde bei der Initialisierung der lokalen Variable
resstr
in der Funktion
inttostr
ebenso wie bei der Definition dieser Funktion als
string
und beim Setzen entsprechender Rückgabewerte in den
return
-Aufrufen ausgenutzt. Zudem lässt sich der Additionsoperator direkt auf
string
-Datentypen anwenden; das Resultat entspricht dabei einem durch Aneinanderfügen der beiden Additionsoperatoren erzeugten
string
.
Obiges Programmbeispiel enthält einige Kontrollstrukturen. So wird in der Funktion
main
über eine
for
-Schleife die Vektorvariable
intary
abgearbeitet. In der Funktion
inttostr
werden eine
while
- und eine
do-while
-Schleife verwendet, um die
string
-Variable
resstr
zu manipulieren. Des Weiteren enthält die Funktion
inttostr
eine
if
-Kontrollstruktur, die in Abhängigkeit vom Wert der lokalen Variablen
n
jeweils in einen entsprechenden Programmblock verzweigt.
Bartels :: Bartels AutoEngineer :: BAE Dokumentation :: User Language Programmierhandbuch :: Sprachbeschreibung :: Einführung in die User Language Programmierung |
Einführung in die User Language Programmierung
© 1985-2024 Oliver Bartels F+E