Aufgabe 1: Kommandozeilenparser
Ziel
- Kennenlernen der Entwicklungsumgebung
- Auffrischen der Programmiersprache C++
- Erzeugung eines minimalen Kommandointerpreter
Aufgabe
In dieser Aufgabe soll anhand der Vorgaben ein minimaler Kommandointerpreter erzeugt werden. Zu diesem Zweck soll die Vorgabe so erweitert werden, dass eine Benutzereingabe in einen bereitgestellten Puffer eingelesen und anschließend ausgewerte wird. Ist die Eingabe länger als der übergebene Puffer soll sie verworfen und ein Fehler gemeldet werden.
Nachdem der Puffer mit einer Eingabe gefüllt wurde, muss diese Eingabe in ihre Bestandteile zerlegt und die gefundenen Komponenten bzw. Worte in einer geeigneten Struktur abgelegt werden. Syntaktische Fehler sind dabei durch entsprechende Meldungen anzuzeigen. Es werden folgende Annahmen zur Struktur einer Eingabezeile gemacht:
- eine Zeile kann mehrere Komponenten umfassen, die mit '
;
' oder '&
' voneinander getrennt sind - innerhalb einer Komponente können beliebig viele Worte vorkommen, die durch beliebig viele Leerzeichen und Tabulatoren voneinander getrennt werden
- einem Wort können die Zeichen '
>
' oder '<
' vorangestellt sein (mit oder ohne Zwischenraum aus Leerzeichen oder Tabulator) - innerhalb einer Komponente kann maximal eine Pipe ('
|
') vorkommen
Die Funktionsfähigkeit der Erweiterung soll anhand des internen
Kommandos 'help
' gezeigt werden. Dieses Kommando ist im Rahmen
der Aufgabe zu implementieren.
Implementierungshinweise
Die Aufgabe besteht im Wesentlichen aus drei Teilen: der Eingabe, der Auswertung der Eingabe und der Umsetzung eines Kommandos. Da die einzelnen Elemente der Aufgabe voneinander abhängen empfehlen wir folgende Bearbeitungsreihenfolge:
- Umsetzung der Eingabe in der Methode
int readline(char* s, int c);
Hinweise: Eine Zeile wird begrenzt durch '\n
' oder EOF, weitere Infos:getchar(3)
- Implementierung der Klasse
Parser
als Superklasse vonBSShell
. Dafür muss eine Struktur definiert werden, in der die gefundenen Komponenten bzw. Worte abgelegt werden und auf die die KlasseBSShell
zugreifen kann. Diese Struktur kann beispielsweise so aussehen:struct command { struct command *next; /* Zeiger auf naechste Kommando */ char **token1; /* Woerter vor "|" */ int numtok1; /* Anzahl der Woerter vor "|" */ char **token2; /* Woerter hinter "|" */ int numtok2; /* Anzahl der Woerter hinter "|" */ char *input; /* Wort hinter "<" */ char *output; /* Wort hinter ">" */ short backgr; /* "&" im Kommando */ short ispipe; /* "|" im Kommando */ };
Die Funktionalität eures Kommandozeilenparsers könnt Ihr dann mit der Methodevoid output();
testen. Beispiel:prompt> ls -l file| wc &wc -l > x file token1 = "ls", "-l", "file" numtok1 = 3 token2 = "wc" numtok2 = 1 backgr = true ispipe = true token1 = "wc", "-l", "file" numtok1 = 3 output = "x" prompt> ls -l | parse: Invalid null command.
Weitere Infos:bash
,sh
,tcsh
,strtok(3)
,strcmp(3)
- Umsetzung der Ausführung der erkannten Kommandosequenzen. Zu
diesem Zweck wird die Methode
bool execute();
verwendet. - Umsetzung des Kommandos '
help
' entsprechend der Beispielvorgaben in der KlasseBuiltin
. Später kommen noch andere Kommandos hinzu die dazu verwendet werden auf den Speicher und das Dateisystem zuzugreifen (memtest, dir, ls, cd, mkdir, rmdir, echo,
usw.)
Hinweis: Achtet auf eine saubere Verwaltung aller von Euch
allozierten Puffer. Achtet außerdem darauf, daß Funktionen und Variablen,
die modullokal gültig sind, als static
gekennzeichnet werden.
Vorgabe
Zur Lösung der Aufgabe benötigt ihr die erste Vorgabe. Sie enthält neben dem bereit vollständigem Quellcode auch das Makefile und einige Tools, die es euch ermöglichen eueren Kommandointerpreter zu übersetzen und zu testen.