|
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.
2.1.1 Ein erstes User Language Programm
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
User Language Program angezeigt. Anschließend wird im Eingabefenster der Prompt
Press ENTER to continue 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.
2.1.2 Variablen, Arithmetik und Funktionen
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.
2.1.3 Vektoren und Kontrollstrukturen
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.
Einführung in die User Language Programmierung © 1985-2024 Oliver Bartels F+E • Aktualisiert: 26. January 2007, 17:23 [UTC]
|